diff --git a/.bzrignore b/.bzrignore index 7c5597bce..9135d7f4a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -26,12 +26,16 @@ docs/*.info docs/stamp-vti docs/version.texi *.elf +example_grub_script_test +example_scripted_test +example_unit_test *.exec genkernsyms.sh gensymlist.sh gentrigtables grub-bin2h -grub-dumpbios +grub_cmd_echo +grub_cmd_regexp grub-editenv grub-emu grub_emu_init.c @@ -44,15 +48,34 @@ grub-kbdcomp grub-macho2img grub-menulst2cfg grub-mk* -grub-pbkdf2 +grub-mount grub-pe2elf grub-probe grub_probe_init.c grub_probe_init.h grub-reboot +grub_script_blanklines +grub_script_blockarg +grub_script_break grub-script-check grub_script_check_init.c grub_script_check_init.h +grub_script_comments +grub_script_continue +grub_script_dollar +grub_script_echo1 +grub_script_echo_keywords +grub_script_expansion +grub_script_final_semicolon +grub_script_for1 +grub_script_functions +grub_script_if +grub_script_not +grub_script_return +grub_script_setparams +grub_script_shift +grub_script_vars1 +grub_script_while1 grub_script.tab.c grub_script.tab.h grub_script.yy.c @@ -76,6 +99,7 @@ Makefile *.mod mod-*.c missing +partmap_test *.pf2 *.pp po/*.mo @@ -110,6 +134,7 @@ grub-core/Makefile.gcry.def grub-core/contrib grub-core/genmod.sh grub-core/gensyminfo.sh +grub-core/modinfo.sh grub-core/*.module grub-core/*.pp util/bash-completion.d/grub @@ -131,5 +156,9 @@ grub-core/gnulib/unistd.h grub-core/gnulib/warn-on-use.h grub-core/gnulib/wchar.h grub-core/gnulib/wctype.h +grub-core/rs_decoder.S widthspec.bin widthspec.h +docs/stamp-1 +docs/version-dev.texi +Makefile.utilgcry.def diff --git a/BUGS b/BUGS new file mode 100644 index 000000000..46faa6452 --- /dev/null +++ b/BUGS @@ -0,0 +1,7 @@ +GRUB team is aware of following problems: + - Currently search and assembling multidevice abstractions scans + all the devices which can be slow. + - Cache isn't used correctly for video which results in slowness. + +While these are bugs their solution has a potential of breaking more and more +seriously. So it was decided for 1.99 that they aren't fixed. diff --git a/ChangeLog b/ChangeLog index cc3c87445..0f52d3fbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,8514 @@ -2010-10-02 Aleš Nesrsta +2012-02-01 Aleš Nesrsta +2012-02-01 Vladimir Serbinenko - * include/grub/scsi.h: - SCSI - cache ID bug + EHCI support. All of the credit goes to Aleš Nesrsta. I've just added + the support for the CS5536 modification thereos and few bugfixes. + + * grub-core/Makefile.core.def (ehci): New module. + * grub-core/bus/usb/ehci.c: New file. + * grub-core/bus/usb/usbhub.c (grub_usb_hub_add_dev): New arguments + port and hubaddr. All users updated. + Save port and hubaddr into dev structure. + * include/grub/cs5536.h (GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE): New + define. + * include/grub/pci.h (grub_dma_phys2virt): New function. + (grub_dma_virt2phys): Likewise. + * include/grub/usb.h (grub_usb_device): New members port and hubaddr. + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/fat.c (grub_fat_mount) [!MODE_EXFAT]: Remove fstype + check as some mkfs implementations omit it. + +2012-01-31 Vladimir Serbinenko + + * docs/grub.texi (Unicode): Mention identifier and space limitations. + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/jfs.c (grub_jfs_sblock): Make volname a char array. + Add new member volname2. + (grub_jfs_label): Use volname2 if available. + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/nilfs2.c (grub_nilfs2_super_block): Expand volume_name + over last_mounted as seen in image generated by mkfs.nilfs2. + (grub_nilfs2_label): Use sizeof for the size of s_volume_name. + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/fat.c (grub_fat_dir_entry) [MODE_EXFAT]: Expand label + to 15 UTF-16 characters as seen in FS generated by mkexfatfs. + (grub_fat_label) [MODE_EXFAT]: Use macros for size. + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/romfs.c (grub_romfs_mount): Fix a bug with labels going + over the sector. + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (get_filesystem_dnode): Support space in + subvolume name (by removing a bogus and useless check). + +2012-01-31 Vladimir Serbinenko + + * grub-core/fs/ext2.c (grub_ext2_label): Fix field size. Change to + sizeof while on it. + +2012-01-30 Vladimir Serbinenko + + * grub-core/disk/scsi.c (grub_scsi_read_capacity): Renamed to ... + (grub_scsi_read_capacity10): ... this. + (grub_scsi_read_capacity16): New function. + (grub_scsi_open): Use read_capacity16 if read_capacity10 returned + 0xffffffff. + Fix off-by-one error. + * include/grub/scsi.h (grub_scsi): Rename size to last_block and make it + 64-bit unsigned. + * include/grub/scsicmd.h (grub_scsi_read_capacity): Rename to ... + (grub_scsi_read_capacity10): ... this. + (grub_scsi_read_capacity_data): Rename to ... + (grub_scsi_read_capacity10_data): ... this. Rename size to last_block. + (grub_scsi_read_capacity16): New struct. + (grub_scsi_read_capacity16_data): Likewise. + (grub_scsi_cmd_t): Rename grub_scsi_cmd_read_capacity to + grub_scsi_cmd_read_capacity10. + New command grub_scsi_cmd_read_capacity16. + +2012-01-30 Vladimir Serbinenko + + SCSI >2TiB support. + + * grub-core/disk/scsi.c (grub_scsi_read16): New function. + (grub_scsi_write16): Likewise. + (grub_scsi_read): Use read16 when necessary. + (grub_scsi_write): Likewise. + * include/grub/scsicmd.h (grub_scsi_read16): New struct. + (grub_scsi_write16): Likewise. + (grub_scsi_cmd_t): Add READ16 and WRITE16. + +2012-01-30 Vladimir Serbinenko + + SCSI write support (for usbms mainly). + + * grub-core/disk/scsi.c (grub_scsi_write10): Uncomment. Make buffer + a const pointer. + (grub_scsi_write): Implement. + * include/grub/scsi.h (grub_scsi_dev): Make write buffer a const pointer + +2012-01-30 Vladimir Serbinenko + + * grub-core/io/lzopio.c (uncompress_block): Fix use of incorrect + variable. + +2012-01-29 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/string.h (memchr): New function. + +2012-01-29 Vladimir Serbinenko + + * po/POTFILES.in: Regenerate. + +2012-01-29 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/assert.h (assert_real): Replace grub_fatal + with grub_printf to avoid unnecessary fatal failure. + +2012-01-29 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/limits.h (SHRT_MAX): New define. + (INT_MAX): Likewise. + * grub-core/lib/posix_wrap/stdio.h (snprintf): New function. + * grub-core/lib/posix_wrap/stdlib.h (abs): Likewise. + * grub-core/lib/posix_wrap/string.h (memcmp): Likewise. + (strcpy): Likewise. + (strstr): Likewise. + (strchr): Likewise. + (strncpy): Likewise. + (strcat): Likewise. + (strncat): Likewise. + (strcoll): Likewise. + * include/grub/types.h (GRUB_SHRT_MAX): New define. + (GRUB_INT_MAX): Likewise. + +2012-01-29 Vladimir Serbinenko + + * grub-core/gnulib/regcomp.c (regerror): Don't use abort on + unexpected error. + (optimize_utf8): Likewise. + * grub-core/lib/posix_wrap/stdlib.h (abort): Removed. + +2012-01-29 Vladimir Serbinenko + + * grub-core/boot/i386/pc/lnxboot.S: Use + GRUB_DECOMPRESSOR_MAX_DECOMPRESSOR_SIZE. + * grub-core/boot/i386/pc/startup_raw.S: Ensure about boot_dev + location. + * include/grub/offsets.h (GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE): New + definition. + (GRUB_DECOMPRESSOR_I386_PC_MAX_DECOMPRESSOR_SIZE): Likewise. + +2012-01-29 Vladimir Serbinenko + + * util/getroot.c (grub_util_get_dm_node_linear_info): Fix memory leak. + * grub-core/disk/cryptodisk.c (cryptodisk_cleanup): Disable for + now to avoid double free. + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_dev): Rename to + hostdisk. + * include/grub/disk.h (grub_disk_dev_id): New id HOSTDISK. + * util/grub-probe.c (escape_of_path): Always return a new copy. + (print_full_name): Escape path. + (probe): Don't call grub_util_devname_to_ofpath on NULL. + Fix hints on abstractions. + +2012-01-29 Vladimir Serbinenko + + * util/grub-mkconfig_lib.in (prepare_grub_to_access_device): + Don't add "root" line if no compatibility hont is available. + Suggested by: Seth Goldberg. + +2012-01-29 Vladimir Serbinenko + + * include/grub/ata.h (grub_ata): Add a new element maxbuffer. + * grub-core/disk/ata.c (grub_ata_readwrite): Limit to ata->maxbuffer. + * grub-core/disk/pata.c (grub_pata_open): Set ata->maxbuffer. + * grub-core/disk/ahci.c (grub_ahci_open): Likewise. + +2012-01-29 Vladimir Serbinenko + + * include/grub/zfs/dnode.h (DN_MIN_INDBLKSHIFT): Removed. + +2012-01-29 Vladimir Serbinenko + + * util/grub-pe2elf.c (ehdr): Make static. + (shdr): Likewise. + (num_sections): Likewise. + (offset): Likewise. + +2012-01-29 Vladimir Serbinenko + + Eliminate ofpath limits and possible overflows. + + * util/ieee1275/ofpath.c (grub_util_info) [STANDALONE]: New function. + (OF_PATH_MAX): Removed. + (MAX_DISK_CAT): New const. + (find_obppath): Use allocated rather than preallocated buffer. + Return result. Argument of_path removed. All users updated. + Add missing fdstat. + (xrealpath): New function. + (block_device_get_sysfs_path_and_link): Remove sysfs argument. + Allocate rather than use preallocated buffer. All users updated. + (__of_path_common): Use allocated rather than preallocatecd buffer. + Return result. Argument of_path removed. All users updated. + (vendor_is_ATA): Read only needed part form the file. + (check_sas): Allocate depending on contents rather than fixed. + (main) [STANDALONE]: Handle NULL result. + +2012-01-29 Vladimir Serbinenko + + * grub-core/normal/completion.c (iterate_dev): Close the disk. + +2012-01-29 Vladimir Serbinenko + + Cryptodisk write support. + + * grub-core/disk/cryptodisk.c (grub_crypto_pcbc_encrypt): New function. + (grub_cryptodisk_decrypt): Moved logic to ... + (grub_cryptodisk_endecrypt): ...this. New argument "encrypt". + (grub_cryptodisk_write): Implement. + * grub-core/kern/emu/hostdisk.c (nwrite): Rename to ... + (grub_util_fd_write): ... this. Make global. + * include/grub/emu/hostdisk.h (grub_util_fd_write): New proto. + +2012-01-29 Vladimir Serbinenko + + * include/grub/list.h (grub_list_remove): Don't crash if element is + removed twice. + +2012-01-29 Vladimir Serbinenko + + Rename ofconsole to console. + + * grub-core/commands/terminal.c (handle_command): Handle ofconsole + as sysnonym to console. + * grub-core/term/ieee1275/ofconsole.c: Renamed to .. + * grub-core/term/ieee1275/console.c: ... this. All users updated. + Rename grub_ofconsole_ to grub_console_. All users updated + (grub_console_term_output): Rename "ofconsole" to "console". + * grub-core/term/terminfo.c (grub_cmd_terminfo): Handle "ofconsole" + as "console". + +2012-01-29 Vladimir Serbinenko + + * grub-core/loader/i386/pc/plan9.c (grub_cmd_plan9): Remove PXE + handling. + * include/grub/disk.h (grub_disk_dev_id): Remove obsolete + GRUB_DISK_DEVICE_UUID_ID, GRUB_DISK_DEVICE_PXE_ID and + GRUB_DISK_DEVICE_FILE_ID. + +2012-01-29 Vladimir Serbinenko + + * grub-core/kern/partition.c (grub_partition_get_name): Simplify logic + and improve performance. + +2012-01-29 Vladimir Serbinenko + + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_encode_devname): Fix + missing ieee1275/ prefix on whole disk. + +2012-01-29 Vladimir Serbinenko + + * include/grub/powerpc/ieee1275/util/biosdisk.h: Remove. + * include/grub/powerpc/ieee1275/biosdisk.h: Likewise. + +2012-01-29 Vladimir Serbinenko + + * grub-core/fs/cpio.c (handle_symlink): Fix a bug. + +2012-01-29 Vladimir Serbinenko + + Merge common RAID and LVM logic to an abstract diskfilter. + Add LDM support using the same framework. + + * Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c, + grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c. + (libgrubmods): Remove grub-core/disk/raid.c and + grub-core/partmap/gpt.c. + * grub-core/Makefile.core.def (ldm): New module. + (raid): Renamed to diskfilter. All users updated. + * grub-core/disk/raid.c: Moved to ... + * grub-core/disk/diskfilter.c: ... here. + * grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_. + (lv_num): New var. + (find_array): Renamed to ... + (find_lv): ... this. Support multi-LV. Skip nameless LVs + (grub_is_array_readable): Renamed to ... + (grub_is_lv_readable): ... this. Support multinode hierarchy. + (insert_array): New argument id. + (is_node_readable): New function. + (scan_device): Rename to ... + (scan_disk): .. this. Restrict to one disk. + (scan_devices): New function. + (grub_diskfilter_iterate): Support multi-LV. + Skip invisible and nameless LVs. + (grub_diskfilter_memberlist): Support multi-LV. + (grub_diskfilter_read_node): New function. + (grub_raid_read): Most of logic moved to ... + (read_segment): ... here + (read_lv): New function. + (grub_diskfilter_get_vg_by_uuid): New function. + (grub_diskfilter_make_raid): Likewise. + * grub-core/disk/ldm.c: New file. + * grub-core/disk/lvm.c (vg_list): Removed. + (lv_count): Likewise. + (scan_depth): Likewise. + (is_lv_readable): Likewise. + (grub_lvm_getvalue): Advance pointer past the number. + (find_lv): Removed. + (do_lvm_scan): Refactored into ... + (grub_lvm_detect): ... this. Support raid. + (grub_lvm_iterate): Removed. + (grub_lvm_memberlist): Likewise. + (grub_lvm_open): Likewise. + (grub_lvm_close): Likewise. + (read_lv): Likewise. + (read_node): Likewise. + (is_node_readable): Likewise. + (is_lv_readable): Likewise. + (grub_lvm_read): Likewise. + (grub_lvm_write): Likewise. + (grub_lvm_dev): Use diskfilter + (GRUB_MOD_INIT): Likewise. + (GRUB_MOD_FINI): Likewise. + * grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use + new interface. + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise. + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise. + * grub-core/disk/raid5_recover.c (grub_raid5_recover): Use + grub_diskfilter_read_node. + Fix a bug with xor. + * grub-core/disk/raid6_recover.c (grub_raid6_recover): Use + grub_diskfilter_read_node. + Support GRUB_RAID_LAYOUT_MUL_FROM_POS. + * grub-core/kern/disk.c (grub_disk_dev_list): Make global. + (grub_disk_dev_iterate): Move from here... + * include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined. + * grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start): + Make global. + (grub_hostdisk_find_partition_start): Likewise. + (grub_hostdisk_os_dev_to_grub_drive): New function. + (grub_util_biosdisk_get_osdev): Check that disk is biosdisk. + * grub-core/kern/emu/hostdisk.c (make_device_name): Move to ... + * util/getroot.c (make_device_name): ... here. + * grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info): + Move to ... + * util/getroot.c (grub_util_get_dm_node_linear_info): ...here. + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Move to ... + * util/getroot.c (convert_system_partition_to_system_disk): ...here. + * grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ... + * util/getroot.c (device_is_wholedisk): ... here. + * grub-core/kern/emu/hostdisk.c (find_system_device): Move to ... + * util/getroot.c (find_system_device): ... here. + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present): + Move to ... + * util/getroot.c (grub_util_biosdisk_is_present): ...here. + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev): + Move to ... + * util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here. + Handle LDM. + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy): + Move to ... + * util/getroot.c (grub_util_biosdisk_is_floppy): ... here. + * grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global. + * include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with + DISKFILTER. + * include/grub/raid.h: Renamed to ... + * include/grub/diskfilter.h: ... this. + * include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_* + (GRUB_RAID_LAYOUT_*): Make into array. + (GRUB_RAID_LAYOUT_MUL_FROM_POS): New value. + (grub_diskfilter_vg): New struct. + (grub_diskfilter_pv_id): Likewise. + (grub_raid_member): Removed. + (grub_raid_array): Likewise. + (grub_diskfilter_pv): New struct. + (grub_diskfilter_lv): Likewise. + (grub_diskfilter_segment): Likewise. + (grub_diskfilter_node): Likewise. + (grub_diskfilter_get_vg_by_uuid): New proto. + (grub_raid_register): Inline. + (grub_diskfilter_unregister): Likewise. + (grub_diskfilter_make_raid): New proto. + (grub_diskfilter_vg_register): Likewise. + (grub_diskfilter_read_node): Likewise. + (grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise. + * include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto. + (grub_util_is_ldm): Likewise. + (grub_util_ldm_embed) [GRUB_UTIL]: Likewise. + (grub_hostdisk_find_partition_start): Likewise. + (grub_hostdisk_os_dev_to_grub_drive): Likewise. + * include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM): + New definition. + (grub_gpt_partition_map_iterate): New proto. + * include/grub/lvm.h (grub_lvm_vg): Removed. + (grub_lvm_pv): Likewise. + (grub_lvm_lv): Likewise. + (grub_lvm_segment): Likewise. + (grub_lvm_node): Likewise. + * util/getroot.c [...] + * util/grub-probe.c (probe_raid_level): Handle diskfilter. + (probe_abstraction): Likewise. + * util/grub-setup.c (setup): Remove must_embed. Support LDM. + (main): Remove dead logic. + +2012-01-28 Vladimir Serbinenko + + Simplify root device discover and don't fail when trying to open + incorrect devices. + + * grub-core/disk/efi/efidisk.c (get_diskname_from_path_real): New + function. + (get_diskname_from_path): Likewise. + (grub_efidisk_get_device_name): Use get_diskname_from_path instead + of iterating. + +2012-01-27 Vladimir Serbinenko + + * grub-core/Makefile.core.def (setpci): Enable on all PCI platforms. + +2012-01-27 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (nvlist_find_value): Check that we don't go + pastthe end. + +2012-01-27 Vladimir Serbinenko + + * util/grub-install.in: Add missing \. + Reported by: gentoofan + +2012-01-26 Vladimir Serbinenko + + * grub-core/fs/squash4.c (xz_decompress): Fix return value. + (direct_read): Use correct compressed size. + (grub_squash_read_data): Likewise. + +2012-01-26 Vladimir Serbinenko + + * docs/grub.texi (Platform limitations): New section. + (Platform-specific operations): Likewise. + * docs/grub-dev.texi (Porting): Likewise. + +2012-01-25 Vladimir Serbinenko + + IEEE1275 disk write support. + + * grub-core/kern/ieee1275/ieee1275.c (grub_ieee1275_write): Make buffer + const void *. + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_write): Likewise. + * grub-core/disk/ieee1275/ofdisk.c (grub_ofdisk_read): Move open + and seek loginc to ... + (grub_ofdisk_prepare): ... here. + (grub_ofdisk_write): Implement. + +2012-01-25 Vladimir Serbinenko + + ARC disk write support. + + * grub-core/disk/arc/arcdisk.c (handle_writable): New var. + (reopen): New argument writable. All users updated. + Handle required access mode. + (grub_arcdisk_write): Implement. + * include/grub/arc/arc.h (grub_arc_file_access): New enum. + (grub_arc_firmware_vector): Make buffer to write a const buffer. + +2012-01-25 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_device): New field size. + (read_sblock): Don't attempt to read superblocks outside the disk size. + +2012-01-25 Vladimir Serbinenko + + * grub-core/fs/nilfs2.c (grub_nilfs2_load_sb): Use device size from + first superblock to find the second one when possible. + +2012-01-25 Vladimir Serbinenko + + * util/grub-install.in: Fix an ARC bug. + Print a warning if no platform-specific setup is available. + +2012-01-24 Vladimir Serbinenko + + Use static allocation rather than scratch pointer in reed_solomon. + It decreases its size significantly and avoids a variable in .text. + + * grub-core/lib/reed_solomon.c (scratch): Removed. + (chosenstat): New const or static array. + (sigma): Likewise. + (errpot): Likewise. + (errpos): Likewise. + (sy): Likewise. + (mstat): Likewise. + (errvals): Likewise. + (eqstat): Likewise. + (pol_evaluate): Replace x with log_x argument. All users updated. + (syndroms): Removed. + (gauss_solve): Use statically allocated arrays. + (rs_recover): Likewise. + Calculate syndroms directly. + (decode_block): Use statically allocated arrays. + (grub_reed_solomon_add_redundancy) [TEST]: Fix -DTEST compilation. + (main) [TEST]: Allow -DTEST -DSTANDALONE. + +2012-01-24 Vladimir Serbinenko + + Eliminate fixed limit on reed solomon decoder length. + + * grub-core/boot/i386/pc/lnxboot.S: Scan for multiboot signature + rather than hardcoding the address. + * grub-core/boot/i386/pc/startup_raw.S: Add new data field + no_reed_solomon_length. + Move gate_a20 to no-reed-solomon part. + Don't force a particular size of no reed-solomon part. + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): + Removed. + (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH): New define. + * util/grub-setup.c (setup): Read no_rs_length from the image itself. + +2012-01-24 Vladimir Serbinenko + + * grub-core/commands/wildcard.c (match_files): Handle filenames + without explicit device. + (wildcard_expand): Don't add explicit device if not already present. + * tests/grub_script_echo1.in: Add a new expansion test. + +2012-01-24 Vladimir Serbinenko + + Replace single-linked with double-linked lists. It results in more + compact and more efficient code. + + * grub-core/kern/list.c (grub_list_push): Moved from here ... + * include/grub/list.h (grub_list_push): ... to here. Set prev. + (grub_list_remove): Moved from here ... + * include/grub/list.h (grub_list_remove): ... here. Use and set prev. + (grub_prio_list_insert): Set prev. + * include/grub/list.h (grub_list): Add prev. All users updated. + +2012-01-24 Vladimir Serbinenko + + Handle newer autotools. Add some missing quotes while on it. + + * Makefile.am (pkglib_DATA): Remove update-grub_lib. + (pkglib_DATA): Move grub-mkconfig_lib from here ... + (pkgdata_DATA): ... here. + * Makefile.util.def (update-grub_lib): Removed. + * conf/Makefile.common (pkglib_DATA): Removed. + (pkglib_SCRIPTS): Likewise. + (pkgdata_DATA): New variable. + * tests/util/grub-shell-tester.in: Replace pkglib with pkgdata where + needed. + Add missing quotes. + Remove unused variable while on it. + * tests/util/grub-shell.in: Likewise. + * util/grub-install.in: Likewise. + * util/grub-mkconfig.in: Likewise. + * util/grub-mknetdir.in: Likewise. + * util/grub-mkrescue.in: Likewise. + * util/grub-mkstandalone.in: Likewise. + * util/grub.d/00_header.in: Likewise. + * util/grub.d/10_hurd.in: Likewise. + * util/grub.d/10_illumos.in: Likewise. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub.d/10_netbsd.in: Likewise. + * util/grub.d/10_windows.in: Likewise. + * util/grub.d/20_linux_xen.in: Likewise. + * util/grub.d/30_os-prober.in: Likewise. + * util/update-grub_lib.in: Removed. + +2012-01-24 Seth Goldberg + + * grub-core/net/drivers/i386/pc/pxe.c (grub_pxe_recv): Relax checks as + a workaround for intel problem. + +2012-01-23 Paulo de Rezende Pinatti +2012-01-23 Vladimir Serbinenko +2012-01-23 pfsmorigo + + * util/grub-install.in: Support dd'in into PreP partition. + * util/grub-probe.c (probe): Support discovering partition type. + (main): Support -t msdos_parttype. + +2012-01-23 Vladimir Serbinenko + + * grub-core/normal/crypto.c (grub_crypto_autoload): Prevent + infinite recursion using counter. + * grub-core/lib/xzembed/xz_dec_stream.c (xz_dec_init): Defer s->crc32 + init to skip it if the magic check fails. + (dec_stream_header): Init s->crc32. + +2012-01-22 Vladimir Serbinenko +2012-01-22 Zachary Bedell +2012-01-22 Richard Laager + + * grub-core/fs/zfs/zfs.c (uberblock_verify): New parameter size. + All users updated. + (find_bestub): Determine correct size. + (fill_vdev_info_real): Fill ashift. New argument. All users updated. + (scan_disk): Align the size down. + Call check pool before find_bestub to have ashift. + +2012-01-22 Vladimir Serbinenko + + * grub-core/lib/relocator.c (malloc_in_range): Remove couple of + dprintf in no-malloc zone. + +2012-01-22 Mario Limonciello + + * configure.ac: Add back in test for limits.h. + +2012-01-20 Vladimir Serbinenko + + Support 4K-sector NTFS. + + * include/grub/ntfs.h (GRUB_NTFS_MAX_MFT): Increase to 8. + (grub_ntfs_data): Remove blocksize. + * grub-core/fs/ntfs.c (fixup): Fix size comparison. + Remove data argument. All users updated. + +2012-01-20 Vladimir Serbinenko + + * grub-core/kern/mips/arc/init.c (grub_total_modules_size): Mark as + being in .text to avoid dprel references. + * include/grub/mips/loongson/kernel.h (grub_arch_machine): Likewise. + * include/grub/mips/loongson/memory.h (grub_arch_memsize): Likewise. + (grub_arch_highmemsize): Likewise. + * include/grub/mips/loongson/time.h (grub_arch_busclock): Likewise. + * include/grub/mips/qemu_mips/memory.h (grub_arch_memsize): Likewise. + * include/grub/mips/time.h (grub_arch_cpuclock): Likewise. + +2012-01-18 Vladimir Serbinenko + + Support powerpc with GCC that defines __PPC__ but not __powerpc__. + + * config.h.in (__powerpc__) [__PPC__ && !__powerpc__]: New definition. + * grub-core/lib/setjmp.S: Treat __PPC__ as equivalent to __powerpc__. + +2012-01-18 Vladimir Serbinenko + + * include/grub/datetime.h (grub_get_datetime_cmos): Don't define in + GRUB_UTIL. + (grub_set_datetime_cmos): Likewise. + +2012-01-18 Vladimir Serbinenko + + Make XZ compression parameters dependent on target and not host CPU. + + * configure.ac: Define GRUB_TARGET_CPU_XYZ series. + * grub-core/lib/xzembed/xz_config.h: Use GRUB_TARGET_CPU_XYZ. + +2012-01-18 Vladimir Serbinenko + + * grub-core/kern/powerpc/dl.c (grub_arch_dl_get_tramp_got_size): Remove + set but not used variable. + +2012-01-14 Vladimir Serbinenko + + * grub-core/fs/reiserfs.c (grub_reiserfs_uuid): Reject 0-uuid as + created when no uuid support is compiled into mkfs.reiser. + +2012-01-14 Vladimir Serbinenko + + * grub-core/fs/hfs.c (macroman_to_utf8): Convert / to :. + (utf8_to_macroman): Do the opposite. + * grub-core/fs/hfsplus.c (grub_hfsplus_iterate_dir): Convert / to :. + +2012-01-14 Vladimir Serbinenko + + * configure.ac: Refise build qemu_mips w/o unifont. + +2012-01-14 Vladimir Serbinenko + + Eliminate grub_min/grub_max prone to overflow usage. + + * grub-core/bus/usb/usbhub.c (grub_usb_add_hub): Eliminate grub_min. + (poll_nonroot_hub): Likewise. + * grub-core/fs/affs.c (grub_affs_iterate_dir): Likewise. + (grub_affs_label): Likewise. + * grub-core/fs/btrfs.c (grub_btrfs_lzo_decompress): Likewise. + * grub-core/fs/hfs.c (grub_hfs_dir): Likewise. + (grub_hfs_label): Likewise. + * grub-core/fs/hfsplus.c (grub_hfsplus_cmp_catkey): Likewise. + * grub-core/fs/zfs/zfs.c (MIN): Remove. + (zap_leaf_array_equal): Use grub_size. Remove MIN. + (zap_leaf_array_get): Likewise. + (dnode_get_path): Likewise. + * grub-core/io/lzopio.c (grub_lzopio_read): Eliminate grub_min. + * grub-core/io/xzio.c (grub_xzio_read): Likewise. + * grub-core/script/execute.c (grub_script_break): Likewise. + * grub-core/script/lexer.c (grub_script_lexer_record): Eliminate + grub_max. + * grub-core/script/yylex.l (grub_lexer_yyrealloc): Likewise. + * include/grub/misc.h (grub_min): Removed. + (grub_max): Likewise. + +2012-01-14 Samuel Thibault + + * grub-core/fs/ext2.c (grub_ext2_iterate_dir): Ignore entries with + direct.inode = 0. + +2012-01-14 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/wctype.h (CHARCLASS_NAME_MAX): New define. + +2012-01-14 Vladimir Serbinenko + + * include/grub/datetime.h (grub_datetime2unixtime): Fix offset. + +2012-01-14 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/stdlib.h (MB_CUR_MAX): Moved from here ... + * grub-core/lib/posix_wrap/wchar.h (MB_CUR_MAX): ... here. Value fixed. + +2012-01-14 Vladimir Serbinenko + + * grub-core/fs/fshelp.c (grub_fshelp_find_file): Use grub_strcasecmp + rather than a hack for grub_strncasemap. + +2012-01-14 Vladimir Serbinenko + + Support multiple initrds + Note: part of this was accidently committed in r3739. + + * grub-core/loader/i386/linux.c (grub_cmd_initrd): Support multiple + initrd. + * grub-core/loader/i386/pc/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/ia64/efi/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/mips/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/powerpc/ieee1275/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/sparc64/ieee1275/linux.c (grub_cmd_initrd): Likewise. + +2012-01-14 Vladimir Serbinenko + + * grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Skip + disks with unknown size. + * grub-core/disk/raid.c (scan_devices): Allow disks with unknown sizes. + +2012-01-14 Vladimir Serbinenko + + Remove defines pertaining to arbitrary limits not affecting GRUB + anymore. + + * grub-core/fs/ext2.c (EXT2_PATH_MAX): Removed. + (EXT2_MAX_SYMLINKCNT): Likewise. + * grub-core/fs/nilfs2.c (NILFS_BTREE_LEVEL_MAX): Likewise. + * grub-core/net/tftp.c (TFTP_MAX_PACKET): Likewise. + * include/grub/i386/pc/pxe.h (GRUB_PXE_MIN_BLKSIZE): Likewise. + (GRUB_PXE_MAX_BLKSIZE): Likewise. + * include/grub/normal.h (GRUB_MAX_CMDLINE): Likewise. + * include/grub/zfs/dnode.h (DN_MAX_INDBLKSHIFT): Likewise. + (DN_MAX_OBJECT_SHIFT): Likewise. + (DN_MAX_OFFSET_SHIFT): Likewise. + (DN_MAX_OBJECT): Likewise. + (DNODES_PER_LEVEL_SHIFT): Likewise. + * include/grub/zfs/spa.h (SPA_MAXBLOCKSHIFT): Likewise. + (SPA_MAXBLOCKSIZE): Likewise. + (SPA_BLOCKSIZES): Likewise. + * include/grub/zfs/zap_impl.h (MZAP_MAX_BLKSHIFT): Likewise. + (MZAP_MAX_BLKSZ): Likewise. + +2012-01-14 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (grub_zfs_read): Remove useless alloc and + handle NULL appropriately. + Remove MIN. + +2012-01-13 Vladimir Serbinenko + + Fix efiemu. + + * grub-core/efiemu/runtime/efiemu.c: explicitly include right + cpu/types.h. + (efiemu_set_virtual_address_map): Remove UINT_TO_PTR. + * configure.ac: Fix efiemu check. + +2012-01-13 Vladimir Serbinenko + + * util/grub.d/30_os-prober.in: Fix occurence of grub-probe instead of + grub_probe. + Reported by: adamwill + +2012-01-12 Seth Goldberg + + * grub-core/lib/arg.c (grub_arg_parse): Fix NULL pointer dereference. + +2012-01-12 Vladimir Serbinenko + + Fix handling of wide characters in gfxterm. + + * grub-core/term/gfxterm.c (grub_colored_char): Remove width and index. + (clear_char): Likewise. + (paint_char): Skip code == NULL chars. + (grub_gfxterm_putchar): Set code = NULL on "shadowed" positions. + +2012-01-12 Vladimir Serbinenko + + * grub-core/normal/charset.c: Move comment to right place. + +2012-01-11 Vladimir Serbinenko + + * grub-core/fs/affs.c (grub_affs_bblock): Revert flags. + (GRUB_AFFS_FLAG_FFS): Put back where it was. + (grub_affs_mount): Revert the correct version checking. + +2012-01-11 Vladimir Serbinenko + + * docs/grub.texi (Unicode): Mention several other unsupported features. + +2011-12-26 Vladimir Serbinenko + + * grub-core/fs/squash4.c (squash_mount): Mark endian conversion in + case statements as compile-time one. + (direct_read): Prevent spurious warnings. + (grub_squash_read_data): Likewise. + +2011-12-26 Vladimir Serbinenko + + Various squash4 fixes and LZO and XZ support. + + * Makefile.util.def (libgrubmods.a): Add xzembed directory to cppflags. + Add xzembed source files. + * grub-core/Makefile.core.def (squash4): Add xzembed and minilzo flags. + * grub-core/fs/squash4.c (grub_squash_super): New field compression. + (grub_squash_inode): New subtype long_dir. + (SQUASH_TYPE_LONG_DIR): New inode type. + (COMPRESSION): New enum. + (XZBUFSIZ): New const. + (grub_squash_data): New fields blksz, decompress, xzdec, xzbuf. + (read_chunk): Use data->decompress. + (zlib_decompress): New function. + (lzo_decompress): Likewise. + (xz_decompress): Likewise. + (squash_mount): Set new data fields. + (grub_squash_iterate_dir): Handle long dir. + (squash_unmount): Free xzdec and xzbuf. + (grub_squash_open): Check ino type. + (direct_read): Stylistic fixes. Use data->decompress. + (grub_squash_read_data): Likewise. + * grub-core/io/gzio.c (grub_gzio): Remove disk_input. + (get_byte): Likewise. + (grub_zlib_disk_read): Removed. + * grub-core/lib/posix_wrap/sys/types.h (ssize_t): New type. + (GRUB_POSIX_BOOL_DEFINED): New define. + * grub-core/lib/posix_wrap/unistd.h: Include sys/types.h. + * grub-core/lib/xzembed/xz.h: Addmissing includes. + [!GRUB_POSIX_BOOL_DEFINED]: Define bool. + * include/grub/deflate.h (grub_zlib_disk_read): Removed. + +2011-12-26 Vladimir Serbinenko + + Don't override more informative errors. + + * grub-core/commands/acpi.c (grub_cmd_acpi): Don't override errors. + * grub-core/font/font.c (open_section): Likewise. + * grub-core/loader/i386/bsd.c (grub_bsd_load_aout): New argument + filename. Don't override errors. + (grub_cmd_openbsd_ramdisk): Don't override errors. + * grub-core/loader/i386/linux.c (grub_cmd_linux): Likewise. + (grub_cmd_initrd): Likewise. + * grub-core/loader/i386/pc/linux.c (grub_cmd_linux): Likewise. + (grub_cmd_initrd): Likewise. + * grub-core/loader/ia64/efi/linux.c (grub_load_elf64): Likewise. + (grub_cmd_linux): Likewise. + (grub_cmd_initrd): Likewise. + (grub_cmd_payload): Likewise. + * grub-core/loader/mips/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/multiboot.c (grub_cmd_multiboot): Likewise. + (grub_cmd_module): Likewise. + * grub-core/loader/powerpc/ieee1275/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/sparc64/ieee1275/linux.c (grub_cmd_initrd): Likewise. + * grub-core/loader/xnu.c (grub_xnu_load_driver): Likewise. + (grub_cmd_xnu_mkext): Likewise. + (grub_cmd_xnu_ramdisk): Likewise. + (grub_xnu_check_os_bundle_required): Likewise. + (grub_xnu_load_kext_from_dir): Likewise. + (grub_cmd_xnu_kextdir): Likewise. + * grub-core/loader/xnu_resume.c (grub_xnu_resume): Likewise. + +2011-12-25 Vladimir Serbinenko + + * grub-core/fs/minix.c (grub_minix_mount) [MODE_MINIX3]: Treat 0xffff + as 1024 in block size field. Found on one of my test images. + Small optimisation while on it. + +2011-12-25 Vladimir Serbinenko + + * docs/grub.texi (Filesystems): Mention SFS as Latin1 filesystem. + * grub-core/fs/sfs.c (grub_sfs_mount): Fix a memory leak while on it. + (grub_sfs_iterate_dir): Convert Latin1 to UTF8. Stylistic and + performance fixes while on it. + (grub_sfs_close): Fix memory leak while on it. + (grub_sfs_label): Convert Latin1 to UTF-8. + +2011-12-25 Vladimir Serbinenko + + * grub-core/fs/hfs.c (grub_hfs_dir): Cap keylen to actually available + space to avoid overflows. + (grub_hfs_label): Convert from macroman to UTF-8. + +2011-12-25 Vladimir Serbinenko + + * grub-core/fs/affs.c (grub_affs_label): Interpret label as latin1. + +2011-12-25 Vladimir Serbinenko + + * grub-core/normal/menu.c (menu_init): Don't stop menu init at gfxterm. + +2011-12-25 Vladimir Serbinenko + + * unicode: Import Unicode 6.0 data. + +2011-12-25 Vladimir Serbinenko + + * grub-core/term/gfxterm.c (grub_gfxterm_putchar): Don't set values + outside of range. + +2011-12-25 Vladimir Serbinenko + + Avoid cutting in the middle of UTF-8 character. + + * include/grub/charset.h (grub_getend): New function. + * grub-core/script/function.c (grub_script_function_find): Use + grub_getend. + * grub-core/normal/completion.c (add_completion): Likewise. + +2011-12-25 Vladimir Serbinenko + + * grub-core/normal/charset.c (grub_ucs4_to_utf8): Small stylistic fix. + (grub_bidi_line_logical_to_visual): Skip tags. They are deprecated. + * include/grub/unicode.h (GRUB_UNICODE_TAG_START): New enum value. + (GRUB_UNICODE_TAG_END): Likewise. + (GRUB_UNICODE_LAST_VALID): Likewise. + +2011-12-25 Vladimir Serbinenko + + * include/grub/unicode.h (grub_unicode_compact_range): Replace end with + len and make it smaller. All users updated. + * util/import_unicode.py: Put length and not end character. + Check length. + +2011-12-25 Vladimir Serbinenko + + Make better Unicode-compliant and unify some UTF-8 code pathes. + + * grub-core/normal/charset.c (grub_utf8_to_utf16): Don't eat possibly + valid character. + (grub_is_valid_utf8): Use grub_utf8_process. + Check resulting code range. + (grub_utf8_to_ucs4): Use grub_utf8_process. + * include/grub/charset.h (grub_utf16_to_utf8): Don't eat up a possibly + valid character. + +2011-12-25 Vladimir Serbinenko + + * grub-core/io/bufio.c (grub_bufio_read): Fix handling of corner cases. + +2011-12-25 Vladimir Serbinenko + + * docs/grub.texi (Filesystems): Mention AFS. + +2011-12-25 Vladimir Serbinenko + + * docs/grub.texi (Filesystems): Clarify restrictions. + (Regexp): Mention non-Unicode regexp behaviour. + (Other): Mention non-Unicode matching behaviour. + +2011-12-24 Vladimir Serbinenko + + Make HFS implementation use MacRoman. + + * grub-core/fs/hfs.c (MAX_UTF8_PER_MAC_ROMAN): New define. + (macroman): New const array. + (macroman_to_utf8): New function. + (utf8_to_macroman): Likewise. + (grub_hfs_find_dir): Use utf8_to_macroman. + (grub_hfs_dir): Use macroman_to_utf8. + Set case_insensitive. + +2011-12-24 Vladimir Serbinenko + + * docs/grub.texi (Filesystems): Add IEEE1275 full-path example. + +2011-12-24 Vladimir Serbinenko + + Integrate hints into autogeneration scripts. + + * docs/grub.texi (Filesystems): Add a hostdisk example. + * Makefile.util.def (grub-mkdevicemap): Remove ofpath. + (grub-probe): Add ofpath. + * gentpl.py: Remove group nosparc64. + * grub-core/commands/search.c (cache_entry): New struct. + (cache): New var. + (FUNC_NAME): Use and save cache. Fix handling of trailing comma. + * grub-core/commands/search_wrap.c (options): Add platform-specific + hint options. + (grub_cmd_search): Handle platform-specific hints. + (GRUB_MOD_INIT): Declare grub_cmd_search as accept_dash. + * grub-core/kern/emu/hostdisk.c (map): New field device_map. + (grub_util_biosdisk_data): Likewise. + (grub_util_biosdisk_open): Set device_map. + (read_device_map): Handle "" as indication of no map. + Set device_map. + (find_system_device): Add hostdisk/ prefix for autogenerated entries. + (grub_util_biosdisk_get_compatibility_hint): New function. + * grub-core/normal/main.c (features): Add feature_platform_search_hint. + * include/grub/emu/hostdisk.h + (grub_util_biosdisk_get_compatibility_hint): New proto. + * util/grub-install.in: Don't call grub-mkdevicemap. + Add platform-specific hint to load.cfg. + * util/grub-mkconfig.in: Don't call grub-mkdevicemap. + * util/grub-mkconfig_lib.in (prepare_grub_to_access_device): Add + hints. Set root preliminary to compatibility hint, not to OS name. + * util/grub-probe.c (PRINT_*): Add hints. + (print): Make static. + (escape_of_path): New function. + (guess_bios_drive): Likewise. + (guess_efi_drive): Likewise. + (guess_baremetal_drive): Likewise. + (print_full_name): Likewise. + (probe): Handle hints. + (main): Likewise. + * util/ieee1275/devicemap.c: Removed. + * util/ieee1275/ofpath.c (find_obppath): Allow to fail. All users + updated. + (grub_util_devname_to_ofpath): Return NULL on failure. + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev): Fix + resource leak. + * util/getroot.c (grub_util_pull_device): Fix memory leak. + + * po/POTFILES.in: Regenerated. + + Allow purely long options + + * grub-core/lib/arg.c (SHORT_ARG_HELP): Removed. + (SHORT_ARG_USAGE): Likewise. + (grub_arg_show_help): Compare opt with help_options. + (parse_option): Receive opt as argument. If makes big simplificatons. + All users updated + +2011-12-24 Vladimir Serbinenko + + * grub-core/lib/libgcrypt_wrap/cipher_wrap.h (WORDS_BIGENDIAN): + Restructure to avoid warning. + +2011-12-24 Vladimir Serbinenko + + * util/grub-install.in: Account for possible escaped comma in device + name. + +2011-12-24 Vladimir Serbinenko + + * util/ieee1275/ofpath.c (of_path_of_ide): Fix address for secondary + channel. + +2011-12-24 Vladimir Serbinenko + + * grub-core/kern/ieee1275/openfw.c (grub_devalias_iterate): Fix + allocation and zero-setting. + (grub_ieee1275_get_devname): Check that alias is complete. + +2011-12-24 Vladimir Serbinenko + + * grub-core/kern/disk.c (grub_disk_read): Fix hook calling for + unaligned segments. + +2011-12-24 Vladimir Serbinenko + + * grub-core/disk/ieee1275/ofdisk.c (grub_ofdisk_iterate): Add ieee1275/ + prefix. + (grub_ofdisk_open): Check and discard ieee1275 prefix. + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_encode_devname): + Add ieee1275 prefix. + +2011-12-23 Vladimir Serbinenko + + * docs/grub.texi (Filesystems): Update. + +2011-12-23 Vladimir Serbinenko + + Support odc, newc and bigendian cpio formats. + + * Makefile.util.def (libgrubmods): Add odc.c, newc.c and cpio_be.c. + * grub-core/Makefile.core.def (newc): New module. + (odc): Likewise. + (cpio_be): Likewise. + * grub-core/fs/cpio.c (ALIGN_CPIO): New macro. + (MAGIC): Likewise. + (MAGIC2): Likewise. + (head) [MODE_ODC]: Adapt for the format. + (head) [MODE_NEWC]: Likewise. + (head) [!MODE_*]: Write fields of interest as arrays. + (MAGIC_USTAR): Removed. + (read_number) [MODE_NEWC]: Change to hex. + (read_number) [!MODE_*]: Parse binary arrays. + (grub_cpio_find_file): Factor out the code for better structure and + always use read_number. + (grub_cpio_mount): Use MAGIC and MAGIC2. + (grub_cpio_dir): Exit on first hook non-0 return. + (grub_cpio_fs) [MODE_ODC]: Set name to odc. + (grub_cpio_fs) [MODE_NEWC]: Set name to newc. + (GRUB_MOD_INIT) [MODE_ODC]: Set name to odc. + (GRUB_MOD_INIT) [MODE_NEWC]: Set name to newc. + (GRUB_MOD_FINI) [MODE_ODC]: Set name to odc. + (GRUB_MOD_FINI) [MODE_NEWC]: Set name to newc. + * grub-core/fs/newc.c: New file. + * grub-core/fs/odc.c: Likewise. + * grub-core/fs/cpio_be.c: Likewise. + +2011-12-23 Vladimir Serbinenko + + Fix handling of tar numbers occupying the whole field. + + * grub-core/fs/cpio.c (read_number): New function. + (grub_cpio_find_file): Use read_number instead of strtoull. + +2011-12-23 Vladimir Serbinenko + + * grub-core/fs/cpio.c (grub_cpio_find_file): Fix handling of names + occupying the whole field size. + +2011-12-23 Lukas Anzinger + + * util/grub-mkconfig_lib.in (version_test_gt): Fix variable names. + +2011-12-23 Vladimir Serbinenko + + * grub-core/net/net.c (grub_cmd_delroute): Add missing out condition. + +2011-12-23 Seth Goldberg + + * grub-core/Makefile.core.def (lzma_decompress): Add missing + TARGET_IMG_LDFLAGS. + +2011-12-23 Vladimir Serbinenko + + * util/getroot.c (ESCAPED_PATH_MAX): New define. + (mountinfo_entry): Increase the field size to take escaping into + account. + (find_root_device_from_libzfs): Add one byte to size of strings for + security. + +2011-12-23 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (grub_reed_solomon_add_redundancy): Add + an assert. + * util/grub-setup.c (setup): Likewise. + +2011-12-23 Vladimir Serbinenko + + * grub-core/boot/i386/pc/startup_raw.S: Add missing argument for + _LzmaDecodeA. + +2011-12-22 Vladimir Serbinenko + + * docs/grub.texi (Internationalisation): New section. + +2011-12-22 Vladimir Serbinenko + + * docs/grub.texi (Loopback booting): New section. + +2011-12-22 Keshav P R + + * util/grub-mkstandalone.in: Fix minor typo errors. + +2011-12-20 Vladimir Serbinenko + + IPv6, TCP, HTTP, ICMP and DNS support. Several cleanups and bugfixes. + + * grub-core/Makefile.core.def (net): Add net/dns.c, net/tcp.c, + net/icmp.c and net/icmp6.c. + (http): New module. + (priority_queue): Likewise. + * grub-core/io/bufio.c: Rewritten. + * grub-core/lib/legacy_parse.c (legacy_command): New argument type + TYPE_WITH_CONFIGFILE_OPTION. + (legacy_commands): Add bootp and dhcp. + (is_option): Handle TYPE_WITH_CONFIGFILE_OPTION. + (grub_legacy_parse): Likewise. + * grub-core/lib/priority_queue.c: New file. + * grub-core/net/arp.c: Add missing license header. + (arp_find_entry): Removed. + (arp_find_entry): Likewise. + (grub_net_arp_resolve): Rename to ... + (grub_net_arp_send_request): ...this. + (grub_net_arp_receive): New card argument. + * grub-core/net/bootp.c (parse_dhcp_vendor): Clean up. + Set router and DNS server. + (grub_net_configure_by_dhcp_ack): Handle routing information. + (grub_cmd_bootp): Set checksum. + (grub_bootp_init): Remove net_dhcp. + * grub-core/net/dns.c: New file. + * grub-core/net/drivers/efi/efinet.c (send_card_buffer): Wait for + completion. + (get_card_packet): Handle allocation. + (grub_efinet_findcards): Set mtu. + * grub-core/net/drivers/emu/emunet.c: Add missing license header. + (get_card_packet): Handle allocation. + (emucard): Set mtu. + * grub-core/net/drivers/i386/pc/pxe.c (grub_pxe_recv): Handle allocation + (GRUB_MOD_INIT): Set mtu. + * grub-core/net/drivers/ieee1275/ofnet.c (grub_ofnetcard_data): Remove + mtu. + (get_card_packet): Handle allocation. + (grub_ofnet_findcards): Set mtu. + * grub-core/net/ethernet.c (send_ethernet_packet): Add compile time + assert. + (grub_net_recv_ethernet_packet): Handle IPv6. + * grub-core/net/http.c: New file. + * grub-core/net/icmp.c: Likewise. + * grub-core/net/icmp6.c: Likewise. + * grub-core/net/ip.c (ip6addr): New type. + (ip6hdr): Likewise. + (reassemble): Likewise. + (cmp): New function. + (reassembles): New variable. + (grub_net_ip_chksum): Handle 0xffff sum and unaligned buffers. + (id): New variable. + (send_fragmented): New function. + (grub_net_send_ip_packet): Rename to ... + (grub_net_send_ip4_packet): ... this. Send fragmented if needed. + Handle non-UDP. + (grub_net_recv_ip_packets): Rename to ... + (handle_dgram): ... this. Check checksum. Handle non-UDP. + (free_rsm): New function. + (free_old_fragments): Likewise. + (grub_net_recv_ip4_packets): New function. + (grub_net_send_ip6_packet): Likewise. + (grub_net_send_ip_packet): Likewise. + (grub_net_recv_ip6_packets): Likewise. + (grub_net_recv_ip_packets): Likewise. + * grub-core/net/net.c (grub_net_link_layer_entry): New struct. + (LINK_LAYER_CACHE_SIZE): New const. + (link_layer_find_entry): New function. + (grub_net_link_layer_add_address): Likewise. + (grub_net_link_layer_resolve_check): Likewise. + (grub_net_link_layer_resolve): Likewise. + (grub_net_ipv6_get_slaac): Likewise. + (grub_net_ipv6_get_link_local): Likewise. + (grub_cmd_ipv6_autoconf): Likewise. + (parse_ip): Handle one number representation. + (parse_ip6): New functoion. + (match_net): Handle IPv6. + (grub_net_resolve_address): Handle IPv6 and DNS. + (grub_net_resolve_net_address): Handle IPv6. + (route_cmp): New function. + (grub_net_route_address): Find best route. + (grub_net_addr_to_str): Handle IPv6. + (grub_net_addr_cmp): New function. + (grub_net_add_addr): Register local route. + (print_net_address): Handle net address. + (grub_net_poll_cards): Retransmit TCP. + (grub_net_poll_cards_idle_real): Likewise. + (have_ahead): New function. + (grub_net_seek_real): Use underlying seek. + (GRUB_MOD_INIT): Register net_ipv6_autoconf and init dns. + * grub-core/net/tcp.c: New file. + * grub-core/net/tftp.c (tftp_data): Add priority_queue. + (cmp): New function. + (ack): Likewise. + (tftp_receive): Handle unordered input. + (destroy_pq): New function. + (tftp_close): Close pq. + * grub-core/net/udp.c: Put missing license header. + (grub_net_udp_socket): New function. + (udp_socket_register): Likewise. + (grub_net_udp_close): Likewise. + (grub_net_recv_udp_packet): Check checksum. + * include/grub/efi/api.h (grub_efi_simple_network): Add status. + * include/grub/misc.h (grub_memchr): New function. + * include/grub/net.h (GRUB_NET_*_SIZE): New enum. + (grub_net_card_driver): Return buf in recv. + (grub_net_slaac_mac_list): New struct. + (grub_network_level_protocol_id): Add ipv6. + (grub_net_network_level_addr): Likewise. + (grub_net_network_level_net_addr): Likewise. + (grub_net_app_protocol): Add seek. + (grub_net_socket): Removed. + (grub_net_sockets): Likewise. + (grub_net_socket_register): Likewise. + (grub_net_socket_unregister): Likewise. + (FOR_NET_SOCKETS): Likewise. + (grub_net_add_addr): Add const. + (GRUB_NET_BOOTP_*): New enum. + (grub_net_addr_cmp): New proto. + (GRUB_NET_MAX_STR_ADDR_LEN): Take IPV6 into account. + (GRUB_NET_MAX_STR_HWADDR_LEN): New define. + (grub_net_hwaddr_to_str): NEw proto. + (FOR_NET_NETWORK_LEVEL_INTERFACES): New macro. + (FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE): Handle NULL. + (grub_dns_init): New proto. + (grub_dns_fini): Likewise. + (grub_net_tcp_retransmit): Likewise. + (grub_net_link_layer_add_address): Likewise. + (grub_net_link_layer_resolve_check): Likewise. + (grub_net_link_layer_resolve): Likewise. + (grub_net_dns_lookup): Likewise. + (grub_net_add_dns_server): Likewise. + (grub_net_remove_dns_server): Likewise. + (GRUB_NET_TRIES): New const. + (GRUB_NET_INTERVAL): Likewise. + * include/grub/net/arp.h: Mostly rewritten. + * include/grub/net/ethernet.h (grub_net_ethertype_t): New enum. + * include/grub/net/ip.h: Mostly rewritten. + * include/grub/net/netbuff.h: Indent. + * include/grub/net/tcp.h: New file. + * include/grub/net/udp.h: Mostly rewritten. + * include/grub/priority_queue.h: New file. + * include/grub/types.h (PRIdGRUB_SSIZE): New define. + (grub_swap_bytes64_compile_time): Likewise. + (grub_cpu_to_be16_compile_time): Likewise. + (grub_cpu_to_be32_compile_time): Likewise. + (grub_cpu_to_be64_compile_time): Likewise. + (grub_be_to_cpu64_compile_time): Likewise. + +2011-12-16 Vladimir Serbinenko + + * grub-core/commands/i386/pc/drivemap.c (int13slot): Replace + UINT_TO_PTR with cast. + +2011-12-15 Vladimir Serbinenko + + * util/import_gcry.py: Skip _gcry_rmd160_mixblock and serpent_test. We + don't use them. + +2011-12-15 Vladimir Serbinenko + + * util/import_gcry.py: Don't add include camellia.h to camellia.c. It's + already there. + +2011-12-15 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Clean multiboot header to avoid + confusing ipxe. + +2011-12-15 Vladimir Serbinenko + + * grub-core/lib/libgcrypt/cipher/md4.c (transform) [WORDS_BIGENDIAN]: + Add missing const attribute. + * grub-core/lib/libgcrypt/cipher/md5.c (transform) [WORDS_BIGENDIAN]: + Likewise. + * grub-core/lib/libgcrypt/cipher/rmd160.c (transform) [WORDS_BIGENDIAN]: + Likewise. + +2011-12-15 Vladimir Serbinenko + + * grub-core/lib/libgcrypt/cipher/serpent.c (serpent_key_prepare): Fix + misaligned access. + (serpent_setkey): Likewise. + (serpent_encrypt_internal): Likewise. + (serpent_decrypt_internal): Likewise. + (serpent_encrypt): Don't put an alignment-increasing cast. + (serpent_decrypt): Likewise. + (serpent_test): Likewise. + +2011-12-15 Vladimir Serbinenko + + * grub-core/loader/multiboot.c (grub_cmd_module): Fix target address. + +2011-12-15 Vladimir Serbinenko + + Replace UINT_TO_PTR and PTR_TO_UINT with explicit grub_addr_t casts. + + * include/grub/types.h (UINT_TO_PTR): Removed. All users switched to + grub_addr_t casts. + (PTR_TO_UINT64): Likewise. + (PTR_TO_UINT32): Likewise. + +2011-12-15 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Decrease the higher limit + because of stack. + * util/grub-setup.c (setup): Don't add redundancy past the higher load + limit. + +2011-12-15 Vladimir Serbinenko + + * grub-core/gfxmenu/gui_label.c (label_paint): Handle the case + text_width > available width a bit more gracefully. + +2011-12-15 Vladimir Serbinenko + + * grub-core/loader/i386/bsdXX.c (grub_freebsd_load_elfmodule): Fix + current address calculation. + +2011-12-15 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (decode_block): Allocate on heap and not + stack. + (encode_block): Likewise. + +2011-12-15 Vladimir Serbinenko + + * grub-core/boot/i386/pc/startup_raw.S: Clear direction flag for + certainety. + +2011-12-15 Vladimir Serbinenko + + * grub-core/boot/i386/pc/startup_raw.S: Move realmode routines to + non-RS part to avoid RS messing with GDT. + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): + Increase to suit in realmode routines. + +2011-12-15 Vladimir Serbinenko + + * grub-core/kern/i386/realmode.S: Increase alignment. + * grub-core/boot/i386/pc/startup_raw.S: Likewise. + +2011-12-14 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (init_powx): Set gf_powx_inv[0] just to + be deterministic. + (syndroms): Compute 0 syndrom. + (rs_recover): Use 0 syndrom. + +2011-12-14 Vladimir Serbinenko + + * include/grub/kernel.h (FOR_MODULES): Make it a bit faster. + +2011-12-14 Vladimir Serbinenko + + * include/grub/types.h (GRUB_PROPERLY_ALIGNED_ARRAY): Add missing + brackets. + +2011-12-14 Vladimir Serbinenko + + * grub-core/gfxmenu/widget-box.c (get_left_pad): Take corners into + account. + (get_top_pad): Likewise. + (get_right_pad): Likewise. + (get_bottom_pad): Likewise. + +2011-12-14 Vladimir Serbinenko + + * grub-core/gfxmenu/gui_list.c (draw_menu): Don't use assignment in if. + +2011-12-14 Vladimir Serbinenko + + * include/grub/efi/api.h (grub_efi_memory_descriptor): Add packed + attribute as the structure isn't guaranteed to be properly aligned. + (grub_efi_pci_device_path): Likewise. + (grub_efi_pccard_device_path): Likewise. + (grub_efi_memory_mapped_device_path): Likewise. Additionaly explicitly + specify the size of `memory_type'. + (grub_efi_vendor_device_path): Likewise. + (grub_efi_controller_device_path): Likewise. + (grub_efi_acpi_device_path): Likewise. + (grub_efi_expanded_acpi_device_path): Likewise. + (grub_efi_atapi_device_path): Likewise. + (grub_efi_scsi_device_path): Likewise. + (grub_efi_fibre_channel_device_path): Likewise. + (grub_efi_1394_device_path): Likewise. + (grub_efi_usb_device_path): Likewise. + (grub_efi_usb_class_device_path): Likewise. + (grub_efi_i2o_device_path): Likewise. + (grub_efi_mac_address_device_path): Likewise. + (grub_efi_ipv4_device_path): Likewise. + (grub_efi_ipv6_device_path): Likewise. + (grub_efi_infiniband_device_path): Likewise. + (grub_efi_uart_device_path): Likewise. + (grub_efi_vendor_messaging_device_path): Likewise. + (grub_efi_hard_drive_device_path): Likewise. + (grub_efi_cdrom_device_path): Likewise. + (grub_efi_vendor_media_device_path): Likewise. + (grub_efi_file_path_device_path): Likewise. + (grub_efi_protocol_device_path): Likewise. + (grub_efi_piwg_device_path): Likewise. + (grub_efi_bios_device_path): Likewise. + +2011-12-14 Vladimir Serbinenko + + * include/grub/charset.h (grub_utf16_to_utf8): Make src a const pointer. + (grub_ucs4_to_utf8_alloc): Likewise. + (grub_ucs4_to_utf8): Likewise. + * grub-core/normal/charset.c (grub_ucs4_to_utf8): Likewise. + (grub_ucs4_to_utf8_alloc): Likewise. + +2011-12-14 Vladimir Serbinenko + + AFFS never uses unicode. + + * include/grub/charset.h (GRUB_MAX_UTF8_PER_LATIN1): New const. + (grub_latin1_to_utf8): New inline function. + * grub-core/fs/affs.c (grub_affs_iterate_dir): Convert latin1 to UTF8. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/romfs.c (grub_romfs_mount): Fix pointer comparison + overflow. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/squash4.c (grub_squash_inode): Fix field sizes. + (grub_squash_dirent_header): Likewise. + (read_chunk): Don't double swap. + (grub_squash_iterate_dir): Fix swap sizes. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/jfs.c (grub_jfs_getent): Handle UTF16 endianness. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/hfs.c (grub_hfs_find_node): Handle unaligned keys. + (grub_hfs_iterate_dir): Likewise. + +2011-12-13 Vladimir Serbinenko + + Fix video on platforms where unaligned access is forbidden. + Make several optimisations while on it. + + * grub-core/video/fb/fbblit.c (grub_video_fbblit_replace_directN): + Optimise and use GRUB_VIDEO_FB_ADVANCE_POINTER. + (grub_video_fbblit_replace_32bit_1bit): Likewise. + (grub_video_fbblit_replace_24bit_1bit) [!GRUB_HAVE_UNALIGNED_ACCESS]: + Disable. + (grub_video_fbblit_replace_16bit_1bit): + Optimise and use GRUB_VIDEO_FB_ADVANCE_POINTER. + (grub_video_fbblit_replace_8bit_1bit): Likewise. + (grub_video_fbblit_replace_BGRX8888_RGBX8888): Likewise. + (grub_video_fbblit_replace_BGRX8888_RGB888): Likewise. + (grub_video_fbblit_replace_BGR888_RGBX8888): Likewise. + (grub_video_fbblit_replace_BGR888_RGBX8888): Likewise. + (grub_video_fbblit_replace_BGR888_RGB888): Likewise. + (grub_video_fbblit_replace_RGBX8888_RGB88): Likewise. + (grub_video_fbblit_replace_RGB888_RGBX888): Likewise. + (grub_video_fbblit_replace_RGB888_RGBX8888): Likewise. + (grub_video_fbblit_replace_index_RGBX8888): Likewise. + (grub_video_fbblit_replace_index_RGB888): Likewise. + (grub_video_fbblit_blend_BGRA8888_RGBA8888): Likewise. + (grub_video_fbblit_blend_BGR888_RGBA8888): Likewise. + (grub_video_fbblit_blend_RGBA8888_RGBA8888): Likewise. + (grub_video_fbblit_blend_RGB888_RGBA8888): Likewise. + (grub_video_fbblit_blend_index_RGBA8888): Likewise. + (grub_video_fbblit_blend_XXXA8888_1bit): Likewise. + (grub_video_fbblit_blend_XXX888_1bit) [!GRUB_HAVE_UNALIGNED_ACCESS]: + Disable. + (grub_video_fbblit_blend_XXX565_1bit): + Optimise and use GRUB_VIDEO_FB_ADVANCE_POINTER. + * grub-core/video/fb/fbfill.c (grub_video_fbfill_direct32): Likewise. + * grub-core/video/fb/fbutil.c (grub_video_fb_get_video_ptr): Return + void *. + * grub-core/video/fb/video_fb.c (common_blitter) + [!GRUB_HAVE_UNALIGNED_ACCESS]: Skip disabled blitters. + (grub_video_fb_create_render_target_from_pointer) + [!GRUB_HAVE_UNALIGNED_ACCESS]: Check alignment. + * include/grub/fbutil.h (grub_video_fb_get_video_ptr): Return void *. + * include/grub/i386/types.h (GRUB_HAVE_UNALIGNED_ACCESS): New + definition. + * include/grub/x86_64/types.h (GRUB_HAVE_UNALIGNED_ACCESS): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/kern/sparc64/dl.c (grub_arch_dl_relocate_symbols): Support + HH22 and HM10 relocations. + +2011-12-13 Vladimir Serbinenko + + * grub-core/kern/misc.c (grub_vsnprintf_real): Fix fmt2 parsing. + +2011-12-13 Vladimir Serbinenko + + * grub-core/commands/videotest.c (grub_cmd_videotest): Check that + allocation succeeded. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/iso9660.c (grub_iso9660_convert_string): Make first + argument a u8 pointer. All users updated. + Handle unaligned buffers. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/iso9660.c (grub_iso9660_iterate_dir): Force inlining of + add_part to workaround compiler bug. + +2011-12-13 Vladimir Serbinenko + + * include/grub/kernel.h (FOR_MODULES): Preserve alignment invariants. + +2011-12-13 Vladimir Serbinenko + + * grub-core/loader/multiboot_mbi2.c (grub_multiboot_add_elfsyms): + Reserve alignment invariants. + (grub_multiboot_load): Likewise. + (retrieve_video_parameters): Likewise. + (grub_multiboot_make_mbi): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/loader/i386/xnu.c (grub_xnu_devprop_remove_property): Fix + incorrect pointer. + +2011-12-13 Vladimir Serbinenko + + * grub-core/disk/pata.c (grub_pata_pio_read): Handle unaligned buffer. + (grub_pata_pio_write): Likewise. + +2011-12-13 Vladimir Serbinenko + + Add noreturn attributes and remove unreachable code. + + * grub-core/bus/cs5536.c (grub_cs5536_smbus_wait): Remove unreachable + code. + * grub-core/commands/halt.c (grub_cmd_halt): Remove unreachable + code. Mark as noreturn. + * grub-core/commands/minicmd.c (grub_mini_cmd_exit): Likewise. + * grub-core/commands/reboot.c (grub_cmd_reboot): Likewise. + * grub-core/disk/efi/efidisk.c (grub_efidisk_get_device_name): Remove + unreachable code. + * grub-core/kern/main.c (grub_main): Mark as noreturn. + * grub-core/kern/rescue_reader.c (grub_rescue_run): Likewise. + * grub-core/lib/posix_wrap/stdlib.h (abort): Likewise. + * grub-core/normal/menu.c (run_menu): Remove unreachable code. + * include/grub/kernel.h (grub_main): Mark as noreturn. + * include/grub/reader.h (grub_rescue_run): Likewise. + +2011-12-13 Vladimir Serbinenko + + * include/grub/i386/qemu/memory.h (grub_machine_mmap_init): Remove + redundant declaration. + +2011-12-13 Vladimir Serbinenko + + * include/grub/net.h (grub_net_network_level_interfaces): Remove + redundant declaration. + (FOR_NET_NETWORK_LEVEL_INTERFACES): Move to appropriate place. + +2011-12-13 Vladimir Serbinenko + + * grub-core/commands/hdparm.c (le16_to_char): Make src and dest uint16 * + to ensure alignment. + (grub_hdparm_print_identify): Make argument uint16 * to ensure + alignment. Ensure tmp alignment. + (grub_cmd_hdparm): Ensure buf alignment. + * grub-core/disk/ata.c (grub_ata_strncpy): Make src and dest uint16 * + to ensure alignment. + (grub_ata_dumpinfo): Ensure text alignment. + (grub_atapi_identify): Preserve alignment invariant. + (grub_ata_identify): Likewise. Use grub_get_unaligned32 when necessary. + +2011-12-13 Vladimir Serbinenko + + * include/grub/emu/misc.h (xasprintf): Add missing format attribute. + * include/grub/mips/kernel.h (grub_halt): Remove redundant declaration. + * include/grub/mips/qemu_mips/kernel.h (grub_halt): Likewise. + * include/grub/misc.h (grub_reboot) + [GRUB_MACHINE_EMU || GRUB_MACHINE_QEMU_MIPS]: Export. + (grub_halt) [__mips__]: Likewise. + +2011-12-13 Vladimir Serbinenko + + * include/grub/efi/memory.h (grub_machine_mmap_iterate): + Remove redundant declaration. + (grub_mmap_get_post64): Likewise. + (grub_mmap_get_upper): Likewise. + (grub_mmap_get_lower): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/partmap/dvh.c (grub_dvh_is_valid): Make argument + uint32_t * to ensure alignment. + (dvh_partition_map_iterate): Make `block' a union to ensure alignment. + +2011-12-13 Vladimir Serbinenko + + * grub-core/partmap/sunpc.c (grub_sun_is_valid): Make argument + uint16_t * to ensure alignment. + (sun_pc_partition_map_iterate): Make `block' a union to ensure + alignment. + +2011-12-13 Vladimir Serbinenko + + * grub-core/partmap/sun.c (grub_sun_is_valid): Make argument uint16_t * + to ensure alignment. + (sun_partition_map_iterate): Make `block' a union to ensure alignment. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/ntfs.c (u16at): Make into inline function. + Handle unaligned pointers. + (u32at): Likewise. + (u64at): Likewise. + (fixup): Use byte access instead of v16at. + (find_attr): Fix imporper usage of v32at. + (read_data): Likewise. + (list_file): Handle byte-swapping and unaligned strings. + (grub_ntfs_label): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/udf.c (grub_udf_partmap): Add packed attribute + as it's not necessarily aligned. + +2011-12-13 Vladimir Serbinenko + + * grub-core/kern/mips/qemu_mips/init.c (grub_at_keyboard_init): Remove + redundant declaration. + (grub_serial_init): Likewise. + (grub_terminfo_init): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (DVA_OFFSET_TO_PHYS_SECTOR): Make into inline + function. + (ZAP_HASH_IDX): Likewise. + (ZAP_LEAF_HASH_SHIFT): Likewise. + (ZAP_LEAF_HASH_NUMENTRIES): Likewise. + (LEAF_HASH): Likewise. + (ZAP_LEAF_NUMCHUNKS): Likewise. + (ZAP_LEAF_CHUNK): Likewise. Changed pointer arithmetic to preserve + alignment invariants. Return pointer. All users updated. + (ZAP_LEAF_ENTRY): Make into inline function. + (NBBY): Removed. + (xor): LIkewise. + (xor_out): Use grub_crypto_xor. + (dnode_get_path): Use grub_get_unaligned. + (nvlist_find_value): Likewise. + (grub_zfs_nvlist_lookup_uint64): Likewise. + (grub_zfs_nvlist_lookup_string): Likewise. + (get_nvlist_size): Likewise. + (grub_zfs_open): Likewise. + (fill_fs_info): Likewise. + (grub_zfs_dir): Likewise. + * include/grub/zfs/zap_leaf.h (zap_leaf_phys): Adapt to preserve + alignment invariants. + * include/grub/zfs/zio.h (zio_eck_t): Mark as packed as it's not + necessarily aligned. + +2011-12-13 Vladimir Serbinenko + + * grub-core/net/netbuff.c (grub_netbuff_alloc): Ensure proper alignment. + +2011-12-13 Vladimir Serbinenko + + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Change pointer + arithmetic to conserve alignment invariants. + +2011-12-13 Vladimir Serbinenko + + * include/grub/efiemu/efiemu.h (grub_efiemu_get_memory_map): Remove + redundant declaration. + (grub_efiemu_mm_obtain_request): Likewise. + (grub_efiemu_prepare): Likewise. + +2011-12-13 Vladimir Serbinenko + + * include/grub/list.h: Explicitly cast return of grub_bad_type_cast + to match types. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/hfsplus.c (grub_hfsplus_btree_recoffset): Handle the + case of aunaligned recptr. + (grub_hfsplus_read_block): Declare extoverflow as key to ensure + alignment. + (grub_hfsplus_btree_search): Handle unaligned index. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/xfs.c (grub_xfs_iterate_dir): Use grub_get_unaligned16 + to get freetag and skip. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/nilfs2.c (grub_nilfs2_btree_node): Add zero-size keys + array. + (grub_nilfs2_btree_node_dkeys): Ensure return pointer alignment. + (grub_nilfs2_btree_lookup): Ensure buffer alignment. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/romfs.c (grub_romfs_iterate_dir): Properly align + name for checksum and fix allocation algorithm. + +2011-12-13 Vladimir Serbinenko + + * include/grub/types.h (grub_properly_aligned_t): New type. + (GRUB_PROPERLY_ALIGNED_ARRAY): New macro. + (grub_get_unaligned16): Add explicit casts. + (grub_get_unaligned32): Likewise. + (grub_get_unaligned64): Likewise. + (grub_set_unaligned16): New function. + (grub_set_unaligned32): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/normal/datetime.c (grub_weekday_names): Make const. + +2011-12-13 Vladimir Serbinenko + + * grub-core/fs/udf.c (read_string): Macroify GRUB_MAX_UTF8_PER_UTF16. + * grub-core/fs/jfs.c (grub_jfs_diropen): Likewise. + * grub-core/fs/fat.c (grub_fat_iterate_dir): Likewise. + +2011-12-13 Vladimir Serbinenko + + * grub-core/term/at_keyboard.c (set_scancodes): Fix preprocessor + conditionals. + +2011-12-13 Vladimir Serbinenko + + * grub-core/kern/emu/main.c (main): Add missing const qualifier. + * grub-core/loader/efi/appleloader.c (devdata): Likewise. + +2011-12-13 Vladimir Serbinenko + + Unify and improve RAID and crypto xor. + + * grub-core/disk/raid.c (grub_raid_block_xor): Removed. All users + changed to grub_crypto_xor + * grub-core/lib/crypto.c (grub_crypto_xor): Moved from here ... + * include/grub/crypto.h (grub_crypto_xor): ... here. Inlined. + Use bigger types when possible. + +2011-12-13 Vladimir Serbinenko + + * grub-core/disk/raid.c (scan_devices): Fix condition. + +2011-12-13 Vladimir Serbinenko + + * grub-core/net/drivers/ieee1275/ofnet.c (bootp_response_properties): + Make name a const ptr. + +2011-12-13 Vladimir Serbinenko + + * grub-core/kern/ieee1275/ieee1275.c (grub_ieee1275_finddevice): Make + first argument a const pointer. + * grub-core/kern/ieee1275/openfw.c (grub_children_iterate): Likewise. + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_finddevice): Update + proto. + (grub_children_iterate): Likewise. + (grub_machine_mmap_iterate): Remove redundant declaration. + +2011-12-13 Vladimir Serbinenko + + * grub-core/commands/acpi.c (grub_acpi_create_ebda) [!x86]: Disable. + (grub_cmd_acpi) [!x86]: Disable EBDA. + +2011-12-13 Vladimir Serbinenko + + Enable UTF8 in gnulib regexp. + + * config.h.in (RE_ENABLE_I18N) [!GRUB_UTIL]: New define. + * grub-core/lib/posix_wrap/ctype.h (islower): Use grub_islower. + (isupper): Use grub_isupper. + (isascii): New inline function. + * grub-core/lib/posix_wrap/wchar.h: Replace dummy with real contents. + * grub-core/lib/posix_wrap/wctype.h: Likewise. + * grub-core/normal/charset.c (grub_utf8_process): New function. + (grub_utf8_to_utf16): Use grub_utf8_process. + (grub_encode_utf8_character): New function. + (grub_ucs4_to_utf8): Use grub_encode_utf8_character. + * include/grub/charset.h (grub_utf8_process): New declaration. + (grub_encode_utf8_character): Likewise. + * include/grub/misc.h (grub_islower): New inline function. + (grub_isupper): Likewise. + (grub_strchrsub): Moved down to fix the definitions. + +2011-12-13 Vladimir Serbinenko + + * grub-core/bus/usb/ohci.c (grub_ohci_check_transfer): Add an unsigned + specification. + +2011-12-13 Vladimir Serbinenko + + * include/grub/loader.h (grub_loader_register_preboot_hook): + Use struct preboot * and not void * for handle. All users updated. + (grub_loader_unregister_preboot_hook): Likewise. + +2011-12-12 Vladimir Serbinenko + + * include/grub/charset.h (GRUB_MAX_UTF8_PER_UTF16): New const. + * grub-core/fs/hfsplus.c (grub_hfsplus_catkey_internal): Change to + UTF-16-BE. All users updated. + (grub_hfsplus_cmp_catkey): Fix unicode handling. + (grub_hfsplus_iterate_dir): Likewise. + (grub_hfsplus_label): Likewise. + +2011-12-12 Vladimir Serbinenko + + * grub-core/disk/ahci.c (grub_ahci_pciinit): Fix compat condition. + +2011-11-30 Vladimir Serbinenko + + Add missing const qualifiers. + + * grub-core/commands/i386/pc/sendkey.c (keysym): Add missing const. + * grub-core/commands/lspci.c (grub_pci_classname): Likewise. + * grub-core/commands/menuentry.c (hotkey_aliases): Likewise. + * grub-core/disk/lvm.c (grub_lvm_getvalue): Likewise. + (grub_lvm_check_flag): Likewise. + * grub-core/efiemu/i386/coredetect.c + (grub_efiemu_get_default_core_name): Likewise + * grub-core/efiemu/main.c (grub_efiemu_autocore): Likewise. + * grub-core/fs/hfsplus.c (grub_hfsplus_catkey_internal): Likewise. + * grub-core/fs/ntfs.c (fixup): Likewise. + * grub-core/fs/xfs.c (grub_xfs_iterate_dir): Likewise. + * grub-core/fs/zfs/zfs.c (decomp_entry): Likewise. + (fzap_lookup): Likewise. + (zap_lookup): Likewise. + * grub-core/gnulib/regcomp.c (init_dfa): Likewise. + * grub-core/lib/legacy_parse.c (check_option): Likewise. + * grub-core/lib/posix_wrap/langinfo.h (nl_langinfo): Likewise. + * grub-core/loader/i386/bsd.c (grub_bsd_add_meta): Likewise. + (grub_freebsd_add_meta_module): Likewise. + (grub_cmd_freebsd_module): Likewise. + * grub-core/loader/i386/xnu.c (tbl_alias): Likewise. + * grub-core/loader/xnu.c (grub_xnu_register_memory): Likewise. + (grub_xnu_writetree_get_size): Likewise. + (grub_xnu_writetree_toheap_real): Likewise. + (grub_xnu_find_key): Likewise. + (grub_xnu_create_key): Likewise. + (grub_xnu_create_value): Likewise. + (grub_xnu_register_memory): Likewise. + (grub_xnu_check_os_bundle_required): Likewise. + (grub_xnu_scan_dir_for_kexts): Likewise. + (grub_xnu_load_kext_from_dir): Likewise. + * grub-core/normal/color.c (color_list): Likewise. + * grub-core/normal/completion.c (current_word): Likewise. + * grub-core/normal/menu_entry.c (insert_string): Likewise. + * grub-core/term/serial.c (grub_serial_find): Likewise. + * grub-core/term/tparm.c (grub_terminfo_tparm): Likewise. + * include/grub/efiemu/efiemu.h (grub_efiemu_get_default_core_name): + Likewise. + * include/grub/i386/bsd.h (grub_bsd_add_meta): Likewise. + (grub_freebsd_add_meta_module): Likewise. + * include/grub/lib/arg.h (grub_arg_option): Likewise. + * include/grub/net.h (grub_net_card_driver): Likewise. + (grub_net_card): Likewise. + (grub_net_app_protocol): Likewise. + * include/grub/parttool.h (grub_parttool_argdesc): Likewise. + * include/grub/serial.h (grub_serial_find): Likewise. + * include/grub/tparm.h (grub_terminfo_tparm): Likewise. + * include/grub/xnu.h (grub_xnu_create_key): Likewise. + (grub_xnu_create_value): Likewise. + (grub_xnu_find_key): Likewise. + (grub_xnu_scan_dir_for_kexts): Likewise. + (grub_xnu_load_kext_from_dir): Likewise. + + * include/grub/zfs/zio_checksum.h (zio_checksum_t): Moved from here ... + * grub-core/fs/zfs/zfs.c (zio_checksum_t): ...here. + * include/grub/zfs/zio_checksum.h (zio_checksum_info): + Moved from here ... + * grub-core/fs/zfs/zfs.c (zio_checksum_info): ... here. Added missing const. + +2011-11-28 Colin Watson + + * util/getroot.c (find_root_device_from_libzfs): Use xasprintf. + +2011-11-27 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (recovery): Fix spelling. + (read_device): Fix size calculation. + +2011-11-25 Robert Millan + + * util/getroot.c [HAVE_LIMITS_H]: Include `'. + (find_root_device_from_libzfs): Add zpool output parser to be used + as fallback when libzfs isn't available. + +2011-11-25 Seth Goldberg + + * po/Makefile.in.in: Add missing escape-continuation. + +2011-11-25 Vladimir Serbinenko + + * grub-core/fs/cpio.c (grub_cpio_dir): Handle subdirs correctly. + +2011-11-16 Vladimir Serbinenko + + * grub-core/kern/dl.c (grub_dl_load_segments): Fix alignment handling. + +2011-11-16 Vladimir Serbinenko + + * grub-core/kern/dl.c (grub_dl_unload): Fix freeing segments. + +2011-11-16 Vladimir Serbinenko + + * grub-core/kern/x86_64/efi/callwrap.S: Fix the comment. + +2011-11-14 Vladimir Serbinenko + + * grub-core/lib/adler32.c: Add missing license specification. + * grub-core/lib/crc64.c: Likewise. + * grub-core/loader/i386/pc/plan9.c: Likewise. + * grub-core/partmap/plan.c: Likewise. + +2011-11-13 Lubomir Kundrak + + Add facility to debug GRUB with gdb under qemu. + + * grub-core/gdb_grub.in: New file. + * grub-core/gmodule.pl.in: Likewise. + * grub-core/Makefile.core.def (gmodule.pl): New script. + (gdb_grub): Likewise. + +2011-11-13 Vladimir Serbinenko + + * util/grub-mount.c (argp_parser): Accept relative pathes. + * util/grub-fstest.c (argp_parser): Likewise. + +2011-11-13 Vladimir Serbinenko + + Plan9 support. + + * Makefile.util.def (libgrubmods): Add + grub-core/partmap/plan.c. + * docs/grub.texi: Notice Plan9 support. + * grub-core/Makefile.core.def (plan9): New module. + (part_plan): Likewise. + * grub-core/loader/i386/pc/plan9.c: New file. + * grub-core/partmap/plan.c: Likewise. + * include/grub/msdos_partition.h (GRUB_PC_PARTITION_TYPE_PLAN9): New + define. + (GRUB_PC_PARTITION_TYPE_LINUX_SWAP): Likewise. + * include/grub/mm.h (grub_extend_alloc): New inline function. + +2011-11-13 Vladimir Serbinenko + + Make Reed-Solomon faster by using power of generator representation of + GF(256)*. + + * grub-core/lib/reed_solomon.c (grub_uint16_t) [TEST]: Removed. + (gf_double_t): Likewise. + (gf_invert): Removed. + (gf_powx): New array. + (gf_powx_inv): Likewise. + (scratch): Move higher. + (gf_reduce): Removed. + (gf_mul): Use powx. + (gf_invert): Likewise. + (init_inverts): Replaced with ... + (init_powx): ...this. All users updated. + (pol_evaluate): Replace multiplications with additions. + (rs_encode): Likewise. + (gauss_eliminate): Call gf_invert. + (grub_reed_solomon_add_redundancy): Call init_powx. + (grub_reed_solomon_recover): Call init_powx unconditionally. + +2011-11-12 Vladimir Serbinenko + + * grub-core/partmap/gpt.c (gpt_partition_map_embed): Fix spelling. + +2011-11-12 Vladimir Serbinenko + + * grub-core/partmap/gpt.c (gpt_partition_map_embed): Restore + disk->partiton for safety. + +2011-11-12 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev): + Fix a memory leak. + (grub_util_biosdisk_get_grub_dev): Add a useful debug info. + +2011-11-12 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (find_system_device): Fix a memory leak. + +2011-11-12 Vladimir Serbinenko + + * include/grub/lvm.h (grub_lvm_pv): Correct start type. + +2011-11-12 Vladimir Serbinenko + + Fix spaces handling in proc/self/mountinfo. + + * util/getroot.c (unescape): New function. + (grub_find_root_device_from_mountinfo): Use unescape. + +2011-11-12 Vladimir Serbinenko + + Support ZFS embedding. + + * grub-core/fs/zfs/zfs.c (grub_zfs_embed): New function. + (grub_zfs_fs): Register grub_zfs_embed. + +2011-11-12 Vladimir Serbinenko + + Fix MIPS compilation. + + * grub-core/boot/mips/startup_raw.S: Use GRUB_DECOMPRESSOR_* + * include/grub/offsets.h: Rename decompressor fields from + GRUB_KERNEL_* to GRUB_DECOMPRESSOR_*. + * util/grub-mkimage.c (image_targets): Use new names. + +2011-11-12 Vladimir Serbinenko + + Defer multiboot device parsing until we're in compressed part. + + * grub-core/boot/i386/pc/lnxboot.S: Remove setting dos_part and + bsd_part. setdevice has fallen into disuse. + * grub-core/boot/i386/pc/startup_raw.S (dos_part): Removed. + (bsd_part): Likewise. + (boot_dev): New variable. + (multiboot_trampoline): Don't parse multiboot device. + Pass multiboot device in %edx. + * grub-core/disk/i386/pc/biosdisk.c (GRUB_MOD_INIT): Parse + grub_boot_device. + * grub-core/kern/i386/pc/init.c (grub_machine_get_bootlocation): + Likewise. + * grub-core/kern/i386/pc/startup.S: Save edx. + (grub_boot_drive): Removed. + (grub_install_dos_part): Likewise. + (grub_install_bsd_part): Likewise. + (grub_boot_device): New variable. + * include/grub/i386/pc/kernel.h (grub_install_dos_part): Removed. + (grub_install_bsd_part): Likewise. + (grub_boot_drive): Likewise. + (grub_boot_device): New variable. + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_INSTALL_DOS_PART): + Removed. + (GRUB_KERNEL_I386_PC_INSTALL_BSD_PART): Likewise. + (GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY): Moved lower. + (GRUB_KERNEL_MACHINE_INSTALL_BSD_PART): Removed. + (GRUB_KERNEL_MACHINE_INSTALL_DOS_PART): Likewise. + * util/grub-install.in: Remove redundant condition. + +2011-11-12 Vladimir Serbinenko + + Fix bug introduced by previous commit. + + * grub-core/boot/i386/pc/startup_raw.S: Compute RS start correctly. + +2011-11-12 Vladimir Serbinenko + + Use decompressors framework on i386-pc. It increases core size + by 46 bytes but improves compatibility and maintainability. + + * grub-core/Makefile.core.def (lzma_decompress): New image. + (kernel): Add i386_pc_ldflags. + * grub-core/kern/i386/pc/startup.S: Move intial part to .. + * grub-core/boot/i386/pc/startup_raw.S: ... here. Pass pointers + to real_to_prot, prot_to_real and device info. + * include/grub/offsets.h: Renamed decompressor offsets. + * util/grub-mkimage.c (grub_compression_t): New cmpression lzma. + (image_target_desc): Remove raw_size and rename decompressor fields. + (compress_kernel): Handle lzma. + (generate_image): Handle decompressors on i386-pc. + +2011-11-12 Vladimir Serbinenko + + * configure.ac: Add -fno-asynchronous-unwind-tables. + +2011-11-12 Vladimir Serbinenko + + Move assembly code to C by using intwrap. It increases core size + by 88 bytes but improves compatibility and maintainability. + + * grub-core/kern/i386/pc/startup.S (grub_console_putchar): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_putchar_real): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_getkey): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_getkey): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_getxy): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_getxy): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_gotoxy): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_gotoxy): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_cls): Moved to ... + * grub-core/term/i386/pc/console.c (grub_console_cls): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_console_setcursor): Moved to .. + * grub-core/term/i386/pc/console.c (grub_console_setcursor): + ... here. Translated to C. + * grub-core/kern/i386/pc/startup.S (grub_get_rtc): Moved to .. + * grub-core/kern/i386/pc/init.c (grub_get_rtc): ... here. + Translated to C. + * grub-core/term/i386/pc/console.c (int10_9): New function. + (grub_console_putchar): Likewise. + * include/grub/i386/pc/console.h: Removed the not anymore shared + functions. + +2011-11-12 Vladimir Serbinenko + + Move grub_chainloader_real_boot out of the kernel. + + * grub-core/Makefile.am: Remove machine/loader.h. + * grub-core/kern/i386/pc/startup.S (grub_chainloader_real_boot): + Removed. + * grub-core/lib/i386/relocator.c (grub_relocator16_esi): New extern + variable. + (grub_relocator16_keep_a20_enabled): Likewise. + (grub_relocator16_boot): Fill new variables. + * grub-core/lib/i386/relocator16.S: Add gate a20 handling. + * grub-core/loader/i386/pc/chainloader.c (grub_chainloader_boot): Use + relocator. + (grub_chainloader_unload): Likewise. + (grub_chainloader_cmd): Likewise. + * include/grub/i386/pc/loader.h: Removed. + * include/grub/i386/relocator.h (grub_relocator16_state): Add a20 + and esi. All initialisers updated. + +2011-11-12 Vladimir Serbinenko +2011-11-12 Colin Watson + + * Makefile.util.def (grub-mount): New util. + * .bzrignore: Add grub-mount. + * configure.ac: Check for fuse and enable grub-mount if available. + * docs/man/grub-mount.h2m: New file. + * util/grub-mount.c: Likewise. + +2011-11-11 Vladimir Serbinenko + + * grub-core/commands/efi/fixvideo.c: Gettextize. + * grub-core/commands/hashsum.c: Likewise. + * grub-core/commands/i386/cmostest.c: Likewise. + * grub-core/commands/i386/pc/drivemap.c: Likewise. + * grub-core/commands/i386/pc/lsapm.c: Likewise. + * grub-core/commands/i386/pc/sendkey.c: Likewise. + * grub-core/commands/lsmmap.c: Likewise. + * grub-core/commands/menuentry.c: Likewise. + * grub-core/commands/mips/loongson/lsspd.c: Likewise. + * grub-core/commands/setpci.c: Likewise. + * grub-core/loader/i386/bsd.c: Likewise. + * grub-core/loader/i386/linux.c: Likewise. + * util/getroot.c: Likewise. + * util/grub-editenv.c: Likewise. + * util/grub-fstest.c: Likewise. + * util/grub-mkfont.c: Likewise. + * util/grub-mkimage.c: Likewise. + * util/grub-mkpasswd-pbkdf2.c: Likewise. + * util/grub-pe2elf.c: Likewise. + * util/grub-probe.c: Likewise. + * util/grub-setup.c: Likewise. + * util/ieee1275/ofpath.c: Likewise. + * util/misc.c: Likewise. + * util/raid.c: Likewise. + +2011-11-11 Robert Millan + + * util/getroot.c (grub_util_get_geom_abstraction): Remove + __attribute__((unused)) from `os_dev', which *is* being used. + +2011-11-11 Vladimir Serbinenko + + * include/grub/dl.h (GRUB_ARCH_DL_TRAMP_SIZE) [__ia64__]: Add back + forgotten define. + (GRUB_ARCH_DL_GOT_ALIGN) [__ia64__]: Redefine in terms of + GRUB_IA64_DL_GOT_ALIGN. + (GRUB_ARCH_DL_TRAMP_ALIGN) [__ia64__]: Redefine in terms of + GRUB_IA64_DL_TRAMP_ALIGN. + +2011-11-11 Vladimir Serbinenko + + Replace grub_fatal with normal errors in i386 linux loader. + + * grub-core/loader/i386/linux.c (find_efi_mmap_size): Return 0 on error. + (allocate_pages): Check find_efi_mmap_size return value. + (grub_e820_add_region): Return error. + (grub_linux_boot): Check mmap return value. + +2011-11-11 Vladimir Serbinenko + + * grub-core/commands/acpihalt.c: Gettextized. + * grub-core/commands/cacheinfo.c: Likewise. + * grub-core/commands/cmp.c: Likewise. + * grub-core/commands/efi/loadbios.c: Likewise. + * grub-core/commands/gptsync.c: Likewise. + * grub-core/commands/ieee1275/suspend.c: Likewise. + * grub-core/commands/legacycfg.c: Likewise. + * grub-core/commands/memrw.c: Likewise. + * grub-core/commands/minicmd.c: Likewise. + * grub-core/commands/parttool.c: Likewise. + * grub-core/commands/time.c: Likewise. + * grub-core/commands/videoinfo.c: Likewise. + * grub-core/disk/geli.c: Likewise. + * grub-core/disk/i386/pc/biosdisk.c: Likewise. + * grub-core/disk/luks.c: Likewise. + * grub-core/disk/lvm.c: Likewise. + * grub-core/font/font_cmd.c: Likewise. + * grub-core/fs/zfs/zfscrypt.c: Likewise. + * grub-core/fs/zfs/zfsinfo.c: Likewise. + * grub-core/gfxmenu/view.c: Likewise. + * grub-core/kern/emu/hostdisk.c: Likewise. + * grub-core/kern/emu/main.c: Likewise. + * grub-core/kern/emu/misc.c: Likewise. + * grub-core/kern/emu/mm.c: Likewise. + * grub-core/kern/mips/arc/init.c: Likewise. + * grub-core/kern/mips/loongson/init.c: Likewise. + * grub-core/kern/partition.c: Likewise. + * grub-core/lib/i386/halt.c: Likewise. + * grub-core/lib/mips/arc/reboot.c: Likewise. + * grub-core/lib/mips/loongson/reboot.c: Likewise. + * grub-core/loader/i386/pc/chainloader.c: Likewise. + * grub-core/loader/i386/xnu.c: Likewise. + * grub-core/loader/multiboot.c: Likewise. + * grub-core/net/bootp.c: Likewise. + * grub-core/net/net.c: Likewise. + * grub-core/normal/term.c: Likewise. + * grub-core/partmap/bsdlabel.c: Likewise. + * grub-core/parttool/msdospart.c: Likewise. + * grub-core/term/gfxterm.c: Likewise. + * grub-core/term/terminfo.c: Likewise. + * grub-core/video/i386/pc/vbe.c: Likewise. + * util/grub-menulst2cfg.c: Likewise. + * util/grub-mkdevicemap.c: Likewise. + * util/grub-mklayout.c: Likewise. + * util/grub-mkrelpath.c: Likewise. + * util/grub-script-check.c: Likewise. + * util/ieee1275/grub-ofpathname.c: Likewise. + * util/resolve.c: Likewise. + +2011-11-11 Vladimir Serbinenko + + Support %1$d syntax. + + * tests/printf_unit_test.c: New file. + * Makefile.util.def (printf_test): New test. + * grub-core/kern/misc.c (grub_vsnprintf_real): Support %1$d syntax. + +2011-11-11 Vladimir Serbinenko + + * grub-core/hook/datehook.c (grub_read_hook_datetime): Small stylistic + fix. + +2011-11-11 Vladimir Serbinenko + + * grub-core/efiemu/mm.c (grub_efiemu_mmap_fill): Change printf into + dprintf. + * grub-core/font/font.c (grub_font_load): Likewise. + +2011-11-11 Vladimir Serbinenko + + * util/grub-macho2img.c: Add comment concerning gettext. + * grub-core/lib/legacy_parse.c: Likewise. + +2011-11-11 Vladimir Serbinenko + + * grub-core/kern/misc.c (grub_vprintf): Add missing va_end. + (grub_xvasprintf): Likewise. + +2011-11-11 Vladimir Serbinenko + + Add const keyword to grub_env_get and gettextize week days. + + * grub-core/hook/datehook.c (grub_datetime_names): Make const. + (grub_read_hook_datetime): Return const char *. + * grub-core/kern/env.c (grub_env_get): Return const char *. All users + updated. + * grub-core/normal/datetime.c (grub_weekday_names): Make const. + Mark for gettext. + (grub_get_weekday_name): Return const char *. Call gettext. + * grub-core/script/argv.c (grub_script_argv_append): Receive const + char * and len as the argument. All users updated. + (grub_script_argv_split_append): Receive const char *. + * include/grub/datetime.h (grub_get_weekday_name): Update proto. + * include/grub/env.h (grub_env_get): Likewise. + (grub_env_read_hook_t): Return const char *. + * include/grub/script_sh.h (grub_script_argv_append): Update proto. + (grub_script_argv_split_append): Likewise. + +2011-11-11 Vladimir Serbinenko + + * grub-core/normal/main.c (grub_normal_execute): Remove leftover call. + +2011-11-11 Vladimir Serbinenko + + * grub-core/kern/misc.c (grub_strstr): Moved from here ... + * include/grub/misc.h (grub_strstr): ... here. Make static and inline. + +2011-11-11 Vladimir Serbinenko + + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_set_property): + Fix prototype. + +2011-11-11 Vladimir Serbinenko + + Fix mips compilation. + + * grub-core/lib/xzembed/xz_dec_stream.c (xz_dec): Restrict hash_id to + normal decoder. + (hashes): Use in embed decoder as well (for sizes). + (dec_stream_header): Fix embed decompressor logic. + (dec_stream_footer): Likewise. + +2011-11-11 Vladimir Serbinenko + + * grub-core/kern/x86_64/dl.c (grub_arch_dl_relocate_symbols): Issue + an error and not a fatal on unrecognised relocation types. + +2011-11-11 Vladimir Serbinenko + + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args): + Issue error rather than printf on unknown arguments. + +2011-11-11 Vladimir Serbinenko + + * grub-core/kern/ieee1275/ieee1275.c (grub_ieee1275_set_property): + Make buf a const. + +2011-11-11 Vladimir Serbinenko + + * grub-core/fs/zfs/zfscrypt.c (GRUB_MOD_INIT), (GRUB_MOD_FINI): + Fix module name. + +2011-11-11 Vladimir Serbinenko + + * grub-core/fs/ntfs.c (grub_ntfs_read_symlink): Stylistic fix. Remove + leftover debug printf. + +2011-11-11 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_embed): Spelling fix. + +2011-11-11 Vladimir Serbinenko + + * grub-core/efiemu/main.c (grub_efiemu_register_configuration_table): + A stylistic fix. + +2011-11-11 Vladimir Serbinenko + + * grub-core/commands/probe.c (grub_cmd_probe): Fix error message. + +2011-11-10 Shea Levy + + Allow all modules to perform serial IO + + * grub-core/term-serial.c (grub_serial_find): Remove static qualifier + * include/grub/serial.h (grub_serial_port_configure): New inline + function. + (grub_serial_port_fetch): Likewise. + (grub_serial_port_put): Likewise. + (grub_serial_port_fini): Likewise. + (grub_serial_find): New proto. + +2011-11-10 Vladimir Serbinenko + + Put symlink at the end of the node and fix a potential + memory corruption. + + * grub-core/fs/iso9660.c (grub_fshelp_node): New field have_symlink. + Make symlink into an array. + (set_rockridge): Set have_symlink and alloc_dirents. + (grub_iso9660_read_symlink): Use new layout. + (grub_iso9660_iterate_dir): Fix memory corruption. + Use new layout. + (grub_iso9660_dir): Set have_symlink. + (grub_iso9660_open): Likewise. + +2011-11-10 Vladimir Serbinenko + + Remove local keyword. + + * util/grub-mkconfig_lib.in (version_test_numeric): Remove local. + (version_test_gt): Likewise. + (version_find_latest): Likewise. + (gettext_printf): Likewise. + * util/grub.d/10_windows.in (get_os_name_from_boot_ini): Likewise. + +2011-11-10 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (zfs_mount): Fix spurious warning. + +2011-11-10 Vladimir Serbinenko + + Fix ZFS memory and resource leaks. + + * grub-core/fs/zfs/zfs.c (fill_vdev_info_real): New paramter inserted. + All users updated. + Free type on exit. + (fill_vdev_info): New parameter inserted. All users updated. + (check_pool_label): Likewise. + (scan_disk): Likewise. + (scan_devices): Close non-inserted disks. + (fzap_iterate): Free l. + (unmount_device): Free children descripto memory. + +2011-11-10 Vladimir Serbinenko + + * grub-core/fs/iso9660.c (grub_iso9660_iterate_dir): Fix grub_strncat + argument (access out of bounds). + +2011-11-10 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_read_logical): Fix RAID10 logic for + >= 6 drives. + +2011-11-10 Vladimir Serbinenko + + * include/grub/i386/netbsd_bootinfo.h (grub_netbsd_btinfo_bootwedge): + Fix declaration. + +2011-11-09 Vladimir Serbinenko + + Fix several memory leaks. + + * grub-core/fs/btrfs.c (grub_btrfs_dir): Fix memory leak. + * grub-core/fs/cpio.c (grub_cpio_find_file): Likewise. + (grub_cpio_dir): Likewise. + * grub-core/fs/fat.c (grub_fat_label): Likewise. + * grub-core/fs/jfs.c (grub_jfs_label): Likewise. + * grub-core/fs/romfs.c (grub_romfs_close): Likewise. + (grub_romfs_label): Likewise. + * grub-core/fs/squash4.c (squash_mount): Use zalloc for safety. + (squash_unmount): New function. + (grub_squash_dir): Fix memory leak. + (grub_squash_open): Likewise. + (grub_squash_read): Likewise. + (grub_squash_mtime): Likewise. + * grub-core/fs/xfs.c (grub_xfs_open): Likewise. + * grub-core/fs/zfs/zfs.c (check_pool_label): Likewise. + * util/grub-fstest.c (fstest): Likewise. + +2011-11-09 Vladimir Serbinenko + + * include/grub/misc.h (grub_strncat): Fix the order of conditionals to + avoid accessing beyond the array. + +2011-11-09 Vladimir Serbinenko + + * configure.ac: Add missing -mXX to TARGET_CPPFLAGS. + +2011-11-09 Vladimir Serbinenko + + Several AFFS fixes. + + * grub-core/fs/affs.c (grub_affs_bblock): Replace flags with version. + (GRUB_AFFS_FLAG_FFS): Removed. + (GRUB_AFFS_SYMLINK_SIZE): Likewise. + (GRUB_AFFS_FILETYPE_DIR): Make positive and unsigned. + (GRUB_AFFS_FILETYPE_DIR), (GRUB_AFFS_FILETYPE_REG): Fix a mix-up. + (grub_fshelp_node): Make block 32-bit. + Add block_cache and last_block_cache. + (grub_affs_read_block): Fill and use block cache. + (grub_affs_read_file): Removed. + (grub_affs_mount): Zero-fill node. Fix version check. Don't reread + boot block. + (grub_affs_read_symlink): Fix symlink size. Add a \0 at the end for + safety. + (grub_affs_iterate_dir): Use more appropriate types. Zero-fill allocated + space. + (grub_affs_close): Free block cache. + (grub_affs_read): Use grub_fshelp_read_file directly. + +2011-11-08 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (read_dva): Issue an error if read failed + with no error set. + +2011-11-08 Vladimir Serbinenko + + * grub-core/lib/LzmaEnc.c (LzmaEnc_CodeOneBlock): Remove set but not + used variable. + * grub-core/kern/ia64/dl_helper.c (grub_ia64_dl_get_tramp_got_size): + Likewise. + +2011-11-08 Vladimir Serbinenko + + Fix potential problem with calling zfs_to_cpu and cpu_to_be in a row. + + * grub-core/fs/zfs/zfscrypt.c (grub_zfs_decrypt_real): Use explicit + byteswap when needed. + +2011-11-08 Vladimir Serbinenko + + Fix FreeBSD compilation. + + * grub-core/disk/geli.c (GRUB_MD_SHA256) [GRUB_UTIL]: Redefine in a way + to avoid circular dependency. + (GRUB_MD_SHA512) [GRUB_UTIL]: Likewise. + * util/getroot.c (grub_util_follow_gpart_up): Move from here... + * grub-core/kern/emu/hostdisk.c (+grub_util_follow_gpart_up): ... here. + +2011-11-08 Vladimir Serbinenko + + Fix ZFS crypto error types. + + * grub-core/fs/zfs/zfscrypt.c (grub_ccm_decrypt): Fix return type. + (grub_gcm_decrypt): Likewise. + (grub_zfs_load_key_real): Fix error code type. Handle possible error + from PBKDF2. + +2011-11-08 Vladimir Serbinenko + + Illumos support. + + * Makefile.util.def (10_illumos): New script. + * configure.ac: Set COND_HOST_ILLUMOS. + * grub-core/kern/emu/hostdisk.c (grub_util_get_fd_sectors) [__sun__]: + Support Illumos calls. + (find_partition_start) [__sun__]: Likewise. + (convert_system_partition_to_system_disk) [__sun__]: Likewise. + (device_is_wholedisk) [__sun__]: Handle Illumos naming scheme. + (grub_util_biosdisk_get_grub_dev) [__sun__]: Handle Illumos. + * util/getroot.c (find_root_device_from_libzfs) [__sun__]: Return raw + device. + * util/grub-probe.c (probe) [__sun__]: Do character check. + * util/grub.d/10_illumos.in: New file. + +2011-11-08 Vladimir Serbinenko + + Support escaped commas in hostdisk. + + * grub-core/kern/emu/hostdisk.c (unescape_cmp): New function. + (find_grub_drive): Use unescape_cmp. + (make_device_name): Escape commas. + +2011-11-08 Vladimir Serbinenko + + * util/grub.d/10_kfreebsd.in: Use ${grub_mkrelpath} not grub-mkrelpath. + +2011-11-08 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (zap_iterate): Remove set but not used + variable. + +2011-11-08 Vladimir Serbinenko + + Support trampoline jumps on powerpc. + + * grub-core/kern/dl.c (grub_dl_load_segments) [__powerpc__]: Follow + __ia64__ path. + (grub_dl_load_segments): Set mod->sz. + (grub_dl_flush_cache): Flush whole space occupied by module, not just + segments. + * grub-core/kern/ia64/dl.c (nopm): Make const while on it. + (jump): Likewise. + * grub-core/kern/powerpc/dl.c (grub_arch_dl_get_tramp_got_size): New + function. + (trampoline): New struct. + (trampoline_template): New const. + (grub_arch_dl_relocate_symbols): Create trampolines on overflow. + * include/grub/dl.h (grub_dl): Add sz element. + [__powerpc__]: Follow __ia64__. + (GRUB_ARCH_DL_TRAMP_ALIGN): Define on ppc. + (GRUB_ARCH_DL_GOT_ALIGN): Likewise. + (GRUB_ARCH_DL_TRAMP_SIZE): Likewise. + (grub_arch_dl_get_tramp_got_size) [__powerpc__]: New proto. + +2011-11-06 Vladimir Serbinenko + + ZFS crypto support. + + * Makefile.util.def (libgrubmods): Add grub-core/fs/zfs/zfscrypt.c. + * grub-core/Makefile.core.def (zfscrypt): New module. + * grub-core/fs/zfs/zfs.c (subvolume): New structure. + (grub_zfs_data): Replace mdn with subvol. Put case_insensitivity inside + it. All users updated. + (grub_zfs_decrypt): New var. + (grub_zfs_load_key): Likewise. + (zio_checksum_functions): Add SHA256+MAC. + (zio_checksum_verify): Handle incomplete comparison due to MAC. + (zio_read): Handle encrypted blocks. + (zap_verify): Remove incorrect check. + (fzap_iterate): Handle non-standard fzap. + (zap_iterate): Likewise. + (zap_iterate_u64): New function. + (dnode_get_fullpath): Load keys. + * grub-core/fs/zfs/zfscrypt.c: New file. + * grub-core/lib/crypto.c (grub_crypto_cipher_close): Removed. + (grub_crypto_ecb_encrypt): Make input const. + * include/grub/crypto.h (grub_crypto_cipher_close): Inline. + (grub_crypto_ecb_encrypt): Make input const. + (GRUB_CIPHER_AES): New macro. + * include/grub/zfs/dmu.h (dmu_object_type): Add DMU_OT_DSL_KEYCHAIN. + * include/grub/zfs/dsl_dir.h (dsl_dir_phys): Add keychain. + * include/grub/zfs/spa.h (grub_zfs_endian): Moved from here ... + * include/grub/zfs/zfs.h (grub_zfs_endian): ... here. Added GURB_ZFS_ + prefix. All users updated. + (grub_zfs_add_key): New proto. + (grub_zfs_decrypt): Likewise. + (grub_zfs_load_key): Likewise. + * include/grub/zfs/zio.h (zio_checksum): Add SHA256+MAC. + * util/grub-fstest.c (options): Add -K option. + (argp_parser): Likewise. + +2011-11-05 Vladimir Serbinenko + + Support zle compression on ZFS. + + * grub-core/fs/zfs/zfs.c (zle_decompress): New function. + (decomp_table): Add zle. + * include/grub/zfs/zio.h (zio_compress): Add zle. + +2011-11-05 Vladimir Serbinenko + + Support BtrFS embedding. + + * grub-core/fs/btrfs.c (grub_btrfs_embed) [GRUB_UTIL]: New function. + (grub_btrfs_fs) [GRUB_UTIL]: Set embed. + * include/grub/fs.h (grub_fs) [GRUB_UTIL]: New field embed. + * util/grub-setup.c (setup): Use fs embedding if available. + Add additional sanity check. + +2011-11-05 Vladimir Serbinenko + + * util/grub-install.in: Fix condition for config_opt. + +2011-11-04 Vladimir Serbinenko + + Support third redundancy strip on raidz3. + + * grub-core/fs/zfs/zfs.c (recovery): Add Gauss for general case. + Return error on singularity. All users updated. + (read_device): Don't stop on 3rd failure on raidz3. + +2011-11-04 Vladimir Serbinenko + + Support case-insensitive ZFS subvolumes. + + * grub-core/fs/zfs/zfs.c (mzap_lookup): New parameter case_insensitive. + All users updated. + (zap_hash): Likewise. + (name_cmp): New function. + (zap_leaf_array_equal): New parameter case_insensitive. + All users updated. + (zap_leaf_lookup): Likewise. + (fzap_lookup): Likewise. + (zap_lookup): Likewise. + (dnode_get_path): New parameter case_insensitive. Retrieve case + sensitiviness of a volume. All users updated. + (dnode_get_fullpath): New parameter case_insensitive. + All users updated. + (grub_zfs_dir): Set info.case_insensitiveness. + +2011-11-04 Vladimir Serbinenko + + Support second redundancy strip on raidz(2,3). + + * grub-core/fs/zfs/zfs.c (powx): New array. + (powx_inv): Likewise. + (poly): New const. + (xor_out): New function. + (gf_mul): Likewise. + (recovery): Likewise. + (read_device): Use second redundancy strip. + +2011-11-04 Vladimir Serbinenko + + Use a power of generator representation of GF(256) multiplication group + to save space time and complexity. + + * grub-core/disk/raid6_recover.c (raid6_table1): Removed. + (raid6_table2): Likewise. + (powx): New array. + (powx_inv): Likewise. + (poly): New const. + (grub_raid_block_mul): Replace with ... + (grub_raid_block_mulx): ...this. + (grub_raid6_init_table): Rewritten. + (grub_raid6_recover): Use power of generator representation. + +2011-11-04 Vladimir Serbinenko + + * grub-core/disk/raid6_recover.c (grub_raid6_recover): Get start_sector + for the right device. + +2011-11-04 Vladimir Serbinenko + + * include/grub/kernel.h (grub_module_header): Make type into uint32 as + expected by grub-mkimage and it's more clear since there is no implicit + padding. + +2011-11-04 Vladimir Serbinenko + + * grub-core/disk/raid.c (scan_devices): Don't derference NULL on whole + disk. + * grub-core/disk/lvm.c (do_lvm_scan): Likewise. + +2011-11-03 Philipp Matthias Hahn + + * util/grub-mkrescue.in: Fix handling xorriso option. + +2011-11-03 Vladimir Serbinenko + + * grub-core/gettext/gettext.c (grub_gettext_init_ext): Exit if local is + NULL. + +2011-11-03 crocket + + * util/grub.d/10_linux.in: Add Slackware initrd naming. + +2011-11-03 Vladimir Serbinenko + + XZ CRC64 and SHA256 support. + + * Makefile.util.def (libgrubmods): Add crc64.c. + * grub-core/Makefile.core.def (crc64): New module. + * grub-core/lib/crc64.c: New file. + * grub-core/lib/xzembed/xz_dec_stream.c (xz_dec_hash) + [!GRUB_EMBED_DECOMPRESSOR]: Rename crc32_context to hash_context. + Fix the type. + (MAX_HASH_SIZE): New define. + (xz_dec) [!GRUB_EMBED_DECOMPRESSOR]: Add generic hash fields. + (dec_block) [!GRUB_EMBED_DECOMPRESSOR]: Handle non-crc32 hashes. + (index_update) [!GRUB_EMBED_DECOMPRESSOR]: Likewise. + (dec_index) [!GRUB_EMBED_DECOMPRESSOR]: Likewise. + (crc32_validate) [!GRUB_EMBED_DECOMPRESSOR]: Rename to ... + (hash_validate) [!GRUB_EMBED_DECOMPRESSOR]: ... this. + Handle non-crc32 hashes. + (hashes) [!GRUB_EMBED_DECOMPRESSOR]: New variable. + (dec_stream_header): Handle non-crc32 hashes. + (dec_stream_footer): Likewise. + (dec_block_header): Likewise. + (dec_main): Likewise. + (xz_dec_init): Likewise. + (xz_dec_reset): Likewise. + (xz_dec_end): Likewise. + * util/import_gcry.py: Add CRC64 line. + +2011-11-03 Vladimir Serbinenko + + * grub-core/fs/ufs.c (grub_ufs_mtime) [MODE_UFS2]: Check mtime field + as well. + +2011-11-03 Vladimir Serbinenko + + Make reiserfs label retrieval similar to other *_label functions. + + * grub-core/fs/reiserfs.c (grub_reiserfs_superblock): New field label. + (REISERFS_MAX_LABEL_LENGTH): Removed. + (REISERFS_LABEL_OFFSET): Likewise. + (grub_reiserfs_label): Rewritten. + +2011-11-03 Vladimir Serbinenko + + * grub-core/fs/nilfs2.c (grub_nilfs2_mtime): Use correct superblock + field. + +2011-11-03 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (read_device): Support raidz3. + +2011-11-02 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (read_device): Add ability to sustain a single + drive failure on both raidz and raidz2. + +2011-11-02 Vladimir Serbinenko + + Fix RAIDZ(2) for >= 5 devices. + + * grub-core/fs/zfs/zfs.c (read_device): Fix length formula. Remove + asize argument. All users updated. + +2011-11-01 Vladimir Serbinenko + + Fix RAIDZ(2). + + * grub-core/fs/zfs/zfs.c (grub_zfs_device_desc): New member ashift. + (fill_vdev_info_real): Set ashift. + (read_device): Rewrite RAIDZ part based on reverse engineering. + +2011-10-31 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_extent_read): Add sanity check and + don't report potentially unavialiable fields in debug output. + (find_path): Fix double-free and memory leak. + +2011-10-31 Vladimir Serbinenko + + Read label on UFS1. + + * grub-core/fs/ufs.c (grub_ufs_label): Remove MODE_UFS2 condition. + (grub_ufs_fs): Always set .label. + +2011-10-31 Vladimir Serbinenko + + Use shifts in UFS. + + * grub-core/fs/ufs.c (UFS_LOG_BLKSZ): New macro. + (grub_ufs_data): New field log2_blksz. + (grub_ufs_read_file): Use shifts. + (grub_ufs_mount): Check block size and logarithm it. + +2011-10-31 Vladimir Serbinenko + + * grub-core/fs/ufs.c (grub_ufs_lookup_symlink): Fix handling of + long symlinks. + +2011-10-30 Vladimir Serbinenko + + Handle symlinks and long names on tar and cpio. + + * grub-core/fs/cpio.c (ATTR_TYPE): New definition. + (ATTR_FILE): Likewise. + (ATTR_DIR): Likewise. + (ATTR_LNK): Likewise. + (grub_cpio_data) [MODE_USTAR]: New fields linkname and linkname_alloc. + (grub_cpio_find_file): Fill mode, handle linkname field as well as + L and K entries. + (grub_cpio_mount): Zero-fill data. + (handle_symlink): New function. + (grub_cpio_dir): Handle symlinks. + (grub_cpio_open): Likewise. + (grub_cpio_close) [MODE_USTAR]: Free linkname. + +2011-10-30 Vladimir Serbinenko + + Fix iso9660 filename limitations and fix memory leaks. + + * grub-core/fs/iso9660.c (set_rockridge): Free sua at the end. + (grub_iso9660_iterate_dir): Fix slash handling in symlinks. + +2011-10-30 Vladimir Serbinenko + + Fix JFS file name length limitations. + + * grub-core/fs/jfs.c (grub_jfs_inode): Fix in-place symlink length. + (grub_jfs_diropen): Fix maximum filename length. + (grub_jfs_getent): Fix filename length. + (grub_jfs_lookup_symlink): Fix size checks. + +2011-10-30 Vladimir Serbinenko + + * grub-core/loader/mips/linux.c (loongson_machtypes): Fix fuloong type + string. + +2011-10-30 Vladimir Serbinenko + + Leverage BFS implementation to read AFS. + + * Makefile.util.def (libgrubmods): Add afs.c. + * grub-core/Makefile.core.def (afs): New module + * grub-core/fs/afs.c: New file. + * grub-core/fs/bfs.c [MODE_AFS]: Adapt for AFS. + +2011-10-30 Vladimir Serbinenko + + * grub-core/fs/bfs.c: Macroify and add some necessary sanity checks. + +2011-10-30 Vladimir Serbinenko + + * grub-core/fs/bfs.c: Run indent. + +2011-10-30 Vladimir Serbinenko + + BFS implementation based on the specification. + + * grub-core/fs/bfs.c: New file. + * Makefile.util.def (libgrubmods): Add bfs.c. + * grub-core/Makefile.core.def (bfs): New module. + +2011-10-30 Vladimir Serbinenko + + * util/grub-fstest.c (cmd_cp): Clarify error message. + (cmd_cmp): Likewise. + +2011-10-30 Yves Blusseau + + * po/POTFILES.in: Regenerate because of the removal of afs, afs_be, befs + and befs_be. + +2011-10-29 Vladimir Serbinenko + + Remove afs and befs because of copyright problem. + + * grub-core/fs/afs.c: Removed. + * grub-core/fs/afs_be.c: Removed. + * grub-core/fs/befs.c: Removed. + * grub-core/fs/befs_be.c: Removed. + * Makefile.util.def (libgrubkern): Remove afs, afs_be, befs and befs_be. + * grub-core/Makefile.core.def (afs): Removed. + (afs_be): Likewise. + (befs): Likewise. + (befs_be): Likewise. + +2011-10-28 Vladimir Serbinenko + + Prefer rockridge over Joliet. + + * grub-core/fs/iso9660.c (grub_iso9660_mount): Move rockridge detection + to ... + (set_rockridge): ... here. + (grub_iso9660_mount): Check rockridge on the primary label when + discovering. Ignore Joliet if Rockridge is present. + +2011-10-28 Vladimir Serbinenko + + Use shifts in nilfs2. + + * grub-core/fs/nilfs2.c (LOG_INODE_SIZE): New definition. + (LOG_NILFS_DAT_ENTRY_SIZE): Likewise. + (grub_nilfs2_palloc_entries_per_group): Replace with ... + (grub_nilfs2_log_palloc_entries_per_group): ... this. + (grub_nilfs2_palloc_group): Use shifts and bitmasks. + (grub_nilfs2_entries_per_block): Replaced with ... + (grub_nilfs2_log_entries_per_block_log): ... this. + (grub_nilfs2_blocks_per_group): Replaced with ... + (grub_nilfs2_blocks_per_group_log): ... this. + (grub_nilfs2_blocks_per_desc_block): Replaced with ... + (grub_nilfs2_blocks_per_desc_block_log): ... this. + (grub_nilfs2_palloc_desc_block_offset): Replaced with ... + (grub_nilfs2_palloc_desc_block_offset_log): ... this. + (grub_nilfs2_palloc_entry_offset): Replaced ... + (grub_nilfs2_palloc_entry_offset_log): ... this. Use shifts. + (grub_nilfs2_dat_translate): Use shifts. + (grub_nilfs2_read_inode): Likewise. + (GRUB_MOD_INIT): Ensure that logs are correct. + +2011-10-28 Vladimir Serbinenko + + Use shifts in minix filesystem. + + * grub-core/fs/minix.c (GRUB_MINIX_ZONESZ): Use log_block_size. + (GRUB_MINIX_ZONE2SECT): Likewise. + (grub_minix_data): Replace block_size with log_block_size. + (grub_minix_read_file): Use shifts. + (grub_minix_mount): Check block size and take a logarithm. + +2011-10-28 Vladimir Serbinenko + + Use shifts in squash4. + + * grub-core/fs/squash4.c (grub_squash_data): New field log2_blksz. + (squash_mount): Check block size and take logarithm. + (direct_read): Use shifts. + +2011-10-28 Vladimir Serbinenko + + Correct befs block counting logic. + + * grub-core/fs/afs.c (GRUB_AFS_BLOCKS_PER_DI_RUN): Replaced with... + (GRUB_AFS_LOG_BLOCKS_PER_DI_RUN): ... this. + (GRUB_AFS_BLOCKRUN_LOG_SIZE): New definition. + (grub_afs_read_inode): Use block_shift. + (RANGE_SHIFT): New definition. + (grub_afs_read_block): Account for RANGE_SHIFT, emit errors on + unexpected conditions, use shifts and appropriate types. + (GRUB_MOD_INIT): Check the value of GRUB_AFS_BLOCKRUN_LOG_SIZE. + +2011-10-28 Vladimir Serbinenko + + * grub-core/disk/raid.c (scan_devices): Check partition. + * grub-core/disk/lvm.c (do_lvm_scan): Likewise. + +2011-10-27 Vladimir Serbinenko + + Support BFS (befs) UUID. + + * grub-core/fs/afs.c (grub_afs_inode): Make small_data zero-size. + (grub_afs_small_data_element_header): New struct. + (grub_afs_read_inode): Read complete inode. Fix ino type while on it. + (grub_afs_read_attribute) [MODE_BFS]: New function. + (grub_afs_iterate_dir): Allocate for complete inode. + (grub_afs_mount): Likewise. + (grub_afs_uuid) [MODE_BFS]: New function. + (grub_afs_fs) [MODE_BFS]: Add .uuid. + +2011-10-27 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (read_device): Silence spurious warning. + (zfs_unmount): Fix memory leak. + +2011-10-26 Vladimir Serbinenko + + Support NTFS reparse points. + + * grub-core/fs/ntfs.c (list_file): Set symlink type when appropriate. + (symlink_descriptor): New struct. + (grub_ntfs_read_symlink): New function. + (grub_ntfs_iterate_dir): Use grub_ntfs_read_symlink. + (grub_ntfs_open): Likewise. + +2011-10-26 Vladimir Serbinenko + + * include/grub/ntfs.h: Add GRUB_NTFS_ prefix. All users updated. + +2011-10-26 Vladimir Serbinenko + + fstest xnu_uuid subcommand. + + * grub-core/commands/xnu_uuid.c (libgrubkrn): Add + grub-core/commands/xnu_uuid.c. + * util/grub-fstest.c (CMD_XNU_UUID): New enum value. + (fstest): Handle xnu_uuid. + (options): Document xnu_uuid. + (argp_parser): Parse xnu_uuid. + +2011-10-26 Vladimir Serbinenko + + * grub-core/commands/xnu_uuid.c (grub_cmd_xnu_uuid): Support + -l argument. Add newline at the end if printing. + (GRUB_MOD_INIT): Document -l. + +2011-10-26 Vladimir Serbinenko + + * grub-core/fs/nilfs2.c (grub_nilfs2_uuid): Add missing field length. + +2011-10-26 Vladimir Serbinenko + + ZFS multi-device and version 33 support. + + * Makefile.util.def (libgrubkern): Add grub-core/fs/zfs/zfsinfo.c. + * grub-core/fs/zfs/zfs.c (grub_zfs_device_desc): New struct. + (grub_zfs_data): Add multidev-ice-related fields. + (zio_checksum_verify): Zero-pad printed values. Print checksum name. + (dva_get_offset): Make dva const. + (zfs_fetch_nvlist): New function. + (fill_vdev_info_real): Likewise. + (fill_vdev_info): Likewise. + (check_pool_label): Likewise. + (scan_disk): Likewise. + (scan_devices): Likewise. + (read_device): Likewise. + (read_dva): Likewise. + (zio_read_gang): Use read_dva. + (zio_read_data): Likewise. + (zap_leaf_lookup): Add missing endian conversion. + (zap_verify): Add missing endian conversion. All users updated. + (fzap_lookup): Likewise. + (fzap_iterate): Likewise. + (dnode_get_path): Handle SA bonus. + (nvlist_find_value): Make input const. All users updated. + (unmount_device): New function. + (zfs_unmount): Use unmount_device. + (zfs_mount): Use scan_disk. + (zfs_mtime): New function. + (grub_zfs_open): Handle system attributes. + (fill_fs_info): Likewise. + (grub_zfs_dir): Likewise. + (grub_zfs_fs): Add mtime. + * grub-core/fs/zfs/zfsinfo.c (print_vdev_info): Add missing return. + * include/grub/zfs/sa_impl.h (SA_TYPE_OFFSET): New definition. + (SA_MTIME_OFFSET): Likewise. + (SA_SYMLINK_OFFSET): Likewise. + * include/grub/zfs/zfs.h (SPA_VERSION): Increase to 33. + * util/grub-fstest.c (CMD_ZFSINFO): New enum value. + (fstest): Support zfsinfo. + (argp_parser): Likewise. + +2011-10-26 Vladimir Serbinenko + + * include/grub/datetime.h (grub_datetime2unixtime): Fix off-by-one + error. + +2011-10-26 Vladimir Serbinenko + + ZFS fixes. + + * grub-core/fs/zfs/zfs.c (fzap_iterate): Fix handling of indexes + sharing the same block. Iterate over correct number of indices. + (dnode_get_path): Handle symlinks correctly. + +2011-10-25 Vladimir Serbinenko + + * grub-core/fs/jfs.c (grub_jfs_sblock): Fix offset to volname. + +2011-10-25 Vladimir Serbinenko + + Read label on HFS+. + + * grub-core/fs/hfsplus.c (grub_hfsplus_cmp_catkey_id): New function. + (grub_hfsplus_btree_search): Fix types. + (grub_hfsplus_label): Implement. + +2011-10-25 Vladimir Serbinenko + + * grub-core/fs/ntfs.c (grub_ntfs_uuid): Fix a memory leak. + +2011-10-25 Vladimir Serbinenko + + * grub-core/fs/fat.c (grub_fat_uuid): Make uppercase to match Linux. + +2011-10-25 Vladimir Serbinenko + + Fix symlink handling on iso9660. + + * grub-core/fs/iso9660.c (grub_fshelp_node): Remove dir_off. Add symlink + All users updated. + (grub_iso9660_susp_iterate): Accept zero-size iterate. + (grub_iso9660_read_symlink): Moved most of code ... + (grub_iso9660_iterate_dir): ... here. Fill node->symlink. + +2011-10-25 Vladimir Serbinenko + + * grub-core/loader/i386/bsd.c (grub_netbsd_add_boot_disk_and_wedge): + Use union to avoid breaking strict-aliasing rules. + +2011-10-25 Vladimir Serbinenko + + Support multi-extent iso files. + + * grub-core/fs/iso9660.c (grub_iso9660_data): Remove first_sector. + Add node. + (grub_fshelp_node): Revamp. All users updated. + (FLAG_*): New enum. + (read_node): New function. + (grub_iso9660_susp_iterate): Use read_node. Receive a node as argument. + All users updated. + (grub_iso9660_mount): Don't attempt to read sua when there is none. + (get_node_size): New function. + (grub_iso9660_iterate_dir): Use read_node. Agglomerate multi-extent + entries. + Fix memory leak on . and .. + (grub_iso9660_read): Use read_node. + (grub_iso9660_close): Free node. + +2011-10-25 Vladimir Serbinenko + + Fix tar 4G limit and handle paths containing dot. + + * grub-core/fs/cpio.c (grub_cpio_data): Use grub_off_t for offsets. + (canonicalize): New function. + (grub_cpio_find_file): Use canonicalize. Store offs in + grub_disk_addr_t. + (grub_cpio_dir): Use grub_disk_addr_t. + (grub_cpio_open): Likewise. + +2011-10-25 Vladimir Serbinenko + + Fix handling of uncompressed blocks on squashfs and break 4G limit. + + * grub-core/fs/squash4.c (grub_squash_super): Add block_size. Remove + unused flags. + (grub_squash_inode): Add long_file and block_size. + (grub_squash_cache_inode): New struct. + (grub_squash_dirent): Make types into enum. + (SQUASH_TYPE_LONG_REGULAR): New type. + (grub_squash_frag_desc): Add field size. + (SQUASH_BLOCK_FLAGS): New enum. + (grub_squash_data): Use grub_squash_cache_inode. + (grub_fshelp_node): Make ino_chunk 64-bit. + (read_chunk): Minor argument change. All users updated. + (squash_mount): Use correct le_to_cpu. + (grub_squash_open): Handle LONG_REGULAR. + (direct_read): New function. + (grub_squash_read_data): Handle blocks correctly. + +2011-10-25 Vladimir Serbinenko + + * grub-core/kern/disk.c (grub_disk_read_small): Fix memory leak. + +2011-10-25 Vladimir Serbinenko + + * grub-core/fs/romfs.c (grub_romfs_open): Add missing return. + +2011-10-24 Vladimir Serbinenko + + Fix 2G limit on ZFS. + + * grub-core/fs/zfs/zfs.c (zio_checksum_verify): Use more appropriate + types. + (uberblock_verify): Likewise. + (dmu_read): Likewise. + (grub_zfs_read): Likewise. Remove invalid cast. + +2011-10-24 Vladimir Serbinenko + + * grub-core/fs/jfs.c (grub_jfs_blkno): Use more appropriate types. + (grub_jfs_blkno): Fix incorrect shift. + (grub_jfs_read_file): Use more appropriate types. + +2011-10-24 Vladimir Serbinenko + + Support triple indirect on minix2 and minix3. + + * grub-core/fs/minix.c (grub_minix_inode) [MODE_MINIX2 || MODE_MINIX3]: + Declare triple_indir_zone. + (grub_minix_get_file_block) [MODE_MINIX2 || MODE_MINIX3]: Handle triple + indirect. + +2011-10-24 Vladimir Serbinenko + + Minix FS fixes. + + * grub-core/fs/minix.c (GRUB_MINIX_INODE_SIZE): Size is always 32-bit. + (grub_minix_inode) [!MODE_MINIX2 && !MODE_MINIX3]: Make size 32-bit. + Rename ctime to mtime. All users updated. + (grub_minix_get_file_block): Fix types and double indirect computations. + +2011-10-23 Vladimir Serbinenko + + * grub-core/fs/fat.c (grub_fat_label) [MODE_EXFAT]: Set *label to 0 + if no label is found. + (grub_fat_iterate_dir): Fix file size type. + (grub_fat_iterate_dir): Likewise. + +2011-10-23 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (gf_invert): Declare as const and + save some space. + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_RAW_SIZE): Decrease. + (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): Likewise. + +2011-10-23 Vladimir Serbinenko + + * util/import_gcry.py: Automatically fix camellia.c and camellia.h. + +2011-10-23 Vladimir Serbinenko + + * util/import_gcry.py: Accept space between # and include. + +2011-10-23 Vladimir Serbinenko + + * grub-core/lib/setjmp.S [__ia64__]: Include ./ia64/longjmp.S. + +2011-10-23 Vladimir Serbinenko + + Fine grainely disable warnings on lexer. Remove Wno-error on it. + + * grub-core/Makefile.core.def (normal): Remove -Wno-error. + * grub-core/script/lexer.c: Declare yytext_ptr to avoid having + yylex_strncpy. + * grub-core/script/yylex.l: Add fine-grained #pragma. + +2011-10-23 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/string.h (memcpy) [GRUB_UTIL]: + New inline function. + * grub-core/lib/libgcrypt_wrap/cipher_wrap.h (memcpy) [GRUB_UTIL]: + Likewise. + (memset) [GRUB_UTIL]: Likewise. + (memcmp) [GRUB_UTIL]: Likewise. + +2011-10-23 Vladimir Serbinenko + + * include/grub/misc.h (grub_memcpy): Declare grub_memcpy with static + inline function rather than a define. + +2011-10-23 Vladimir Serbinenko + + * util/grub-setup.c: Add missing include. + +2011-10-23 Vladimir Serbinenko + + * util/ieee1275/grub-ofpathname.c: Add missing include. + +2011-10-23 Vladimir Serbinenko + + * grub-core/kern/i386/pc/startup.S (grub_exit): Add missing zeroing-out. + * grub-core/lib/i386/reboot_trampoline.S (grub_reboot_start): + Likewise. + +2011-10-23 Vladimir Serbinenko + + * grub-core/io/lzopio.c (test_header): Fix incorrect memcmp instead of + grub_memcmp usage. + +2011-10-23 Vladimir Serbinenko + + * util/grub-install.in: Add datarootdir as per automake manual + suggestion. + * util/grub-mknetdir.in: Likewise. + +2011-10-23 Vladimir Serbinenko + + * util/grub.d/10_hurd.in: Add datarootdir as per automake manual + suggestion. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub.d/10_netbsd.in: Likewise. + * util/grub.d/10_windows.in: Likewise. + * util/grub.d/20_linux_xen.in: Likewise. + +2011-10-20 Vladimir Serbinenko + + Remove redundant grub_kernel_image_size. + + * grub-core/kern/i386/coreboot/init.c (grub_machine_init): Use + _edata and _start. + * grub-core/kern/i386/coreboot/startup.S: Move multiboot header after + the small code. It moves it only by few bytes but simplifies the code. + * grub-core/kern/i386/pc/init.c (grub_machine_init): Use _edata and + _start. + * grub-core/kern/i386/pc/startup.S: Use _edata and _start. + (grub_kernel_image_size): Removed. + * grub-core/kern/i386/qemu/startup.S: Use _edata and _start. + (grub_kernel_image_size): Removed. + [APPLE_CC]: Remove apple compiler support. i386-qemu port can't be + compiled with Apple toolchain. + * grub-core/kern/sparc64/ieee1275/crt0.S: Remove leftover fields. + * include/grub/i386/pc/kernel.h (grub_kernel_image_size): Removed. + * include/grub/i386/qemu/kernel.h (grub_kernel_image_size): Removed. + (grub_total_module_size): Likewise. + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE): + Removed. + (GRUB_KERNEL_I386_PC_COMPRESSED_SIZE): Put it lower. + (GRUB_KERNEL_I386_PC_INSTALL_DOS_PART): Likewise. + (GRUB_KERNEL_I386_PC_INSTALL_BSD_PART): Likewise. + (GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY): Likewise. + (GRUB_KERNEL_I386_QEMU_KERNEL_IMAGE_SIZE): Removed. + (GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE): Likewise. + (GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE): Likewise. + * include/grub/sparc64/ieee1275/kernel.h (grub_kernel_image_size): + Removed. + (grub_total_module_size): Removed. + * util/grub-mkimage.c (image_target_desc): Remove image_size. + (image_targets): Likewise. + Set .compressed_size to no field on sparc. + (generate_image): Remove kernel_image_size handling. + +2011-10-19 Szymon Janc + + * grub-core/bus/usb/uhci.c (grub_uhci_setup_transfer): Fix possible + NULL pointer dereference. + +2011-10-19 Vladimir Serbinenko + + Removed unused GRUB_BOOT_VERSION. Check for kernel version is better + done with a dedicated section. + + * grub-core/boot/sparc64/ieee1275/boot.S: Remove GRUB_BOOT_VERSION. + Ensure the correct position of boot_path. + * grub-core/kern/i386/efi/startup.S: Remove GRUB_BOOT_VERSION. + * grub-core/kern/i386/pc/startup.S: Likewise. Ensure correct position of + other fields. + * grub-core/kern/x86_64/efi/startup.S: Remove GRUB_BOOT_VERSION. + * include/grub/boot.h: Removed. All references removed. + * include/grub/sparc64/ieee1275/boot.h (GRUB_BOOT_MACHINE_VER_MAJ): + Removed. + (GRUB_BOOT_MACHINE_BOOT_DEVPATH): Make it lower. + +2011-10-19 Vladimir Serbinenko + + * util/grub-install.in: Declare IEEE1275 as able to find out the disk + name. + +2011-10-19 Vladimir Serbinenko + + * grub-core/kern/main.c (grub_set_prefix_and_root): Init prefix. + +2011-10-19 Vladimir Serbinenko + + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_encode_devname): + Don't add the bogus brackets. + +2011-10-19 Vladimir Serbinenko + + ExFAT support. + + * Makefile.util.def (libgrubmods.a): Add grub-core/fs/exfat.c. + * grub-core/Makefile.core.def (exfat): New module. + * grub-core/fs/exfat.c: New file. + * grub-core/fs/fat.c (GRUB_FAT_DIR_ENTRY_SIZE): Removed. + (GRUB_FAT_ATTR_*): Make into an enum. + (GRUB_FAT_ATTR_LONG_NAME) [MODE_EXFAT]: Removed. + (GRUB_FAT_ATTR_VALID) [MODE_EXFAT]: Remove GRUB_FAT_ATTR_VOLUME_ID. + (GRUB_FAT_ATTR_VOLUME_ID) [MODE_EXFAT]: Removed. + (GRUB_FAT_MAXFILE): Removed. + (grub_exfat_bpb) [MODE_EXFAT]: New struct. + (grub_current_fat_bpb_t): New type. + (grub_fat_dir_entry) [MODE_EXFAT]: New struct. + (grub_fat_dir_node) [MODE_EXFAT]: New struct. + (grub_fat_dir_node_t): New type. + (grub_fat_data) [MODE_EXFAT]: Remove root_sector and num_root_sectors. + (fat_log2) [MODE_EXFAT]: Removed. + (grub_fat_mount): Use grub_current_fat_bpb_t. Add some sanity checks. + (grub_fat_mount) [MODE_EXFAT]: Handle ExFAT. + (grub_fat_iterate_dir) [MODE_EXFAT]: New function. + (grub_fat_find_dir) [MODE_EXFAT]: Handle ExFAT. + (grub_fat_label) [MODE_EXFAT]: New function. + (grub_fat_fs) [MODE_EXFAT]: Set name to "exfat" and + reserved_first_sector to 0. + +2011-10-19 Vladimir Serbinenko + + Move grub_reboot out of the kernel. + + * grub-core/Makefile.core.def (reboot): Add platform-specific files. + * grub-core/kern/efi/efi.c (grub_reboot): Moved to ... + * grub-core/lib/efi/reboot.c: ... here. + * grub-core/kern/i386/efi/startup.S: Remove including of realmode.S. + * grub-core/kern/i386/ieee1275/startup.S: Likewise. + * grub-core/kern/i386/pc/startup.S (grub_exit): Inline cold_reboot. + * grub-core/kern/i386/realmode.S (grub_reboot): Moved to... + * grub-core/lib/i386/reboot_trampoline.S: ... here. + * grub-core/kern/ieee1275/openfw.c (grub_reboot): Moved to... + * grub-core/lib/ieee1275/reboot.c: ... here. + * grub-core/kern/mips/arc/init.c (grub_reboot): Moved to... + * grub-core/lib/mips/arc/reboot.c: ... here. + * grub-core/kern/mips/loongson/init.c (grub_reboot): Moved to... + * grub-core/lib/mips/loongson/reboot.c: ...here. + * grub-core/kern/mips/qemu_mips/init.c (grub_reboot): Moved to... + * grub-core/lib/mips/qemu_mips/reboot.c: ... here. + * include/grub/emu/misc.h (grub_reboot): New function declaration. + * include/grub/i386/reboot.h: New file. + * include/grub/mips/loongson/ec.h: Fix includes. + * include/grub/mips/qemu_mips/kernel.h (grub_reboot): Removed. + * include/grub/misc.h (grub_reboot): Don't mark as kernel function. + * grub-core/lib/i386/reboot.c: New file. + +2011-10-18 Vladimir Serbinenko + + Make grub_prefix into module to fix the arbitrary limit and save + some space. + + * grub-core/kern/emu/main.c (grub_prefix): Removed. + * grub-core/kern/i386/coreboot/startup.S (grub_prefix): Likewise. + * grub-core/kern/i386/efi/startup.S (grub_prefix): Likewise. + * grub-core/kern/i386/ieee1275/startup.S (grub_prefix): Likewise. + * grub-core/kern/i386/pc/startup.S (grub_prefix): Likewise. + * grub-core/kern/i386/qemu/startup.S (grub_prefix): Likewise. + * grub-core/kern/ia64/efi/startup.S (grub_prefix): Likewise. + * grub-core/kern/mips/startup.S (grub_prefix): Likewise. + * grub-core/kern/powerpc/ieee1275/startup.S (grub_prefix): Likewise. + * grub-core/kern/sparc64/ieee1275/crt0.S (grub_prefix): Likewise. + * grub-core/kern/x86_64/efi/startup.S (grub_prefix): Likewise. + * include/grub/ia64/efi/kernel.h: Removed. + * include/grub/kernel.h: New module type OBJ_TYPE_PREFIX. + (grub_prefix): Removed. + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_PREFIX): Removed. + (GRUB_KERNEL_I386_PC_PREFIX_END): Likewise. + (GRUB_KERNEL_I386_QEMU_PREFIX): Likewise. + (GRUB_KERNEL_I386_QEMU_PREFIX_END): Likewise. + (GRUB_KERNEL_SPARC64_IEEE1275_PREFIX): Likewise. + (GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END): Likewise. + (GRUB_KERNEL_POWERPC_IEEE1275_PREFIX): Likewise. + (GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END): Likewise. + (GRUB_KERNEL_MIPS_LOONGSON_PREFIX): Likewise. + (GRUB_KERNEL_MIPS_LOONGSON_PREFIX_END): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX_END): Likewise. + (GRUB_KERNEL_MIPS_ARC_PREFIX): Likewise. + (GRUB_KERNEL_MIPS_ARC_PREFIX_END): Likewise. + (GRUB_KERNEL_I386_EFI_PREFIX): Likewise. + (GRUB_KERNEL_I386_EFI_PREFIX_END): Likewise. + (GRUB_KERNEL_IA64_EFI_PREFIX): Likewise. + (GRUB_KERNEL_IA64_EFI_PREFIX_END): Likewise. + (GRUB_KERNEL_X86_64_EFI_PREFIX): Likewise. + (GRUB_KERNEL_X86_64_EFI_PREFIX_END): Likewise. + (GRUB_KERNEL_I386_COREBOOT_PREFIX): Likewise. + (GRUB_KERNEL_I386_COREBOOT_PREFIX_END): Likewise. + (GRUB_KERNEL_I386_MULTIBOOT_PREFIX): Likewise. + (GRUB_KERNEL_I386_MULTIBOOT_PREFIX_END): Likewise. + (GRUB_KERNEL_I386_IEEE1275_PREFIX): Likewise. + (GRUB_KERNEL_I386_IEEE1275_PREFIX_END): Likewise. + (GRUB_KERNEL_MACHINE_PREFIX): Likewise. + (GRUB_KERNEL_MACHINE_PREFIX_END): Likewise. + * grub-core/kern/main.c (grub_set_prefix_and_root): Retrieve grub_prefix + from module. + * util/grub-mkimage.c (image_target_desc): Removed prefix and + prefix_end. + (image_targets): Likewise. + (generate_image): Put prefix as a module. + +2011-10-16 Vladimir Serbinenko + + Replace grub_module_iterate with FOR_MODULES. + + * grub-core/disk/memdisk.c (GRUB_MOD_INIT): Switched to new interface. + * grub-core/kern/efi/efi.c (grub_arch_modules_addr): Renamed to... + (grub_efi_modules_addr): ...this. + * grub-core/kern/efi/init.c (grub_modbase): New variable. + (grub_efi_init): Set grub_modbase. + * grub-core/kern/emu/main.c (grub_arch_modules_addr): Removed. + (grub_modbase): New variable. + * grub-core/kern/i386/coreboot/init.c (grub_arch_modules_addr): Removed. + (grub_modbase): New variable. + (grub_machine_init): Set grub_modbase. + * grub-core/kern/i386/pc/init.c (grub_arch_modules_addr): Removed. + (grub_modbase): New variable. + (grub_machine_init): Set grub_modbase. + * grub-core/kern/ieee1275/init.c (grub_arch_modules_addr): Removed. + (grub_modbase): New variable. + (grub_machine_init): Set grub_modbase. + * grub-core/kern/main.c (grub_module_iterate): Remove. + (grub_modules_get_end): Use grub_modbase. + (grub_load_modules): Use FOR_MODULES. + (grub_load_config): Likewise. + * grub-core/kern/mips/arc/init.c (grub_arch_modules_addr): Removed. + (grub_modbase): New variable. + (grub_machine_init): Set grub_modbase. + * grub-core/kern/mips/loongson/init.c (grub_arch_modules_addr): Removed. + (grub_modbase): New variable. + (grub_machine_init): Set grub_modbase. + * grub-core/kern/mips/qemu_mips/init.c (grub_arch_modules_addr): + Removed. + (grub_modbase): New variable. + (grub_machine_init): Set grub_modbase. + * include/grub/efi/efi.h (grub_efi_modules_addr): New declaration. + * include/grub/kernel.h (grub_arch_modules_addr): Removed. + (grub_module_iterate): Likewise. + (grub_modbase): New variable declaration. + (FOR_MODULES): New macro. + +2011-10-16 Vladimir Serbinenko + + * configure.ac: Check for __ctzdi2 and __ctzsi2. + * include/grub/libgcc.h: Include __ctzdi2 and __ctzsi2 if present. + +2011-10-16 Vladimir Serbinenko + + Fix few obvious type discrepancies. + + * grub-core/fs/affs.c (grub_affs_read_file): Use grub_off_t for offset. + * grub-core/fs/afs.c (grub_afs_read_file): Likewise. + * grub-core/fs/fshelp.c (grub_fshelp_find_file): Remove leftover + variable. + * grub-core/fs/hfs.c (grub_hfs_read_file): Use grub_off_t for offset + and connected types. + * grub-core/fs/nilfs2.c (grub_nilfs2_read_file): Use grub_off_t for + offset. + (grub_nilfs2_iterate_dir): Use grub_off_t for fpos. + * grub-core/fs/sfs.c (grub_sfs_read_file): Use grub_off_t for offset. + * grub-core/fs/ufs.c (grub_ufs_read_file): Use grub_off_t for offset + and connected types. + +2011-10-16 Vladimir Serbinenko + + Fix python 3.x incompatibilities. + + * gentpl.py: Put brackets around print strings. + * util/import_gcry.py: Open explicitly as utf-8. + Use in instead of has_key. + +2011-10-16 Vladimir Serbinenko + + * grub-core/fs/xfs.c (grub_xfs_inode): New field fork_offset. + (GRUB_XFS_INO_AGBITS): Make into inline function. + (GRUB_XFS_INO_INOINAG): Likewise. + (GRUB_XFS_INO_AG): Likewise. + (GRUB_XFS_FSB_TO_BLOCK): Likewise. + (GRUB_XFS_EXTENT_OFFSET): Likewise. + (GRUB_XFS_EXTENT_BLOCK): Likewise. + (GRUB_XFS_EXTENT_SIZE): Likewise. + (GRUB_XFS_ROUND_TO_DIRENT): Likewise. + (GRUB_XFS_NEXT_DIRENT): Likewise. + (grub_xfs_read_block): Rewrite the btree parsing. Fixes invalid BMAP. + (grub_xfs_read_file): Fix offset type. + +2011-10-15 Robert Millan + + * util/getroot.c (grub_util_get_grub_dev): Fix OS selection #ifdefs. + +2011-10-15 Robert Millan + + Fix build problem on FreeBSD and GNU/kFreeBSD. + + * util/getroot.c [__FreeBSD_kernel__]: Include `'. + +2011-10-14 Vladimir Serbinenko + + Fix overflow with >2GiB file on HFS+. >4GiB wasn't tested. + + * grub-core/fs/hfsplus.c (grub_hfsplus_btree): Use more appropriate + types. + (grub_hfsplus_btree_recoffset): Likewise. + (grub_hfsplus_btree_recptr): Likewise. + (grub_hfsplus_find_block): Likewise. + (grub_hfsplus_btree_search): Likewise. + (grub_hfsplus_read_block): Likewise. + (grub_hfsplus_read_file): Likewise. + (grub_hfsplus_mount): Likewise. + (grub_hfsplus_btree_iterate_node): Likewise. + (grub_hfsplus_btree_search): Likewise. + (grub_hfsplus_iterate_dir): Likewise. + (grub_hfsplus_read): A small code simplification. + +2011-10-14 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Don't assume that children + of mapper nodes are mapper nodes. + +2011-10-14 Vladimir Serbinenko + + * grub-core/lib/posix_wrap/ctype.h (isxdigit): Use grub_isxdigit. + * include/grub/misc.h (grub_isxdigit): New function. + * grub-core/video/colors.c (my_isxdigit): Removed. All users + switched to grub_isxdigit. + * grub-core/term/serial.c (grub_serial_find): Fix in case of port + number starting with a letter. + +2011-10-09 Robert Millan + + LVM support for FreeBSD and GNU/kFreeBSD. + + * util/lvm.c (grub_util_lvm_isvolume): Enable on FreeBSD and + GNU/kFreeBSD. + (LVM_DEV_MAPPER_STRING): Move from here ... + * include/grub/util/lvm.h (LVM_DEV_MAPPER_STRING): ... to here. + * util/getroot.c: Include `'. + (grub_util_get_dev_abstraction): Enable + grub_util_biosdisk_is_present() on FreeBSD and GNU/kFreeBSD. + Check for LVM abstraction on FreeBSD and GNU/kFreeBSD. + (grub_util_get_grub_dev): Replace "/dev/mapper/" with + `LVM_DEV_MAPPER_STRING'. Enable LVM and mdRAID only on platforms that + support it. + * util/grub-setup.c (main): Check for LVM also on FreeBSD and + GNU/kFreeBSD. + * util/grub.d/10_kfreebsd.in: Load `geom_linux_lvm' kernel module + when LVM abstraction is required for ${GRUB_DEVICE}. + +2011-10-06 Szymon Janc + + Add support for LZO compression in GRUB: + - import of minilzo library, + - LZO decompression for btrfs, + - lzop files decompression. + + * grub-core/io/lzopio.c: New file. + * grub-core/lib/adler32.c: Likewise. + * grub-core/lib/minilzo/lzoconf.h: Likewise. + * grub-core/lib/minilzo/lzodefs.h: Likewise. + * grub-core/lib/minilzo/minilzo.c: Likewise. + * grub-core/lib/minilzo/minilzo.h: Likewise. + * Makefile.util.def (libgrubmods.a): Add grub-core/io/lzopio.c, + grub-core/lib/adler32.c, grub-core/io/lzopio.c, + grub-core/lib/minilzo/minilzo.c to common. + * Makefile.util.def (libgrubmods.a): Add flags required by minilzo to + cflags in cppflags. + * grub-core/Makefile.core.def (btrfs): Likewise. + * grub-core/Makefile.core.def (lzopio): New module. + (adler32): Likewise. + * grub-core/fs/btrfs.c: Include minilzo.h. + (GRUB_BTRFS_COMPRESSION_LZO): New define. + (GRUB_BTRFS_LZO_BLOCK_SIZE): Likewise. + (GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE): Likewise. + (grub_btrfs_lzo_decompress): New function. + (grub_btrfs_extent_read): Add support for LZO compression type. + * include/grub/types.h (GRUB_UCHAR_MAX): New define. + (GRUB_USHRT_MAX): Likewise. + (GRUB_UINT_MAX): Likewise. + * grub-core/lib/posix_wrap/limits.h (USHRT_MAX): Likewise. + (UINT_MAX): Likewise. + (CHAR_BIT): Likewise. + * grub-core/lib/posix_wrap/sys/types.h (ULONG_MAX): Moved to + grub-core/lib/posix_wrap/limits.h + (UCHAR_MAX): Likewise. + * include/grub/file.h (grub_file_filter_id): New compression filter + GRUB_FILE_FILTER_LZOPIO. + * include/grub/file.h (grub_file_filter_id): Set + GRUB_FILE_FILTER_LZOPIO as GRUB_FILE_FILTER_COMPRESSION_LAST. + * include/grub/types.h (grub_get_unaligned16): New function. + (grub_get_unaligned32): Likewise. + (grub_get_unaligned64): Likewise. + * util/import_gcry.py (cryptolist): Add adler32. + +2011-10-05 Vladimir Serbinenko + + * grub-core/Makefile.core.def: Eliminate rarely used emu_condition. This + in perspective decreases the complexity of build system and fixes + compilation right now. + +2011-10-01 Ales Nesrsta + + * grub-core/bus/usb/uhci.c: Changes made by Rock Cui - thanks! + (fixed problem related to using UHCI with coreboot). + +2011-08-25 BVK Chaitanya + + * gentpl.py: Use Autogen macros so that the output template file + (Makefile.tpl) size is reduced. + +2011-09-29 Mads Kiilerich + + * grub-core/Makefile.core.def (kernel): Add kern/i386/int.S to + extra_dist. + +2011-09-29 Mario Limonciello + + * util/misc.c (grub_util_get_disk_size) [__MINGW32__]: Strip trailing + slashes on PHYSICALDRIVE%d paths when making Windows CreateFile calls. + +2011-09-29 Mario Limonciello + + * grub-core/kern/emu/misc.c (canonicalize_file_name) [__MINGW32__]: Use + _fullpath. + +2011-09-29 Mario Limonciello + + Remove extra declaration of sleep for mingw32. + + * util/misc.c (sleep) [__MINGW32__]: Removed. + * include/grub/util/misc.h (sleep) [__MINGW32__]: Likewise. + +2011-09-28 Grégoire Sutre + + * include/grub/bsdlabel.h (grub_partition_bsd_disk_label): Add fields + type and packname. + * include/grub/i386/netbsd_bootinfo.h (NETBSD_BTINFO_BOOTDISK): + Resurrected. + (NETBSD_BTINFO_BOOTWEDGE): New definition. + (grub_netbsd_btinfo_bootwedge): New struct. + * grub-core/loader/i386/bsd.c (grub_netbsd_add_boot_disk_and_wedge): + New function. + (grub_cmd_netbsd): Call grub_netbsd_add_boot_disk_and_wedge. + +2011-09-28 Thomas Haller + + * grub-core/loader/multiboot_elfxx.c (Elf_Shdr): Set according to + loader. + +2011-09-28 Andreas Born + + Fix incorrect identifiers in bash-completion. + + * util/bash-completion.d/grub-completion.bash.in + (_grub_mkpasswd-pbkdf2): Rename to ... + (_grub_mkpasswd_pbkdf2): ... this. All users updated. + (_grub_script-check): Rename to ... + (_grub_script_check): ... this. All users updated. + +2011-09-28 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy): + Return 0 if disk isn't biosdisk. + +2011-09-17 Grégoire Sutre + + * Makefile.util.def (grub-mkrelpath): Add LIBUTIL for getrawpartition(3) + on NetBSD. + * Makefile.util.def (grub-fstest): Likewise. + +2011-09-17 Grégoire Sutre + + * grub-core/kern/emu/hostdisk.c (grub_util_get_fd_sectors) [__NetBSD__]: + Get sector size from disk label. + +2011-09-05 Colin Watson + + * util/grub-mkconfig_lib.in (grub_file_is_not_garbage): Return 1 for + */README* as well as README*. + Reported by: Axel Beckert. + +2011-08-23 Vladimir Serbinenko + + * grub-core/kern/mips/loongson/init.c (grub_machine_init): Handle the + case of less than 256 MiB of RAM. + +2011-08-23 Vladimir Serbinenko + + * grub-core/commands/wildcard.c (make_regex): Handle @. + +2011-08-23 Vladimir Serbinenko + + * util/grub-install.in: Move cryptodisk logic to appropriate place. + +2011-08-21 Szymon Janc + + * acinclude.m4: Use AC_LANG_PROGRAM macro to generate source code for + AC_LANG_CONFTEST macros. + +2011-08-20 Szymon Janc + + Add grub-fstest option to uncompress data for commands. + + * util/grub-fstest.c (uncompress): New var. + (options): New option -u. + +2011-08-20 Szymon Janc + + * grub-core/loader/i386/linux.c (grub_linux_setup_video): Add + GRUB_VIDEO_DRIVER_RADEON_FULOONG2E to switch case statement. + +2011-08-20 Szymon Janc + + * grub-core/io/gzio.c (grub_gzio_open): Always return original io if + file type was not recognized correctly (not gzip or corrupted). + +2011-08-19 Vladimir Serbinenko + + * grub-core/kern/mips/loongson/init.c (grub_reboot): Reboot Fuloong. + * include/grub/cs5536.h (GRUB_CS5536_MSR_DIVIL_RESET): New definition. + +2011-08-19 Vladimir Serbinenko + + * grub-core/Makefile.core.def (kernel): Add video/radeon_fuloong2e.c on + loongson. + * grub-core/kern/mips/loongson/init.c (grub_machine_init): Init + video_radeon_fuloong2e. + * grub-core/video/radeon_fuloong2e.c: New file. + * include/grub/video.h (grub_video_id_t): Add new ID + GRUB_VIDEO_DRIVER_RADEON_FULOONG2E. + +2011-08-19 Vladimir Serbinenko + + * include/grub/mips/loongson.h (GRUB_CPU_LOONGSON_COP0_PRID): New + define. + * grub-core/kern/mips/loongson/init.c (grub_machine_init): Check + that PRID matches the detected subplatform and reset the subplatform + if it doesn't. + +2011-08-19 Vladimir Serbinenko + + * grub-core/kern/misc.c (grub_vprintf): Fix a bug on malloc failure. + +2011-08-19 Vladimir Serbinenko + + Fix PCI iterating on functions >= 4. + + * grub-core/bus/pci.c (grub_pci_iterate): Remove useless ghost skipping. + * include/grub/mips/loongson/pci.h (GRUB_LOONGSON_OHCI_GHOST_FUNCTION): + Removed. + (GRUB_LOONGSON_EHCI_GHOST_FUNCTION): Likewise. + (grub_pci_read): Fix bitmask. + (grub_pci_read_word): Likewise. + (grub_pci_read_byte): Likewise. + (grub_pci_write): Likewise. + (grub_pci_write_word): Likewise. + (grub_pci_write_byte): Likewise. + +2011-08-19 Vladimir Serbinenko + + * configure.ac: Don't impose march=loongson2f on loongson platform. (It + can still be specified in TARGET_CFLAGS) + +2011-08-19 Vladimir Serbinenko + + Rename Fuloong into Fuloong 2F. Add new ID for Fuloong2E. + + * grub-core/Makefile.core.def (fwstart_fuloong): Rename fwstart_fuloong + into fwstart_fuloong2f. Use boot/mips/loongson/fuloong2f.S. + * grub-core/boot/mips/loongson/fuloong.S: Rename to ... + * grub-core/boot/mips/loongson/fuloong2f.S: ... this. + (FULOONG): Rename to ... + (FULOONG2F): ... this. All users updated. + * grub-core/boot/mips/startup_raw.S (machtype_fuloong_str): Rename to + (machtype_fuloong2f_str): ... this. + (machtype_fuloong2e_str): New string. + Check for machtype_fuloong2e_str. + * grub-core/loader/mips/linux.c (loongson_machtypes) + [GRUB_MACHINE_MIPS_LOONGSON]: Add GRUB_ARCH_MACHINE_FULOONG2E. + * grub-core/term/serial.c (loongson_defserial) + [GRUB_MACHINE_MIPS_LOONGSON]: New array. + (grub_serial_register) [GRUB_MACHINE_MIPS_LOONGSON]: Use + loongson_defserial. + * include/grub/mips/loongson/kernel.h (GRUB_ARCH_MACHINE_FULOONG): + Rename to ... + (GRUB_ARCH_MACHINE_FULOONG2F): ... this. + (GRUB_ARCH_MACHINE_FULOONG2E): New const. + * util/grub-mkimage.c (image_target_desc): Rename IMAGE_FULOONG_FLASH + to IMAGE_FULOONG2F_FLASH. All users updated. + (image_targets): Rename images. + * util/grub-mkstandalone.in: Accept fuloong2f and fuloong2e. + +2011-08-19 Szymon Janc + + Make enable of disk cache statistics code configurable. + + * configure.ac: --enable-cache-stats added. + * config.h.in (DISK_CACHE_STATS): New define. + * grub-core/Makefile.core.def (cacheinfo): New command. + * include/grub/disk.h(grub_disk_cache_get_performance): New function. + * grub-core/commands/cacheinfo.c: New file. + * grub-core/commands/minicmd.c (grub_rescue_cmd_info): Updated and + moved to cacheinfo.c. + * grub-core/kern/disk.c: Use DISK_CACHE_STATS to disable disk cache + debug code. + * include/grub/disk.h: Likewise. + +2011-08-19 Szymon Janc + + * Makefile.am (AUTOMAKE_OPTIONS): = Added -Wno-portability flag. + * grub-core/Makefile.am: Likewise. + +2011-08-16 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_iterate): Skip with + non-zero pull. + +2011-08-16 Vladimir Serbinenko + + * grub-core/fs/jfs.c (grub_jfs_read_file): New parameter ino. + All users updated. + (grub_jfs_lookup_symlink): Use correct starting inode. + +2011-08-16 Vladimir Serbinenko + + * util/grub-setup.c (main): Add missing gcry initialisation. + +2011-08-16 Vladimir Serbinenko + + Don't accept text modes on EFI when booting Linux. + + * grub-core/loader/i386/linux.c (ACCEPTS_PURE_TEXT): New define. + (grub_linux_boot) [!ACCEPTS_PURE_TEXT]: Restrict to graphics modes. + +2011-08-15 Mario Limonciello +2011-08-15 Colin Watson + + * util/grub-probe.c (probe): Canonicalise the path argument, fixing + use of "/path/.." as in grub-install for EFI as well as handling + symlinks correctly. + Fixes Debian bug #637768. + +2011-08-15 Colin Watson + + * util/grub-probe.c: Remove duplicate #include. + +2011-08-10 Robert Millan + + Detect LSI MegaRAID SAS (`mfi') devices on GNU/kFreeBSD. + + * util/deviceiter.c [__FreeBSD_kernel__] (get_mfi_disk_name): New + function. + [__FreeBSD_kernel__] (grub_util_iterate_devices): Scan for mfi + (/dev/mfid[0-9]+) devices using get_mfi_disk_name(). + +2011-08-03 Robert Millan + + * include/grub/zfs/zap_leaf.h (typedef union zap_leaf_chunk): Mark + la_array as packed. + Reported by: Zachary Bedell + +2011-07-26 Colin Watson + + * configure.ac: The Loongson port requires grub-mkfont due to its + use of -DUSE_ASCII_FAILBACK. Raise an error if it is not going to + be built. + +2011-07-26 Colin Watson + + * util/grub-install.in: Don't source grub-mkconfig_lib until after + processing arguments (otherwise help2man fails when GRUB has not yet + been installed). + +2011-07-25 Vladimir Serbinenko + + New script grub-mkstandalone. + + * Makefile.util.def (grub-mkstandalone): New script. + * docs/man/grub-mkstandalone.h2m: New file. + * util/grub-mkstandalone.in: Likewise. + +2011-07-25 Vladimir Serbinenko + + Support ATA disks with 4K sectors. + + * include/grub/ata.h (grub_ata): New member log_sector_size. + * grub-core/disk/ata.c (grub_ata_dumpinfo): Show sector size. + (grub_ata_identify): Read sector size. + (grub_ata_readwrite): Use log_sector_size rather than hardcoded value. + +2011-07-25 Vladimir Serbinenko + + * util/grub-install.in: Don't use uhci outside of x86. + +2011-07-25 Vladimir Serbinenko + + * util/grub-mkrescue.in: Add missing quotes. + +2011-07-25 Vladimir Serbinenko + + * grub-core/normal/menu.c (grub_menu_execute_entry): Fix NULL + dereference. + +2011-07-23 Vladimir Serbinenko + + * grub-core/disk/pata.c (grub_pata_readwrite): Add missing wait. + +2011-07-23 Vladimir Serbinenko + + * include/grub/video.h: add missing EXPORT_FUND on + grub_video_edid_checksum and grub_video_edid_preferred_mode. + +2011-07-23 Vladimir Serbinenko + + * include/grub/mips/kernel.h: Fix define conflict. + +2011-07-23 Vladimir Serbinenko + + * grub-core/kern/mips/cache_flush.S [GRUB_MACHINE_MIPS_LOONGSON]: Flush + all four ways. + +2011-07-21 Colin Watson + + Preferred resolution detection for VBE. + + * grub-core/video/video.c (grub_video_edid_checksum): New function. + (grub_video_edid_preferred_mode): Likewise. Try EDID followed by + the Flat Panel extension, in line with the X.org VESA driver. + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_flat_panel_info): + New function. + (grub_vbe_bios_get_ddc_capabilities): Likewise. + (grub_vbe_bios_read_edid): Likewise. + (grub_vbe_get_preferred_mode): Likewise. + (grub_video_vbe_setup): When the mode is "auto", try to get the + preferred mode from VBE, and use the largest mode that is no larger + than the preferred mode (some BIOSes expose a preferred mode that is + not in their mode list!). If this fails, fall back to 640x480 as a + safe conservative choice. + (grub_video_vbe_get_edid): New function. + (grub_video_vbe_adapter): Add get_edid. + * include/grub/video.h (struct grub_vbe_edid_info): New structure. + (struct grub_video_adapter): Add get_edid. + (grub_video_edid_checksum): Add prototype. + (grub_video_edid_preferred_mode): Likewise. + * include/grub/i386/pc/vbe.h (struct grub_vbe_flat_panel_info): New + structure. + + * grub-core/commands/videoinfo.c (print_edid): New function. + (grub_cmd_videoinfo): Print EDID if available. + + * util/grub.d/00_header.in (GRUB_GFXMODE): Default to "auto". This + is more appropriate on a wider range of platforms than 640x480. + * docs/grub.texi (Simple configuration): Update GRUB_GFXMODE + documentation. + +2011-07-10 Vladimir Serbinenko + + * util/grub-install.in: Recognize ESP mounted at /boot/EFI. + +2011-07-10 Vladimir Serbinenko + + * po/POTFILES.in: Regenerate. + +2011-07-10 Vladimir Serbinenko + + * grub-core/disk/efi/efidisk.c (grub_efidisk_get_device_name): Fix + incorrect memory usage. + +2011-07-10 Vladimir Serbinenko + + * util/grub-install.in: Source grub-mkconfig_lib. + +2011-07-08 Vladimir Serbinenko + + Remove getroot.c from core on emu platform. + + * grub-core/Makefile.core.def (kernel): Remove kern/emu/getroot.c and + kern/emu/raid.c. + * grub-core/kern/emu/main.c (main): Don't try to guess root device. It's + useless. + * grub-core/kern/emu/misc.c (get_win32_path): Moved from here... + * util/getroot.c (get_win32_path): ... here. + * grub-core/kern/emu/misc.c (fini_libzfs): Moved from here... + * util/getroot.c (fini_libzfs): ... here. + * grub-core/kern/emu/misc.c (grub_get_libzfs_handle): Moved from here... + * util/getroot.c (grub_get_libzfs_handle): ... here. + * grub-core/kern/emu/misc.c (grub_find_zpool_from_dir): + Moved from here... + * util/getroot.c (grub_find_zpool_from_dir): ... here. + * grub-core/kern/emu/misc.c + (grub_make_system_path_relative_to_its_root): Moved from here... + * util/getroot.c (grub_make_system_path_relative_to_its_root): ... here. + * grub-core/kern/emu/getroot.c: Moved from here ... + * util/getroot.c: ... here. All users updated. + * grub-core/kern/emu/raid.c: Moved from here ... + * util/raid.c: ... here. All users updated. + +2011-07-08 Vladimir Serbinenko + + * po/POTFILES.in: Regenerate. + +2011-07-07 Vladimir Serbinenko + + Fix compilation on GNU/Linux. + + * grub-core/kern/emu/getroot.c (grub_util_pull_device) [!FreeBSD]: + Disable geli. + (grub_util_get_grub_dev) [!FreeBSD]: Likewise. + (grub_util_pull_device) [HAVE_DEVICE_MAPPER]: Fix const and func name. + * grub-core/disk/cryptodisk.c (grub_cryptodisk_open): Fix proto. + +2011-07-07 Vladimir Serbinenko +2011-07-07 Michael Gorven +2011-07-07 Clemens Fruhwirth + + LUKS and GELI support. + + * Makefile.util.def (libgrubkern.a): Add grub-core/lib/crypto.c, + grub-core/disk/luks.c, grub-core/disk/geli.c, + grub-core/disk/cryptodisk.c, grub-core/disk/AFSplitter.c, + grub-core/lib/pbkdf2.c, grub-core/commands/extcmd.c, + grub-core/lib/arg.c. + (libgrubmods.a): Remove gcrypts cflags and cppflags. + Remove grub-core/commands/extcmd.c, grub-core/lib/arg.c, + grub-core/lib/crypto.c, grub-core/lib/libgcrypt-grub/cipher/sha512.c, + grub-core/lib/libgcrypt-grub/cipher/crc.c and grub-core/lib/pbkdf2.c. + (grub-bin2h): Add libgcry.a. + (grub-mkimage): Likewise. + (grub-mkrelpath): Likewise. + (grub-script-check): Likewise. + (grub-editenv): Likewise. + (grub-mkpasswd-pbkdf2): Likewise. + (grub-pe2elf): Likewise. + (grub-fstest): Likewise. + (grub-mkfont): Likewise. + (grub-mkdevicemap): Likewise. + (grub-probe): Likewise. + (grub-ofpath): Likewise. + (grub-mklayout): Likewise. + (example_unit_test): Likewise. + (grub-menulst2cfg): Likewise. + * autogen.sh (UTIL_DEFS): Add Makefile.utilgcry.def. + * grub-core/Makefile.core.def (cryptodisk): New module. + (luks): Likewise. + (geli): Likewise. + * grub-core/disk/AFSplitter.c: New file. + * grub-core/disk/cryptodisk.c: Likewise. + * grub-core/disk/geli.c: Likewise. + * grub-core/disk/luks.c: Likewise. + * grub-core/kern/emu/getroot.c (get_dm_uuid): New function based on + grub_util_is_lvm. + (grub_util_get_dm_abstraction): New function. + (grub_util_follow_gpart_up): Likewise. + (grub_util_get_geom_abstraction): Likewise. + (grub_util_get_dev_abstraction): Use new functions. + (grub_util_pull_device): Pull GELI and LUKS. + (grub_util_get_grub_dev): Handle LUKS and GELI. + * grub-core/kern/emu/hostdisk.c (grub_util_get_fd_sectors): New function. + (grub_util_biosdisk_open): Use grub_util_get_fd_sectors. + (follow_geom_up): Removed. + (grub_util_fd_seek): New function. + (open_device): Use grub_util_fd_seek. + (nread): Rename to .. + (grub_util_fd_read): ... this. All users updated. + * grub-core/lib/crypto.c (grub_crypto_ecb_decrypt): A better prototype. + (grub_crypto_cbc_decrypt): Likewise. + (grub_crypto_hmac_write): Likewise. + (grub_crypto_hmac_buffer): Likewise. + (grub_password_get): Extend to util. + * include/grub/crypto.h (gcry_cipher_spec) [GRUB_UTIL]: + New member modname. + (gcry_md_spec) [GRUB_UTIL]: Likewise. + * include/grub/cryptodisk.h: New file. + * include/grub/disk.h (grub_disk_dev_id): Rename LUKS to CRYPTODISK. + * include/grub/emu/getroot.h (grub_dev_abstraction_types): Add + LUKS and GELI. + (grub_util_follow_gpart_up): New proto. + * include/grub/emu/hostdisk.h (grub_util_fd_seek): Likewise. + (grub_util_fd_read): Likewise. + (grub_cryptodisk_cheat_mount): Likewise. + (grub_util_cryptodisk_print_uuid): Likewise. + (grub_util_get_fd_sectors): Likewise. + * util/grub-fstest.c (mount_crypt): New var. + (fstest): Mount crypto if requested. + (options): New option -C. + (argp_parser): Parse -C. + (main): Init and fini gcry. + * util/grub-install.in: Support cryptodisk install. + * util/grub-mkconfig.in: Export GRUB_ENABLE_CRYPTODISK. + * util/grub-mkconfig_lib.in (is_path_readable_by_grub): Support + cryptodisk. + (prepare_grub_to_access_device): Likewise. + * util/grub-mkpasswd-pbkdf2.c (main): Use grub_password_get. + * util/grub-probe.c (probe_partmap): Support cryptodisk UUID probe. + (probe_cryptodisk_uuid): New function. + (probe_abstraction): Likewise. + (probe): Use new functions. + * util/import_gcry.py: Create Makefile.utilgcry.def. + Add modname member. + +2011-07-07 Vladimir Serbinenko + + Lazy device scanning. + + * Makefile.util.def (libgrubkern.a): Add grub-core/kern/emu/raid.c. + (grub-setup): Remove util/raid.c. + * grub-core/Makefile.core.def (kernel): Add kern/emu/raid.c on emu. + * grub-core/disk/lvm.c (scan_depth): New variable. + (grub_lvm_iterate): Rescan if necessary. + (find_lv): New function based on grub_lvm_open. + (grub_lvm_open): Use find_lv. Rescan on error. + (is_node_readable): New function. + (is_lv_readable): Likewise. + (grub_lvm_scan_device): Skip already found disks. + (do_lvm_scan): New function. Move grub_lvm_scan_device inside of it. + Stop if searched device is found and readable. + * grub-core/disk/raid.c (inscnt): New variable. + (scan_depth): Likewise. + (scan_devices): New function based on grub_raid_register. Abort if + looked for device is found. + (grub_raid_iterate): Rescan if needed. + (find_array): NEw function based on -grub_raid_open. + (grub_raid_open): Use find_array and rescan. + (insert_array): Set became_readable_at. + * grub-core/kern/disk.c (grub_disk_dev_iterate): Iterate though "pull. + * grub-core/kern/emu/getroot.c (grub_util_open_dm) [HAVE_DEVICE_MAPPER]: + New function. + (grub_util_is_lvm) [HAVE_DEVICE_MAPPER]: Use grub_util_open_dm. + (grub_util_pull_device): New function. + (grub_util_get_grub_dev): Call grub_util_pull_device. + * util/raid.c: Moved to .. + * grub-core/kern/emu/raid.c: ... here. + (grub_util_raid_getmembers): New parameter "bootable". + All users updated. Support 1.x. + * include/grub/ata.h (grub_ata_dev): Change iterate prototype. + All users updated. + * include/grub/disk.h (grub_disk_pull_t): New enum. + (grub_disk_dev): Change iterate prototype. + All users updated. + * include/grub/emu/getroot.h (grub_util_raid_getmembers) [__linux__]: + New proto. + * include/grub/emu/hostdisk.h (grub_util_pull_device): Likewise. + * include/grub/lvm.h (grub_lvm_lv): New members fullname and compatname. + * include/grub/raid.h (grub_raid_array): New member became_readable_at. + * include/grub/scsi.h (grub_scsi_dev): Change iterate prototype. + All users updated. + * include/grub/util/raid.h: Removed. + +2011-07-06 Vladimir Serbinenko + + * po/POTFILES.in: Regenerate. + +2011-07-06 Vladimir Serbinenko + + Unify sparc init with other ieee1275. + + * grub-core/Makefile.core.def (kernel): Use kern/ieee1275/init.c + instead of kern/sparc64/ieee1275/init.c. + * grub-core/kern/ieee1275/cmain.c (grub_ieee1275_find_options) + [__sparc__]: Set GRUB_IEEE1275_FLAG_NO_PARTITION_0. + * grub-core/kern/ieee1275/init.c [__sparc__]: Include + grub/machine/kernel.h. + (grub_ieee1275_original_stack) [__sparc__]: New variable. + (grub_claim_heap) [__sparc__]: Use sparc version. + (grub_machine_init): Moved args parsing to + (grub_parse_cmdline): ...this. + * grub-core/kern/sparc64/ieee1275/init.c: Removed. + * include/grub/offsets.h (GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP): + New definition. + (GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN): Likewise. + + Move BOOTP to separate file. + + * grub-core/Makefile.core.def (net): Add net/bootp.c. + * grub-core/net/net.c: Move all BOOTP functions to + * grub-core/net/bootp.c: ... here. + + Use frame interface on PXE. + + * grub-core/Makefile.core.def (pxecmd): Removed. + (pxe): Use net/drivers/i386/pc/pxe.c rather than net/i386/pc/pxe.c. + * grub-core/commands/i386/pc/pxecmd.c: Removed. + * grub-core/i386/pc/pxe.c: Moved from here ... + * grub-core/net/i386/pc/pxe.c: ... here. Rewritten. + * grub-core/net/net.c (grub_net_open_real): Handle old pxe syntax. + * include/grub/i386/pc/pxe.h (grub_pxe_unload): Removed. + + EFI network support. + + * grub-core/Makefile.core.def (efinet): New module. + * grub-core/disk/efi/efidisk.c (compare_device_paths): Moved from + here... + * grub-core/kern/efi/efi.c (grub_efi_compare_device_paths): ... here. + All users updated. + * grub-core/kern/efi/init.c (grub_efi_net_config): New variable. + (grub_machine_get_bootlocation): Call grub_efi_net_config if needed. + * grub-core/kern/x86_64/efi/callwrap.S (efi_wrap_7): New function. + * grub-core/net/drivers/efi/efinet.c: New file. + * include/grub/efi/efi.h (grub_efi_compare_device_paths): New proto. + (grub_efi_net_config): New extern var. + + Various cleanups and bugfixes. + + * grub-core/disk/efi/efidisk.c (grub_efidisk_open): Fix off-by-one + error. + (grub_efidisk_get_device_name): Unify similar codepaths. Accept whole + disk declared as partition. + * grub-core/disk/ieee1275/ofdisk.c (grub_ofdisk_open): Fix memory + leak on failure. + * grub-core/kern/dl.c (grub_dl_load_file): Fix memory leak. + * grub-core/kern/mm.c (grub_debug_malloc): Don't use unsupported %zx. + (grub_debug_zalloc): Likewise. + (grub_debug_realloc): Likewise. + (grub_debug_memalign): Likewise. + * grub-core/net/arp.c (grub_net_arp_receive): IPv4 is 4-byte wide. + Check that target is IPv4. + * grub-core/net/drivers/ieee1275/ofnet.c (grub_ofnet_findcards): Use + local-mac-address as fallback. + * grub-core/net/ethernet.c (grub_net_recv_ethernet_packet): Prevent + memory leak. + * grub-core/net/ip.c (ipchksum): Rename to ... + (grub_net_ip_chksum): ... this. All users updated. + (grub_net_recv_ip_packets): Special handling for DHCP. + * util/grub-mkimage.c (generate_image): Zero-out aout header. + + Unify prefix handling + + * grub-core/kern/efi/init.c (grub_efi_set_prefix): Revamped into ... + (grub_machine_get_bootlocation): ... this. + * grub-core/kern/emu/main.c (grub_machine_set_prefix): Revamped into ... + (grub_machine_get_bootlocation): ... this. + (grub_prefix): New variable. + (prefix): Removed. + (root_dev): New variable. + (dir): Likewise. + (main): Use new variables. + * grub-core/kern/i386/coreboot/init.c (grub_machine_set_prefix): + Revamped into ... + (grub_machine_get_bootlocation): ... this. + * grub-core/kern/i386/efi/init.c (grub_machine_set_prefix): Removed. + * grub-core/kern/i386/pc/init.c (make_install_device): Revamped into ... + (grub_machine_get_bootlocation): ... this. + (grub_machine_set_prefix): Removed. + * grub-core/kern/ia64/efi/init.c (grub_machine_set_prefix): Removed. + * grub-core/kern/ieee1275/init.c (grub_machine_set_prefix): + Revamped into ... + (grub_machine_get_bootlocation): ... this. + * grub-core/kern/main.c (grub_set_root_dev): Revamped into ... + (grub_set_prefix_and_root): ... this. All users updated. + * grub-core/kern/mips/init.c (grub_machine_set_prefix): + Revamped into ... + (grub_machine_get_bootlocation): ... this. + * include/grub/kernel.h (grub_machine_set_prefix): Removed. + (grub_machine_get_bootlocation): New proto. + * include/grub/i386/pc/kernel.h (grub_pc_net_config): New var. + + Less intrusive and more reliable seek on network implementation. + + * grub-core/kern/file.c (grub_file_net_seek): Removed. + (grub_file_seek): Don't call grub_file_net_seek. + * grub-core/net/net.c (grub_net_fs_read): Renamed to ... + (grub_net_fs_read_real): .. this. + (grub_net_seek_real): Use net->offset. + (grub_net_fs_read): Seek if necessary. + + Unify IEEE1275 netwotk config with the other platforms. + + * grub-core/kern/ieee1275/init.c (grub_ieee1275_net_config): + New variable. + (grub_machine_get_bootlocation): Support network. + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args): + Support type and device parsing. + (grub_ieee1275_get_device_type): New function. + * grub-core/net/drivers/ieee1275/ofnet.c (grub_getbootp_real): Revamped + into ... + (grub_ieee1275_net_config_real): ... this. + (grub_ofnet_probecards): Removed. + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Remove ofnet.h. + * include/grub/ieee1275/ofnet.h: Removed. + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_net_config): NEw + extern var. + (grub_ieee1275_get_device_type): New function. + + Unify network device closing across platforms and make more robust. + + * grub-core/kern/ieee1275/init.c (grub_machine_fini): Don't call + grub_grubnet_fini. + * grub-core/net/ethernet.c (send_ethernet_packet): Open card if it isn't + already. + * grub-core/net/net.c (grub_net_network_level_interface_register): + Update num_ifaces. + (grub_net_card_unregister): Close all interfaces. + (receive_packets): Don't poll if no iterfaces are registered. + Open if necessary. + (grub_net_fini_hw): New function. + (grub_net_restore_hw): Likewise. + (fini_hnd): New variable. + (GRUB_MOD_INIT): Register preboot hook. + (GRUB_MOD_FINI): Run and unregister preboot hook. + + Poll network cards when idle. + + * grub-core/kern/term.c (grub_net_poll_cards_idle): New variable. + (grub_checkkey): Call grub_net_poll_cards_idle if it's not NULL. + * grub-core/net/net.c (receive_packets): Save last poll time. + (grub_net_poll_cards_idle_real): New function. + (GRUB_MOD_INIT): Register grub_net_poll_cards_idle. + (GRUB_MOD_FINI): Unregister grub_net_poll_cards_idle. + * include/grub/kernel.h (grub_poll_cards_idle): New extern variable. + + Rename ofnet interfaces. + + * grub-core/net/drivers/ieee1275/ofnet.c (find_alias): New function. + (grub_ofnet_findcards): Use ofnet_%s names. + + * util/grub-mknetdir.in: Support for EFI and IEEE1275. + + Cleanup socket opening. + + * grub-core/net/net.c (grub_net_fs_open): Rewritten. + (grub_net_fs_close): Likewise. + (grub_net_fs_read_real): Use eof member. + * include/grub/net/udp.h (+grub_net_udp_open): New proto. + (+grub_net_udp_close): New inline function. + + * include/grub/net/tftp.h: Moved to the top of ... + * grub-core/net/tftp.c: ... here. + * include/grub/net/ip.h: Moved mostly to the top of ... + * grub-core/net/ip.c: ... here. + * include/grub/net/ethernet.h: Moved mostly to the top of ... + * grub-core/net/ethernet.c: ... here. + + * grub-core/kern/device.c (grub_device_close): Free device->net->server. + + * grub-core/commands/probe.c (grub_cmd_probe): Use protocol name for + FS name. + + * include/grub/net/ip.h (ipv4_ini): Removed. + (ipv4_fini): Likewise. + + * include/grub/net/ip.h (grub_net_recv_ip_packets): New proto. + (grub_net_send_ip_packets): Likewise. + +2011-07-05 Vladimir Serbinenko + + * grub-core/kern/i386/qemu/mmap.c (grub_machine_mmap_init): Use new + grub_read_cmos prototype. + +2011-07-05 Vladimir Serbinenko + + VGA text support in qemu-mips + + * grub-core/Makefile.core.def (kernel): Add term/i386/pc/vga_text.c, + term/i386/vga_common.c and kern/vga_init.c on qemu-mips. + * grub-core/kern/mips/qemu_mips/init.c (grub_machine_init): Init vga + text. + * grub-core/kern/i386/qemu/init.c: Renamed to ... + * grub-core/kern/vga_init.c: ... this. + * grub-core/kern/vga_init.c (VGA_ADDR) [__mips__]: Adjust. + (grub_qemu_init_cirrus) [__mips__]: Skip PCI and adjust the I/O base. + * grub-core/term/i386/pc/vga_text.c (VGA_TEXT_SCREEN) [__mips__]: + Adjust. + * include/grub/vga.h [GRUB_MACHINE_MIPS_QEMU_MIPS]: Declare + GRUB_MACHINE_PCI_IO_BASE. + +2011-07-05 Vladimir Serbinenko + + MIPS qemu flash support. + + * grub-core/boot/mips/startup_raw.S [GRUB_MACHINE_MIPS_QEMU_MIPS]: Check + magic. + * grub-core/kern/mips/qemu_mips/init.c (probe_mem): New function. + (grub_machine_init): Probe memory if its size isn't known. + * util/grub-mkimage.c (image_targets): Add flash targets. + (generate_image): Handle flash targets. + +2011-07-05 Vladimir Serbinenko + + MIPS qemu at_keyboard support. + + * gentpl.py (videoinkernel): Add qemu-mips. + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Add necessary headers. + * grub-core/Makefile.core.def (kernel): Add at_keyboard and layout. + * grub-core/kern/mips/qemu_mips/init.c (grub_machine_init): Init new + modules. + * grub-core/term/at_keyboard.c (grub_keyboard_controller_init) + [GRUB_MACHINE_MIPS_QEMU_MIPS]: Don't consider original set. + * grub-core/term/serial.c (grub_serial_register) + [GRUB_MACHINE_MIPS_QEMU_MIPS]: Make com0 explicitly active. + +2011-07-05 Vladimir Serbinenko + + CMOS support on sparc. + + * gentpl.py (cmos): Add powerpc and sparc. + * grub-core/Makefile.core.def (datetime): Add lib/ieee1275/cmos.c on + powerpc and sparc. + * grub-core/lib/cmos_datetime.c (grub_get_datetime) + [__powerpc__ || __sparc__]: Rename to grub_get_datetime_cmos. + (grub_set_datetime) [__powerpc__ || __sparc__]: Likewise to + grub_set_datetime_cmos. + * grub-core/lib/ieee1275/cmos.c: New file. + * grub-core/lib/ieee1275/datetime.c (no_ieee1275_rtc): New vaiable. + (find_rtc): Set no_ieee1275_rtc on error. + (grub_get_datetime): Call grub_get_datetime_cmos on error. + (grub_set_datetime): Call grub_set_datetime_cmos on error. + * include/grub/cmos.h (grub_cmos_read): Return grub_err_t since it may + fail. Move value to argument. All users updated + (grub_cmos_write): Likewise. + (grub_cmos_read) [__powerpc__ || __sparc__]: Rewritten. + (grub_cmos_write) [__powerpc__ || __sparc__]: Likewise. + * include/grub/datetime.h [__powerpc__ || __sparc__]: Declare + grub_get_datetime_cmos and grub_set_datetime_cmos. + +2011-07-02 Grégoire Sutre + + * util/grub-mkconfig.in: Use @PACKAGE@ instead of hardcoded name when + sourcing grub-mkconfig_lib. + * util/update-grub_lib.in: Likewise. + * util/grub.d/00_header.in: Likewise. + * util/grub.d/10_hurd.in: Likewise. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub.d/10_netbsd.in: Likewise. + * util/grub.d/10_windows.in: Likewise. + * util/grub.d/20_linux_xen.in: Likewise. + * util/grub.d/30_os-prober.in: Likewise. + +2011-06-28 Colin Watson + + * grub-core/term/gfxterm.c (grub_virtual_screen_setup): Use + default_bg_color rather than black. + (grub_gfxterm_fullscreen): Likewise. + (grub_gfxterm_background_color_cmd): Save new background color in + default_bg_color. + +2011-06-27 Vladimir Serbinenko + + * grub-core/Makefile.core.def (chain): Fix coreboot filename. + +2011-06-27 Vladimir Serbinenko + + * grub-core/disk/pata.c (grub_pata_initialize) [QEMU_MIPS]: Fix a + mismerge. + +2011-06-27 Vladimir Serbinenko + + Chainloading on coreboot support. + + * grub-core/Makefile.core.def (chain): Add coreboot. + * grub-core/loader/i386/coreboot/chainloader.c: New file. + +2011-06-27 Vladimir Serbinenko + + * grub-core/loader/i386/bsd.c (grub_bsd_load): Handle relocator failure + if it happens. + +2011-06-27 Vladimir Serbinenko + + Implement time command. + + * grub-core/Makefile.core.def (time): New module. + * grub-core/commands/time.c: New file. + * grub-core/script/parser.y: Remove "time" keyword. + * grub-core/script/yylex.l: Likewise. + +2011-06-27 Vladimir Serbinenko + + * include/grub/loader.h (grub_loader_unregister_preboot_hook): Export. + +2011-06-27 Vladimir Serbinenko + + * grub-core/lib/relocator.c (malloc_in_range): Fix a memory corruption + when handling leftovers. + +2011-06-27 Vladimir Serbinenko + + * util/ieee1275/grub-ofpathname.c (main): Handle --help and --version + so that help2man doesn't fail. + +2011-06-27 Vladimir Serbinenko + + * grub-core/net/drivers/ieee1275/ofnet.c (send_card_buffer) Use right + type in pointers on sparc64. + (get_card_packet): Likewise. + +2011-06-27 Colin Watson + + * grub-core/commands/videoinfo.c (hook): Indicate current video mode + with `*'. + (grub_cmd_videoinfo): Fetch current video mode. + +2011-06-27 Vladimir Serbinenko + + * grub-core/disk/scsi.c (grub_scsi_read): Limit SCSI reads to 32K + because of underlying system restrictions. + +2011-06-27 Vladimir Serbinenko + + * util/grub-mkrescue.in: Rename "ata" to "pata" and add ahci when + necessary. + +2011-06-27 Vladimir Serbinenko + + Coreboot video support. + + * grub-core/Makefile.core.def (vga): Extend to coreboot and multiboot. + (vbe): Likewise. + * grub-core/kern/i386/coreboot/startup.S: Include int.S. + * grub-core/kern/i386/pc/startup.S (grub_bios_interrupt): Moved from + here ... + * grub-core/kern/i386/int.S: ... here. + * grub-core/video/i386/pc/vbe.c: Updated includes. + * grub-core/video/i386/pc/vga.c: Likewise. + * include/grub/i386/coreboot/memory.h + (GRUB_MEMORY_MACHINE_SCRATCH_ADDR): New definition. + (GRUB_MEMORY_MACHINE_SCRATCH_SEG): Likewise. + (GRUB_MEMORY_MACHINE_SCRATCH_SIZE): Likewise. + * include/grub/i386/pc/int.h (GRUB_CPU_INT_FLAGS_DEFAULT) [!PCBIOS]: + Disable interrupts. + * include/grub/i386/pc/vga.h: Removed. All users updated. + +2011-06-27 Vladimir Serbinenko + + * grub-core/disk/ahci.c (grub_ahci_readwrite_real): Use proper + definitions for dprintf. + * grub-core/disk/pata.c (grub_pata_readwrite): Likewise. + +2011-06-27 Vladimir Serbinenko + + * grub-core/net/drivers/ieee1275/ofnet.c (send_card_buffer): Fix + prototype. + (get_card_packet): Likewise. + +2011-06-26 Yves Blusseau + + Display the path of the file when file is not found + + * grub-core/fs/fat.c: Display the filename when file is not found. + * grub-core/fs/fshelp.c: Likewise. + * grub-core/fs/hfs.c: Likewise. + * grub-core/fs/jfs.c: Likewise. + * grub-core/fs/minix.c: Likewise. + * grub-core/fs/ufs.c: Likewise. + * grub-core/fs/btrfs.c: Likewise. + * grub-core/commands/i386/pc/play.c: Likewise. + +2011-06-26 Szymon Janc + + * grub-core/commands/cmp.c (grub_cmd_cmp): Remove unnecessary NULL + pointer checks before calling grub_free(). + * grub-core/commands/wildcard.c (match_devices): Likewise. + * grub-core/commands/wildcard.c (match_files): Likewise. + * grub-core/fs/cpio.c (grub_cpio_dir): Likewise. + * grub-core/fs/cpio.c (grub_cpio_open): Likewise. + * grub-core/fs/udf.c (grub_udf_read_block): Likewise. + * grub-core/fs/xfs.c (grub_xfs_read_block): Likewise. + * grub-core/loader/efi/chainloader.c (grub_cmd_chainloader): Likewise. + * grub-core/normal/cmdline.c (grub_cmdline_get): Likewise. + * grub-core/script/yylex.l (grub_lexer_unput): Likewise. + * grub-core/video/readers/jpeg.c (grub_video_reader_jpeg): Likewise. + * grub-core/video/readers/png.c (grub_png_output_byte): Likewise. + +2011-06-25 Patrick + + * grub-core/kern/main.c (grub_load_normal_mode): Correct the comment. + +2011-06-25 Vladimir Serbinenko + + * grub-core/net/i386/pc/pxe.c (grub_pxe_recv): Fix declaration. + (grub_pxe_send): Likewise. + (GRUB_MOD_INIT): Fix types. + +2011-06-24 Szymon Janc + + * grub-core/io/xzio.c: Fix code style issues + +2011-06-24 Vladimir Serbinenko +2011-06-24 Manoel Rebelo Abranches + + Network infrastructure. + The ARP protocol was made by Paulo Pinatti + + * include/grub/net/arp.h: New file. + * include/grub/net/device.h: Likewise. + * include/grub/net/ethernet.h: Likewise. + * include/grub/net/ip.h: Likewise. + * include/grub/net/netbuff.h: Likewise. + * include/grub/net/tftp.h: Likewise. + * include/grub/net/udp.h: Likewise. + * include/grub/ieee1275/ofnet.h: Likewise. + * include/grub/emu/export.h: Likewise. + * include/grub/net.h: Likewise. + * grub-core/net/arp.c: Likewise. + * grub-core/net/ethernet.c: Likewise. + * grub-core/net/ip.c: Likewise. + * grub-core/net/udp.c: Likewise. + * grub-core/net/tftp.c: Likewise. + * grub-core/net/netbuff.c: Likewise. + * grub-core/net/net.c: Likewise. + * grub-core/net/drivers/emu/emunet.c: Likewise. + * grub-core/net/drivers/ieee1275/ofnet.c: Likewise. + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Add net.h, ofnet.h and + export.h. + * grub-core/Makefile.core.def (net): New module. + (tftp): Likewise. + (ofnet): Likewise. + (emunet): Likewise. + * grub-core/commands/ls.c (grub_ls_list_devices) [!GRUB_UTIL]: List + network protocols. + * grub-core/kern/device.c (grub_net_open) : New variable. + (grub_device_open): Handle network device. + (grub_device_close): Likewise. + * grub-core/kern/file.c (grub_file_net_seek) : New variable. + (grub_grubnet_fini): Likewise. + (grub_file_seek): Seek in network device. + * grub-core/kern/fs.c (grub_fs_probe): Handle network devices. + * grub-core/kern/ieee1275/init.c (grub_machine_set_prefix): Handle + network root. + (grub_machine_fini): Call grub_grubnet_fini. + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_parse_args): Handle + network. + (grub_ieee1275_get_aliasdevname): New function. + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_get_mbi_size): + Add unofficial Solaris network info. + (grub_multiboot_make_mbi): Likewise. + * grub-core/fs/i386/pc/pxe.c: Moved from here ... + * grub-core/net/i386/pc/pxe.c: ...here. Adapted for new design. + * include/grub/device.h (grub_fs): Removed. + * include/grub/err.h (grub_err_t): Add network-related values. + * include/grub/i386/pc/pxe.h: Removed bootp parts. + * include/grub/ieee1275/ieee1275.h (grub_ofnetcard_data): New struct. + (grub_ieee1275_get_aliasdevname): New proto. + * include/grub/net.h: Rewritten. + +2011-06-24 Vladimir Serbinenko + + * grub-core/disk/raid.c (insert_array): Ensure uniqueness of readable + names. + +2011-06-24 Vladimir Serbinenko + + * grub-core/commands/wildcard.c (match_files): Add a useful dprintf. + (wildcard_expand): Don't stop on nonregexp parts after regexp ones since + it truncates the output. + Reported by: Ximin Luo. + +2011-06-24 Vladimir Serbinenko + + * grub-core/fs/iso9660.c (grub_iso9660_iterate_dir): Skip . and .. + +2011-06-24 Vladimir Serbinenko + + * util/grub-mkconfig_lib.in (prepare_grub_to_access_device): Load + partmap before abstraction. + +2011-06-24 Alexander Kurtz + + * util/grub-mkconfig_lib.in: Add missing quotes. + +2011-06-24 Vladimir Serbinenko + + * grub-core/kern/emu/getroot.c (grub_guess_root_device): Revert to + old method if mountinfo would return /dev/root and /dev/root doesn't + exist. + +2011-06-24 Vladimir Serbinenko + + ZFS zlib support + + * grub-core/fs/zfs/zfs.c (zlib_decompress): New function. + (decomp_table): Add zlib entries. + (zio_read): USe 8 bits for compression function rather than 3. + * include/grub/zfs/zio.h (zio_compress): Add zlib values. + +2011-06-24 Vladimir Serbinenko + + * grub-core/disk/ahci.c: Add missing license statements. + * grub-core/fs/romfs.c: Likewise. + * grub-core/lib/ia64/setjmp.S: Likewise. + * grub-core/loader/i386/pc/freedos.c: Likewise. + * grub-core/loader/ia64/efi/linux.c: Likewise. + * grub-core/video/colors.c: Likewise. + * include/grub/dl.h (GRUB_MOD_DEP): New macro. + +2011-06-23 Vladimir Serbinenko + + AHCI support. + + * grub-core/Makefile.core.def (ata_pthru): Removed. + (ahci): New module. + (pata): Likewise. + * grub-core/bus/usb/ohci.c (GRUB_MOD_FINI): Unregister preboot hook + on unload. + * grub-core/commands/hdparm.c (grub_hdparm_do_ata_cmd): Use ATA + readwrite. + (grub_hdparm_do_check_powermode_cmd): Likewise. + (grub_hdparm_do_smart_cmd): Likewise. + (grub_hdparm_set_val_cmd): Likewise. + (grub_cmd_hdparm): Likewise. Check thta we have an ATA device. + * grub-core/disk/ahci.c: New file. + * grub-core/disk/ata.c: Factor out the low-level part into ... + * grub-core/disk/pata.c: ... here. + * grub-core/disk/ata_pthru.c: Contents moved to ... + * grub-core/disk/pata.c: ... here. + * grub-core/disk/scsi.c (grub_scsi_names): New array. + (grub_scsi_iterate): Use grub_scsi_names. + (grub_scsi_open): Likewise. + * grub-core/kern/disk.c (grub_disk_ata_pass_through): Removed. + * include/grub/ata.h (grub_ata_commands): Add DMA commands. + (grub_ata_regs_t): New struct. + (grub_disk_ata_pass_through_parms): Likewise. + (grub_ata_device): Renamed to ... + (grub_ata): ... this. + (grub_ata_dev): New struct. + Removed all low-level inline functions. + * include/grub/scsi.h: Add PATA and AHCI subsystems. + (grub_scsi_dev): Removed 'name' and 'id'. Added 'id' parameter to + iterate hooks and open. All users updated. + * util/grub-install.in: Handle AHCI disk module. + +2011-06-23 Szymon Janc + + Add support for DRI and RSTn markers in JPEG files. + + * grub-core/video/readers/jpeg.c (JPEG_MARKER_DRI): New define. + (JPEG_MARKER_RST0): Likewise. + (JPEG_MARKER_RST1): Likewise. + (JPEG_MARKER_RST2): Likewise. + (JPEG_MARKER_RST3): Likewise. + (JPEG_MARKER_RST4): Likewise. + (JPEG_MARKER_RST5): Likewise. + (JPEG_MARKER_RST6): Likewise. + (JPEG_MARKER_RST7): Likewise. + (grub_jpeg_data): New fields dri, r1, bitmap_ptr. + (grub_jpeg_decode_dri): New function. + (grub_jpeg_decode_sos): Move image data related part into + grub_jpeg_decode_data function. + (grub_jpeg_decode_data): New function. + (grub_jpeg_reset): New function. + (grub_jpeg_decode_jpeg): Handle new markers. + +2011-06-23 Vladimir Serbinenko + + * util/ieee1275/ofpath.c (check_sas): Close fd. + (main): Free of_path. + Reported by: David Volgyes . + +2011-06-23 Vladimir Serbinenko + + * util/grub-mkpasswd-pbkdf2.c (main): Don't double-close. + Reported by: David Volgyes . + +2011-06-23 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy): Close + file after stat. + Reported by: David Volgyes . + +2011-06-23 Vladimir Serbinenko + + * util/raid.c (grub_util_raid_getmembers): Close fd before returning. + + Reported by: David Volgyes . + +2011-06-23 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (rs_recover) [STANDALONE]: + Prevent memory leak. + +2011-06-23 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (rs_recover): Prevent memory leak. + (main): Close file. + Reported by: David Volgyes . + +2011-06-23 Vladimir Serbinenko + + * grub-core/loader/i386/xnu.c (grub_cpu_xnu_fill_devprop): Don't attempt + to continue if allocation is failed. + + Reported by: David Volgyes . + +2011-06-23 David Volgyes + + * grub-core/bus/usb/ohci.c (grub_ohci_pci_iter): Avoid NULL-pointer + dereference. + +2011-06-23 Vladimir Serbinenko + + Fix spurious warning. + + * grub-core/partmap/acorn.c (grub_acorn_boot_block): Make a union. + (acorn_partition_map_find): Use .bin member. + +2011-06-23 Vladimir Serbinenko + + * grub-core/kern/emu/getroot.c (grub_guess_root_device): Don't accept + /dev/root as a valid device. + +2011-06-23 Jim Meyering + + Avoid NULL deref in grub_device_open. + + * grub-core/kern/device.c (grub_device_open): Don't dereference + a NULL pointer upon failed grub_env_get. + +2011-06-23 Vladimir Serbinenko + + Support non-512B sectors and agglomerate reads. + + * Makefile.util.def (libgrubmods.a): Add grub-core/commands/testload.c. + * grub-core/disk/efi/efidisk.c (grub_efidisk_data): Remove disk_io. + (disk_io_guid): Removed. + (make_devices): Locate solely by BlockIO. + (grub_efidisk_open): Fill log_sector_size and total_sectors. + (grub_efidisk_read): Use read_blocks. + (grub_efidisk_write): Use write_blocks. + * grub-core/disk/i386/pc/biosdisk.c (grub_biosdisk_open): Fill + log_sector_size. + (get_safe_sectors): Handle non-512B sectors. + (grub_biosdisk_read): Remove special CDROM handling. Handle non-512B + sectors. + (grub_biosdisk_write): Handle non-512B sectors. + * grub-core/disk/scsi.c (grub_scsi_open): Fill log_sector_size. + (grub_scsi_read): Remove special non-512B block handling (now handled + one level up). + * grub-core/kern/disk.c (grub_disk_open): Fill default log_sector_size + and do sanity checks. + (grub_disk_adjust_range): Handle non-512B sectors. + (transform_sector): New function. + (grub_disk_read_small): Likewise. + (grub_disk_read): Rewritten. + (grub_disk_write): Handle non-512B sectors. + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_open): Fill + log_sector_size. + (open_device): Use log_sector_size. + (grub_util_biosdisk_read): Likewise. + (grub_util_biosdisk_write): Likewise. + * grub-core/partmap/msdos.c (grub_partition_msdos_iterate): Handle + non-512B sectors. + (pc_partition_map_embed): Likewise. + * include/grub/disk.h (grub_disk): New field log_sector_size. + (GRUB_DISK_CACHE_SIZE): Redefined from GRUB_DISK_CACHE_BITS. + (GRUB_DISK_CACHE_BITS): Increased to 6. + * util/grub-fstest.c (fstest): New command testload. + (argp_parser): Likewise. + +2011-06-16 Robert Millan + + Detect `ataraid' devices on GNU/kFreeBSD. Fix for ATA devices using + `ata' driver on kernel of FreeBSD 9. + + * util/deviceiter.c [__FreeBSD_kernel__] (get_ada_disk_name) + (get_ataraid_disk_name): New functions. + [__FreeBSD_kernel__] (grub_util_iterate_devices): Scan for ataraid + (/dev/ar[0-9]+) and ada (/dev/ada[0-9]+) devices using + get_ataraid_disk_name() and get_ada_disk_name(). + +2011-06-13 Colin Watson + + * docs/man/grub-mklayout.h2m (DESCRIPTION): Add a reference to the + input format. + +2011-05-29 Colin Watson + + * docs/grub.texi (Obtaining and Building GRUB): Substitute + `ftp.gnu.org' for `alpha.gnu.org'. + +2011-05-27 Colin Watson + + * grub-core/kern/emu/hostdisk.c (linux_find_partition): Handle + partitions under /dev/disk/by-id/. + +2011-05-27 Colin Watson + + * grub-core/kern/emu/hostdisk.c (linux_find_partition): Give up + after ten consecutive open failures. Scanning all the way up to + 10000 is excessive and can cause serious performance problems in + some configurations. + Fixes Ubuntu bug #787461. + +2011-05-21 Vladimir Serbinenko + + * grub-core/disk/arc/arcdisk.c (reopen): Close old handle before + opening new one. + +2011-05-21 Colin Watson +2011-05-21 Vladimir Serbinenko + + Don't stat devices unless we have to. + + * grub-core/kern/emu/getroot.c (grub_find_device): Recognize + dir == /dev/mapper. + (grub_guess_root_device): Use already known os_dev if possible. + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Scan only in /dev/mapper + if device is known to be a dm one. + +2011-05-20 Colin Watson + + * util/grub-mkconfig.in: Export GRUB_CMDLINE_LINUX_XEN_REPLACE and + GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT. + Reported by: Pawel Tecza. + +2011-05-19 Vladimir Serbinenko + + * grub-core/Makefile.core.def (lsacpi): Fix ia64 mismerge. + (lsefisystab): Likewise. + (lssal): Likewise. + (lsefimmap): Likewise. + (hdparm): Enable on qemu-mips. + (setjmp): Add ia64 nodist. + (serial): Simplify tags. + +2011-05-18 Colin Watson + + * Makefile.util.def (grub-ofpathname): Install manual page. + +2011-05-18 Colin Watson + + * grub-core/fs/squash4.c: Add missing GRUB_MOD_LICENSE. + +2011-05-18 Colin Watson + + * .bzrignore: Add grub-core/modinfo.sh and a number of test files. + +2011-05-18 Vladimir Serbinenko + + * grub-core/bus/usb/usbhub.c (poll_nonroot_hub): Downgrade a printf + into dprintf. + +2011-05-18 Vladimir Serbinenko + + Use full 64-bit division. + + * grub-core/kern/misc.c (grub_divmod64_full): Renamed to ... + (grub_divmod64): ... this. + * include/grub/misc.h (grub_divmod64): Removed. All users switch to full + version. + +2011-05-18 Colin Watson + + * util/grub-mkrescue.in: Use portable `.' rather than non-portable + `source'. + +2011-05-18 Colin Watson + + * grub-core/genmod.sh.in: Use 'set -e' rather than '#! /bin/sh -e', + to avoid accidents when debugging with 'sh -x'. + * grub-core/gensyminfo.sh.in: Likewise. + * tests/example_scripted_test.in: Likewise. + * tests/grub_cmd_regexp.in: Likewise. + * tests/grub_script_blanklines.in: Likewise. + * tests/grub_script_dollar.in: Likewise. + * tests/grub_script_expansion.in: Likewise. + * tests/grub_script_final_semicolon.in: Likewise. + * tests/partmap_test.in: Likewise. + * tests/util/grub-shell-tester.in: Likewise. + * tests/util/grub-shell.in: Likewise. + +2011-05-18 Colin Watson + + Move gfxmenu color handling to video, so that gfxterm can use it + too. + + * grub-core/gfxmenu/named_colors.c: Move to ... + * grub-core/video/colors.c: ... here. Rename + grub_gui_get_named_color to grub_video_get_named_color. + * grub-core/gfxmenu/gui_string_util.c (my_isxdigit): Move to ... + * grub-core/video/colors.c (my_isxdigit): ... here. + * grub-core/gfxmenu/gui_string_util.c (parse_hex_color_component): + Move to ... + * grub-core/video/colors.c (parse_hex_color_component): ... here. + * grub-core/gfxmenu/gui_string_util.c (grub_gui_parse_color): Move + to ... + * grub-core/video/colors.c (grub_video_parse_color): ... here. + + * include/grub/gui.h (grub_gui_color_t): Move to ... + * include/grub/video.h (grub_video_rgba_color_t): ... here. + * include/grub/gui.h (grub_gui_color_rgb): Move to ... + * include/grub/video.h (grub_video_rgba_color_rgb): ... here. + * include/grub/gui.h (grub_gui_map_color): Move to ... + * include/grub/video.h (grub_video_map_rgba_color): ... here. + * include/grub/gui_string_util.h (grub_gui_get_named_color): Move + to ... + * include/grub/video.h (grub_video_get_named_color): ... here. + * include/grub/gui_string_util.h (grub_gui_parse_color): Move to ... + * include/grub/video.h (grub_video_parse_color): ... here. + + * grub-core/Makefile.core.def (kernel) [videoinkernel]: Add + video/colors.c. + (gfxmenu): Remove gfxmenu/named_colors.c. + (video) [videomodules]: Add video/colors.c. + + Add a background_color command. + + * grub-core/term/gfxterm.c (grub_gfxterm_background_color_cmd): New + function. + (GRUB_MOD_INIT): Register background_color command. + (GRUB_MOD_FINI): Unregister background_color command. + (redraw_screen_rect): Allow blend/replace of text layer to be + controlled independently from whether there is a background bitmap. + (grub_gfxterm_background_image_cmd): Change blend_text_bg when + changing bitmap. + +2011-05-18 Vladimir Serbinenko + + Patch BPB in ntldr and chainloader --bpb. + + * grub-core/fs/fat.c: Include grub/fat.h. + (grub_fat_bpb): Moved to ... + * include/grub/fat.h (grub_fat_bpb): ... here. New file. + * grub-core/loader/i386/pc/chainloader.c: Include grub/fat.h and + grub/ntfs.h. + * include/grub/i386/pc/chainloader.h (grub_chainloader_flags_t): + Moved from here... + * grub-core/loader/i386/pc/chainloader.c (grub_chainloader_flags_t): ... + here. + * grub-core/loader/i386/pc/chainloader.c (grub_chainloader_patch_bpb): + New function. + (grub_chainloader_cmd): Patch BPB if --bpb is given. + (GRUB_MOD_INIT): Show --bpb. + * grub-core/loader/i386/pc/ntldr.c (grub_cmd_ntldr): Patch BPB. + * grub-core/normal/main.c (features): New variable. + (GRUB_MOD_INIT): Set feature_* variables. + * include/grub/i386/pc/chainloader.h (grub_chainloader_patch_bpb): New + proto. + * include/grub/ntfs.h (grub_ntfs_bpb): New field bios_drive. + +2011-05-18 Vladimir Serbinenko + + * grub-core/Makefile.core.def (ieee1275_fb): Use enable=powerpc_ieee1275 + for cleanness. + +2011-05-18 Vladimir Serbinenko + + FreeDOS direct loading support. + + * docs/grub.texi (Supported OS): Add FreeDOS. + * grub-core/Makefile.core.def (freedos): New module. + * grub-core/lib/i386/relocator.c (grub_relocator16_ebx): New extern + variable. + (grub_relocator16_boot): Handle %ebx. + * grub-core/lib/i386/relocator16.S: Likewise. + * grub-core/loader/i386/pc/freedos.c: New file. + +2011-05-18 Vladimir Serbinenko + + Long Linux command line support. + + * grub-core/loader/i386/linux.c (GRUB_LINUX_CL_END_OFFSET): Removed. + (maximal_cmdline_size): New variable. + (allocate_pages): Use maximal_cmdline_size. + (grub_cmd_linux): Set and use maximal_cmdline_size. + * grub-core/loader/i386/pc/linux.c (GRUB_LINUX_CL_END_OFFSET): Removed. + (allocate_pages): Use maximal_cmdline_size. + (grub_cmd_linux): Set and use maximal_cmdline_size. + * include/grub/i386/linux.h (GRUB_LINUX_SETUP_MOVE_SIZE): Removed. + (linux_kernel_header): Add fields kernel_alignment, relocatable, pad + and cmdline_size. + +2011-05-18 Vladimir Serbinenko +2011-05-18 Colin Watson + + Improve devmapper support + + * grub-core/kern/emu/getroot.c (grub_util_is_dmraid): Removed. + (grub_util_is_lvm): New function. + (grub_util_get_dev_abstraction): Assume dmraid if not lvm rather + than lvm if not dmraid. + Handle mapped md nodes. + * grub-core/kern/emu/hostdisk.c (device_is_mapped): Rename to ... + (grub_util_device_is_mapped): ... this. Make always available. All users + updated. + (grub_util_get_dm_node_linear_info) [HAVE_DEVICE_MAPPER]: New function. + (convert_system_partition_to_system_disk): Handle lvm, mpath and + dmraid nodes. + * include/grub/emu/misc.h (grub_util_device_is_mapped): New proto. + +2011-05-18 Vladimir Serbinenko + + Unify grub-mkrescue (except powerpc) and grrub-mknetdir across platforms + + * grub-core/Makefile.am (platform_DATA): Add modinfo.sh. + * grub-core/modinfo.sh.in: New file. + * grub-core/Makefile.core.def (modinfo.sh): New script. + * util/grub-mknetdir.in: Use modinfo.sh. + * util/grub-mkrescue.in: Likewise. + +2011-05-17 Vladimir Serbinenko + + * grub-core/kern/ia64/dl_helper.c (grub_ia64_dl_get_tramp_got_size): + Fix potential usage of Elf32 instead of Elf64 when compiling on + 32-bit architecture. Add endianness macros while on it. + +2011-05-17 Vladimir Serbinenko + + Use mipsel- rather than mips- in directories involving mipsel ports to + allow both endiannesses coexist. + + * configure.ac: proparate target_cpu=mipsel rather than resetting to + mips. All conditions adjusted. + * tests/util/grub-shell-tester.in: Remove gratuitious target_cpu + variable. + * util/grub-install.in: Adjust conditions to take renaming into account. + * util/grub-mkimage.c (image_targets): Likewise. New target + mips-qemu_mips-elf for bigendian mips. + +2011-05-17 Vladimir Serbinenko + + Avoid unnecessary copying on MIPS. + + * grub-core/boot/decompressor/none.c (grub_decompress_core): Exit + early if src == dest. + * util/grub-mkimage.c (generate_image): Arange for src == dest if + compression is none. + +2011-05-17 Vladimir Serbinenko + + Reduce memory footprint on SGI by putting modules before the kernel + as opposed to after. + + * grub-core/Makefile.core.def (kernel): Increase linking address. + (none_decompress): Likewise. + (xz_decompress): Likewise. + * grub-core/boot/mips/startup_raw.S: Use prewritten uncompression + address. + * grub-core/kern/mips/arc/init.c (grub_machine_init): Handle memory + layout change. + (grub_arch_modules_addr): New function. + * grub-core/kern/mips/init.c (grub_arch_modules_addr): Moved from here... + * grub-core/kern/mips/loongson/init.c (grub_arch_modules_addr): .. here + * grub-core/kern/mips/qemu_mips/init.c (grub_arch_modules_addr): ... and + here. + * grub-core/kern/mips/startup.S (total_size): Rename to ... + (grub_total_modules_size): ... this. Make global. + [GRUB_MACHINE_ARC]: Don't attempt to move modules out of the bss. + * include/grub/offsets.h (GRUB_KERNEL_MIPS_LOONGSON_UNCOMPRESSED_ADDR): + New definition. + (GRUB_KERNEL_MIPS_QEMU_MIPS_UNCOMPRESSED_ADDR): Likewise. + (GRUB_KERNEL_MIPS_ARC_UNCOMPRESSED_ADDR): Likewise. + (GRUB_KERNEL_MACHINE_UNCOMPRESSED_ADDR): Likewise. + (GRUB_KERNEL_MIPS_ARC_LINK_ADDR): Increased. + * util/grub-mkimage.c (image_target_desc): New flag + PLATFORM_FLAGS_MODULES_BEFORE_KERNEL. + (image_targets): Set PLATFORM_FLAGS_MODULES_BEFORE_KERNEL on mips-arc. + (generate_image): Handle images with modules before kernel. + +2011-05-17 Vladimir Serbinenko + + Prevent potential loss of memory map by overwrite on qemu-mips. + + * grub-core/boot/mips/startup_raw.S [GRUB_MACHINE_MIPS_QEMU_MIPS]: + Save ram size in $s4. + * grub-core/kern/mips/qemu_mips/init.c (RAMSIZE): Removed. + All users changed to grub_arch_memsize. + * grub-core/kern/mips/startup.S (grub_arch_machine): Restrict to + Loongson. + [GRUB_MACHINE_MIPS_QEMU_MIPS]: Save grub_arch_memsize. + * grub-core/loader/mips/linux.c (grub_linux_boot): Pass memory size. + * include/grub/mips/qemu_mips/memory.h (grub_arch_memsize): New + external variable. + +2011-05-17 Colin Watson + + * .bzrignore: Remove grub-dumpbios. + +2011-05-17 Colin Watson + + * util/grub.d/20_linux_xen.in: Honour GRUB_CMDLINE_LINUX_XEN_REPLACE + and GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT, which replace + GRUB_CMDLINE_LINUX and GRUB_CMDLINE_LINUX_DEFAULT (complementing the + existing options which append). + * docs/grub.texi (Simple configuration): Document new options. + Reported by: Ian Jackson. Fixes Debian bug #617538. + +2011-05-17 Colin Watson + + * util/grub-fstest.c (cmd_cat): New function. + (fstest): Handle CMD_CAT. + (options): Add cat. + (argp_parser): Handle cat. + +2011-05-17 Colin Watson + + * Makefile.util.def (grub-bin2h): Don't install. + * docs/man/grub-bin2h.h2m: Remove. + +2011-05-17 Vladimir Serbinenko + + * grub-core/kern/mips/startup.S (grub_arch_cpuclock): Move to the right + place. + +2011-05-17 Vladimir Serbinenko + + Reenable qemu-mips port. + + * configure.ac: Handle --target=qemu-mips and --target=qemu_mips. + Fix small arc bug while on it. + * gentpl.py: Handle qemu_mips. + * grub-core/Makefile.am: Likewise. + * grub-core/Makefile.core.def: Likewise. + * grub-core/disk/ata.c [GRUB_MACHINE_MIPS_QEMU_MIPS]: Remove + inappropriate includes. + (grub_ata_pciinit) [GRUB_MACHINE_MIPS_QEMU_MIPS]: Removed. + (grub_ata_initialize): [GRUB_MACHINE_MIPS_QEMU_MIPS]: Rewritten. + * grub-core/kern/main.c (grub_modules_get_end) + [GRUB_MACHINE_MIPS_QEMU_MIPS]: Enable. + * grub-core/kern/mips/qemu-mips: Moved to .. + * grub-core/kern/mips/qemu_mips: ... this. + * grub-core/kern/mips/qemu_mips/init.c (grub_get_rtc): Removed. + (grub_machine_init): Call terminfo_init and serial_init. + * grub-core/kern/mips/startup.S: Change MIPS_LOONGSON to MACHINE. + * grub-core/loader/mips/linux.c (params) [GRUB_MACHINE_MIPS_QEMU_MIPS]: + New variable. + (grub_linux_boot) [GRUB_MACHINE_MIPS_QEMU_MIPS]: Handle the qemu-mips + parameter passing. + (grub_linux_unload) [GRUB_MACHINE_MIPS_QEMU_MIPS]: Free params. + (grub_cmd_linux) [GRUB_MACHINE_MIPS_QEMU_MIPS]: Handle params. + (grub_cmd_initrd) [GRUB_MACHINE_MIPS_QEMU_MIPS]: Likewise. + * include/grub/mips/qemu_mips/cmos.h: New file. + * include/grub/mips/qemu-mips/kernel.h: Don't include cpu/kernel.h. + * include/grub/mips/qemu-mips/memory.h (grub_machine_mmap_iterate): + Removed. + * include/grub/mips/qemu-mips/serial.h (GRUB_MACHINE_SERIAL_PORTS): + Use correct mips-style address. + * include/grub/mips/qemu-mips/time.h: Include cpu/time.h. + (GRUB_TICKS_PER_SECOND): Removed. + (grub_get_rtc): Likewise. + (grub_cpu_idle): Likewise. + * include/grub/offsets.h (GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR): + New definition. + (GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_COMPRESSED_SIZE): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_UNCOMPRESSED_SIZE): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX_END): Likewise. + (GRUB_KERNEL_MIPS_QEMU_MIPS_MOD_ALIGN): Likewise. + * util/grub-mkimage.c (image_targets): Add mipsel-qemu_mips-elf. + +2011-05-17 Vladimir Serbinenko + + SGI ARCS port. + + * Makefile.util.def (libgrubmods.a): Add dvh.c. + * conf/Makefile.common (CCASFLAGS_PLATFORM): Add -mips3 on all mips + platforms. + * configure.ac: New target mips-arc. + * gentpl.py: Likewise. + * grub-core/Makefile.am: Likewise. + * grub-core/Makefile.core.def: Likewise. + (xz_decompress): Remove -D GRUB_MACHINE_LINK_ADDR. + (none_decompress): Likewise. + (lsdev): New module. + (datetime): Use lib/arc/datetime.c on ARC. + (part_dvh): New module. + * grub-core/commands/arc/lsdev.c: New file. + * grub-core/disk/arc/arcdisk.c: Likewise. + * grub-core/kern/mips/arc/init.c: Likewise. + * grub-core/kern/mips/cache_flush.S: Don't flush non 4-byte + aligned addresses. + * grub-core/kern/mips/dl.c (grub_arch_dl_check_header): Fix bigendian + support. + (grub_arch_dl_relocate_symbols): Likewise. + * grub-core/kern/mips/loongson/init.c (grub_get_rtc): Moved from here... + * grub-core/kern/mips/init.c (grub_get_rtc): ... here. + * grub-core/kern/mips/startup.S (grub_arch_cpuclock): Have on all + platforms. + * grub-core/lib/arc/datetime.c: New file. + * grub-core/loader/mips/linux.c: Always include time.h. Don't include + pci.h on non-loongson. + (envp_off) [!GRUB_MACHINE_MIPS_LOONGSON]: Remove. + (grub_linux_boot): Set unused registers to 0. + (grub_cmd_linux) [!GRUB_MACHINE_MIPS_LOONGSON]: Remove envp. + * grub-core/mmap/mips/loongson/uppermem.c: Moved from here ... + * grub-core/mmap/mips/uppermem.c: ...here. + * grub-core/partmap/dvh.c: New file. + * grub-core/term/arc/console.c: Likewise. + * grub-core/term/terminfo.c (ANSI_C0_STR): New const. + (grub_terminfo_set_current): Add terminal "arc". + (grub_terminfo_readkey): Support ARC sequences. + * include/grub/arc/arc.h: New file. + * include/grub/arc/console.h: Likewise. + * include/grub/disk.h (grub_disk_dev_id): Add + GRUB_DISK_DEVICE_ARCDISK_ID. + * include/grub/mips/arc/kernel.h: New file. + * include/grub/mips/arc/memory.h: Likewise. + * include/grub/mips/arc/time.h: Likewise. + * include/grub/mips/loongson/kernel.h (grub_halt): Moved from here ... + * include/grub/mips/kernel.h (grub_halt): ... here. + * include/grub/mips/loongson.h (GRUB_CPU_REGISTER_WRAP): Moved from + here... + * include/grub/mips/mips.h (GRUB_CPU_REGISTER_WRAP): ... here. + (GRUB_CPU_LOONGSON_COP0_TIMER_COUNT): Moved from here ... + * include/grub/mips/mips.h (GRUB_CPU_LOONGSON_COP0_TIMER_COUNT): .. here + * include/grub/mips/loongson/kernel.h (grub_reboot): Removed redundant + proto. + * include/grub/mips/loongson/memory.h (GRUB_ARCH_LOWMEMVSTART): Moved + from here ... + * include/grub/mips/memory.h (GRUB_ARCH_LOWMEMVSTART): ... here. + (GRUB_ARCH_LOWMEMPSTART): Moved from here ... + * include/grub/mips/memory.h (GRUB_ARCH_LOWMEMPSTART): ... here. + (GRUB_ARCH_LOWMEMMAXSIZE): Moved from here ... + * include/grub/mips/memory.h (GRUB_ARCH_LOWMEMMAXSIZE): ... here. + (GRUB_ARCH_HIGHMEMPSTART): Moved from here ... + * include/grub/mips/memory.h (GRUB_ARCH_HIGHMEMPSTART): ... here. + (grub_phys_addr_t): Moved from here ... + * include/grub/mips/memory.h (grub_phys_addr_t): ... here. + (grub_vtop): Moved from here ... + * include/grub/mips/memory.h (grub_vtop): ... here. + (grub_map_memory): Moved from here ... + * include/grub/mips/memory.h (grub_map_memory): ... here. + (grub_unmap_memory): Moved from here ... + * include/grub/mips/memory.h (grub_unmap_memory): ... here. + (grub_machine_mmap_iterate): Moved from here ... + * include/grub/mips/memory.h (grub_machine_mmap_iterate): ... here. + (grub_mmap_get_lower): Moved from here ... + * include/grub/mips/memory.h (grub_mmap_get_lower): ... here. + (grub_mmap_get_upper): Moved from here ... + * include/grub/mips/memory.h (grub_mmap_get_upper): ... here. + * include/grub/mips/loongson/time.h (grub_arch_cpuclock): Moved from + here ... + * include/grub/mips/time.h (grub_arch_cpuclock): ... here. + * include/grub/mips/loongson/time.h (grub_get_rtc): Moved from + here ... + * include/grub/mips/time.h (grub_get_rtc): ... here. + * include/grub/mips/loongson/time.h (grub_arch_cpuclock): Moved from + here ... + * include/grub/mips/time.h (grub_arch_cpuclock): ... here. + * include/grub/mips/loongson/time.h (grub_cpu_idle): Moved from + here ... + * include/grub/mips/time.h (grub_cpu_idle): ... here. + * include/grub/offsets.h (GRUB_KERNEL_MIPS_ARC_LINK_ADDR): New + definition. + (GRUB_KERNEL_MIPS_ARC_LINK_ALIGN): Likewise. + (GRUB_KERNEL_MIPS_ARC_COMPRESSED_SIZE): Likewise. + (GRUB_KERNEL_MIPS_ARC_UNCOMPRESSED_SIZE): Likewise. + (GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE): Likewise. + (GRUB_KERNEL_MIPS_ARC_PREFIX): Likewise. + (GRUB_KERNEL_MIPS_ARC_PREFIX_END): Likewise. + (GRUB_KERNEL_MIPS_ARC_MOD_ALIGN): Likewise. + (GRUB_MACHINE_LINK_ADDR): Likewise. + * include/grub/terminfo.h (GRUB_TERMINFO_READKEY_MAX_LEN): Increased + to 6. + * util/grub-install.in: Run dvhtool on ARC. + * util/grub-mkimage.c (image_targets): Add mips-arc. + (generate_image): Handle ECOFF output for mips-arc. + +2011-05-16 Vladimir Serbinenko + + * grub-core/bus/pci.c (grub_memalign_dma32): Always allocate in 64-byte + blocks. + +2011-05-16 Vladimir Serbinenko + + * grub-core/bus/usb/usbhub.c (attach_root_port): Wait 10ms + after enabling port. + +2011-05-16 Vladimir Serbinenko + + Skip incorrect USB devices. + + * grub-core/bus/usb/usb.c (grub_usb_device_initialize): Fail if + configcnt == 0. + * include/grub/usb.h (grub_usb_err_t): New enum value + GRUB_USB_ERR_BADDEVICE. + +2011-05-16 Vladimir Serbinenko + + Fuloong video init support. + + * include/grub/vga.h (grub_vga_write_arx): inb monochrome address as + well. + (grub_vga_read_arx): New function. + * grub-core/video/sis315pro.c (GRUB_SIS315PRO_MMIO_SPACE): New + definition. + (framebuffer): New members io, mmioptr and mmiobase. + (read_sis_cmd): New function. + (write_sis_cmd): Likewise. + (grub_video_sis315pro_setup): Do the initialisation. Use 640x480 + rather than 640x400. + * grub-core/video/sis315_init.c: New file. + +2011-05-15 Vladimir Serbinenko + + * grub-core/bus/cs5536.c: Don't include grub/machine/kernel.h on + non-loongson. + * grub-core/kern/mips/dl.c (grub_arch_dl_init_linker): Fix argument + to grub_dl_register_symbol. + +2011-05-15 Vladimir Serbinenko + + Fix compilation errors. + + * grub-core/term/ns8250.c (serial_get_divisor): Declare 'port' as + potentially unused. + * grub-core/loader/i386/linux.c (grub_linux_setup_video): + Handle GRUB_VIDEO_DRIVER_SIS315PRO. + * grub-core/bus/cs5536.c (grub_cs5536_init_geode): Restrict DIVIL init + to loongson machines. + +2011-05-15 Vladimir Serbinenko + + Several FS mtime support. + + * grub-core/fs/affs.c (grub_affs_time): New struct. + (grub_affs_file): New field mtime. + (grub_fshelp_node): Changed 'block' and 'parent' to more appropriate + type. Removed 'size'. New field 'di'. All users updated. + (grub_affs_mount): Simplify checsum checking. + (grub_affs_iterate_dir): New helper grub_affs_create_node. + (grub_affs_dir): Handle mtime. + * grub-core/fs/cpio.c (grub_cpio_find_file): Handle mtime. + (grub_cpio_dir): Likewise. + * grub-core/fs/hfs.c (grub_hfs_dirrec): New fields 'ctime' and 'mtime'. + (grub_hfs_filerec): New field mtime. + (grub_hfs_dir): Handle mtime. + (grub_hfs_mtime): New function. + (grub_hfs_fs): Register grub_hfs_mtime. + * grub-core/fs/iso9660.c (grub_iso9660_date2): New struct. + (grub_iso9660_dir): New field mtime. + (grub_fshelp_node): New field dirent. + (iso9660_to_unixtime): New function. + (iso9660_to_unixtime2): Likewise. + (grub_iso9660_read_symlink): Use node->dirent. + (grub_iso9660_iterate_dir): Likewise. + (grub_iso9660_dir): Set mtime. + (grub_iso9660_mtime): New function. + (grub_iso9660_fs): Register grub_iso9660_mtime. + * grub-core/fs/jfs.c (grub_jfs_time): New struct. + (grub_jfs_inode): New fields atime, ctime and mtime. + (grub_jfs_dir): Set mtime. + * grub-core/fs/minix.c (grub_minix_dir): Likewise. + * grub-core/fs/ntfs.c (list_file): Set mtime. + (grub_ntfs_dir): Likewise. + * grub-core/fs/reiserfs.c (grub_fshelp_node): New field 'mtime'. + (grub_reiserfs_iterate_dir): Set mtime. + (grub_reiserfs_dir): Likewise. + * grub-core/fs/sfs.c (grub_sfs_obj): New field mtime. + (grub_fshelp_node): Likewise. + (grub_sfs_iterate_dir): Set mtime. + (grub_sfs_dir): Likewise. + * grub-core/fs/udf.c (grub_udf_dir): Set mtime. + * grub-core/fs/xfs.c (grub_xfs_time): New struct. + (grub_xfs_inode): New fields atime, mtime, ctime. + (grub_xfs_dir): Set mtime. + * include/grub/datetime.h (grub_datetime2unixtime): New function. + * include/grub/hfs.h (grub_hfs_sblock): New fields ctime and mtime. + * include/grub/ntfs.h (grub_fshelp_node): New field mtime. + + Support UDF symlinks. + + * grub-core/fs/udf.c (grub_udf_iterate_dir): Handle symlinks. + (grub_ufs_read_symlink): New function. All users updated. + + Check amiga partmap checksum. + + * grub-core/partmap/amiga.c (grub_amiga_rdsk): Pad to 128 bytes. + (grub_amiga_partition): Likewise. + (amiga_partition_map_checksum): New function. + (amiga_partition_map_iterate): Check checksum. + +2011-05-15 Vladimir Serbinenko + + ROMFS support. + + * Makefile.util.def (libgrubmods.a): Add romfs. + * grub-core/Makefile.core.def (romfs): New module. + * grub-core/fs/romfs.c: New file. + +2011-05-15 Vladimir Serbinenko + + Squashfs v4 support. + + * Makefile.util.def (libgrubmods.a): Add squash4. + * grub-core/Makefile.core.def (squash4): New module. + * grub-core/fs/squash4.c: New file. + * grub-core/io/gzio.c (grub_gzio): New members disk_input_off, + disk_input_start, disk_input. + (get_byte): Handle disk_input. + (grub_zlib_disk_read): New function. + * include/grub/deflate.h (grub_zlib_disk_read): New proto. + +2011-05-15 Vladimir Serbinenko +2011-05-15 Feiran Zheng + + * Makefile.util.def (libgrubmods.a): Add minix3. + * grub-core/Makefile.core.def (minix3): New module. + * grub-core/fs/minix.c (GRUB_MINIX_MAGIC) [MODE_MINIX3]: New value. + (GRUB_MINIX_BSIZE): Removed. + (GRUB_MINIX_INODE_DIR_BLOCKS): New definition. All users updated. + (grub_minix_ino_t): New type. + (grub_minix_le_to_cpu_ino): New macro. + (GRUB_MINIX_ZONE2SECT): New definition. All users updated. + (grub_minix_sblock) [MODE_MINIX3]: Change for minix3. + (grub_minix_data): New field block_size. + (grub_minix_read_file): Handle 64-bit correctly. + * grub-core/fs/minix3.c: New file. + +2011-05-15 Tristan Gingold +2011-05-15 Robert Millan +2011-05-15 Vladimir Serbinenko + + IA64 support. + + * Makefile.util.def (libgrubmods.a): Add grub-core/kern/ia64/dl_helper.c + * configure.ac: Add ia64-efi target. + Probe for __ia64_trampoline, __udivsi3, __umoddi3, __udivdi3, + __divsi3, __modsi3, __umodsi3, __moddi3 and __divdi3 symbols. + * gentpl.py: Add ia64_efi platform. + Rename x86_efi to efi and Add ia64-efi. All users updated. + * grub-core/Makefile.am: Set KERNEL_HEADER_FILES for ia64-efi. + * grub-core/Makefile.core.def (kernel.img): Add compile flags for ia64. + Remove kern/generic/rtc_get_time_ms.c on EFI. + Add kern/ia64/efi/startup.S, kern/ia64/efi/init.c, kern/ia64/dl.c, + kern/ia64/dl_helper.c on ia64-efi. + Add kern/emu/cache.c on emu. + (linux): Use on loader/ia64/efi/linux.c on ia64. + * grub-core/gensymlist.sh (grub_register_exported_symbols): Check + whether symbol is a function. + * grub-core/kern/dl.c [GRUB_MACHINE_EMU]: Include sys/mman.h. + (grub_symbol): New field 'isfunc'. + (grub_dl_resolve_symbol): Return whole symbol rather than just address. + (grub_dl_register_symbol): New argument 'isfunc'. All users updated. + (grub_dl_load_segments): Place all sections into the same region. + [__ia64__]: Create trampolines and got. + [GRUB_MACHINE_EMU]: Call mprotect. + (grub_dl_resolve_symbols): Resolve symbol type as well. + [__ia64__]: Create function descriptors. + * grub-core/kern/efi/efi.c (grub_get_rtc): Renamed to ... + (grub_rtc_get_time_ms): ... this. Expressions simplified. + (grub_get_rtc): New function. + * grub-core/kern/emu/cache.c [__ia64__]: New file. + * grub-core/kern/emu/cache.S: Renamed to ... + * grub-core/kern/emu/cache_s.S: ... this. + [__ia64__]: Add a nop. + * grub-core/kern/emu/full.c (grub_arch_dl_get_tramp_got_size) + [__ia64__]: New function. + * grub-core/kern/emu/lite.c [__ia64__]: Include ../ia64/dl.c. + * grub-core/kern/ia64/dl.c: New file. + * grub-core/kern/ia64/dl_helper.c: Likewise. + * grub-core/kern/ia64/efi/init.c: New file. + * grub-core/kern/ia64/efi/startup.S: Likewise. + * grub-core/lib/efi/halt.c [__ia64__]: Don't try acpi. + * grub-core/lib/ia64/longjmp.S: New file (from glibc). + * grub-core/lib/ia64/setjmp.S: Likewise (from glibc). + * grub-core/lib/setjmp.S [__ia64__]: Include ./ia64/setjmp.S. + * grub-core/loader/ia64/efi/linux.c: New file. + * include/grub/dl.h (GRUB_MOD_NAME): Redefined using C rather than asm. + (GRUB_MOD_DEP): Likewise. + (grub_dl) [__ia64__]: New fields got and tramp. + (grub_dl): New field 'base'. + (grub_dl_register_symbol): New argument isfunc. All users updated. + (GRUB_IA64_DL_TRAMP_ALIGN): New definition. + (GRUB_IA64_DL_TRAMP_SIZE): Likewise. + (GRUB_IA64_DL_GOT_ALIGN): Likewise. + (grub_ia64_dl_get_tramp_got_size): New proto. + (GRUB_ARCH_DL_TRAMP_ALIGN) [__ia64__]: Likewise + (GRUB_ARCH_DL_GOT_ALIGN) [__ia64__]: Likewise + (grub_arch_dl_get_tramp_got_size) [__ia64__]: Likewise + * include/grub/efi/api.h: Skip call wrappers on ia64. + * include/grub/efi/pe32.h (GRUB_PE32_MACHINE_IA64): New definition. + * include/grub/efi/time.h (GRUB_TICKS_PER_SECOND): Change to 1000. + * include/grub/elf.h (ELF_ST_INFO): New definition. + * include/grub/ia64/efi/kernel.h: New file. + * include/grub/ia64/efi/memory.h: Likewise. + * include/grub/ia64/efi/time.h: Likewise. + * include/grub/ia64/kernel.h: Likewise. + * include/grub/ia64/setjmp.h: Likewise (from glibc). + * include/grub/ia64/time.h: New file. + * include/grub/ia64/types.h: Likewise. + * include/grub/libgcc.h (__udivsi3, __umodsi3, __umoddi3, __udivdi3, + __moddi3, __divdi3, __divsi3, __modsi3, __ia64_trampoline): + New protos. + * include/grub/offsets.h (GRUB_KERNEL_IA64_EFI_PREFIX): New definition. + (GRUB_KERNEL_IA64_EFI_PREFIX_END): Likewise. + * include/grub/types.h (PRIxGRUB_ADDR): Likewise. + * util/grub-mkimage.c (image_target_desc): New field pe_target. + All users updated. + (EFI64_HEADER_SIZE): New definition. All users updated. + (image_targets): Add ia64-efi. + * util/grub-mkimagexx.c (relocate_symbols): New arguments jumpers and + jumpers_addr. All users updated. + Create function descriptors. + (count_funcs): New function. + (unaligned_uint32): New struct. + (MASK20): New definition. + (MASK19): Likewise. + (MASKF21): Likewise. + (add_value_to_slot_20b): New function. + (add_value_to_slot_21_real): Likewise. + (add_value_to_slot_21): Likewise. + (ia64_kernel_trampoline): New struct. + (nopm): New variable. + (jump): Likewise. + (make_trampoline): New function. + (relocate_addresses): Handle ia64. + (make_reloc_section): Likewise. + (load_image): Likewise. + +2011-05-15 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_read_logical): Silence spurious + warning. Move variables before code while on it. + +2011-05-15 Vladimir Serbinenko + + Fuloong support. + + * configure.ac: Rename yeeloong platform to loongson. All users updated. + * grub-core/Makefile.core.def (fwstart_fuloong): New image. + * grub-core/boot/mips/loongson/fuloong.S: New file. + * grub-core/boot/mips/loongson/fwstart.S: Wait for CS5536 to come up. + Explicitly init CS5536. + [FULOONG]: Don't use serial until CS5536 is available. + Set GPIO based on dumps. + (serial_hw_init) [FULOONG]: Handle CS5536 parts. + [FULOONG]: Handle GPIO and memory controller differences. + Parse machine type in $a2. + * grub-core/boot/mips/startup_raw.S: Determine and save the + architecture. + * grub-core/bus/cs5536.c (gpiodump): Move to fwstart.S. + (grub_cs5536_init_geode): Remove gpio part. Conditionalise DIVIL + init on architecture type. + * grub-core/kern/mips/loongson/init.c (grub_machine_init): Init + SIS315E. Don't init at_keyboard on fuloong. + (grub_halt): Support Fuloong. + * grub-core/kern/mips/startup.S [LOONGSON]: Save $s7. + * grub-core/loader/mips/linux.c (LOONGSON_MACHTYPE): Removed. + (loongson_machtypes): New array. + (grub_cmd_linux) [GRUB_MACHINE_MIPS_LOONGSON]: Pass the right machine + type. + * grub-core/term/ns8250.c (serial_get_divisor): New parameter port and + config. All users updated. Handle CS5536 serial. + * grub-core/term/serial.c (grub_serial_register): Conditionalise + default port on machine type. Register serial as inactive. + * grub-core/video/sis315pro.c: New file. + * include/grub/cs5536.h (GRUB_CS5536_MSR_MAILBOX_CONFIG_ENABLED): New + definition. + (GRUB_CS5536_MSR_MAILBOX_CONFIG): Likewise. + (GRUB_CS5536_MSR_DIVIL_LEG_IO_UART1_COM1): Likewise. + (GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3): Likewise. + (GRUB_CS5536_MSR_DIVIL_UART1_CONF): Likewise. + (GRUB_CS5536_MSR_DIVIL_UART2_CONF): Likewise. + * include/grub/mips/loongson.h (GRUB_CPU_LOONGSON_SHUTDOWN_GPIO): Rename + to ... + (GRUB_CPU_YEELOONG_SHUTDOWN_GPIO): ... this. + * include/grub/mips/loongson/kernel.h (GRUB_ARCH_MACHINE_YEELOONG): New + definition. + (GRUB_ARCH_MACHINE_FULOONG): Likewise. + (grub_arch_machine): New extern var. + * include/grub/mips/loongson/serial.h + (GRUB_MACHINE_SERIAL_DIVISOR_115200): Renamed to ... + (GRUB_MACHINE_SERIAL_PORT0_DIVISOR_115200): ... this. + (GRUB_MACHINE_SERIAL_PORT): Renamed to ... + (GRUB_MACHINE_SERIAL_PORT0): ... this. + (GRUB_MACHINE_SERIAL_PORT2_DIVISOR_115200): New definition. + (GRUB_MACHINE_SERIAL_PORT1): Likewise. + (GRUB_MACHINE_SERIAL_PORT2): Likewise. + (GRUB_MACHINE_SERIAL_PORTS): Include ports 1 and 2. + * include/grub/term.h (grub_term_register_input_inactive): New inline + function. + (grub_term_register_output_inactive): Likewise. + * include/grub/video.h (grub_video_driver_id): New value + GRUB_VIDEO_DRIVER_SIS315PRO. + * util/grub-mkimage.c (image_target_desc): Rename name to dirname. + New field "names". All users updated. + New field value IMAGE_FULOONG_FLASH. + (generate_image): USe separate fwstart hashes for yeeloong and fuloong. + +2011-05-14 Jordan Uggla + + * docs/grub.texi (Invoking grub-install): Fix additional outdated claims + and add some clarification. + +2011-05-14 Vladimir Serbinenko + + * util/grub.d/10_linux.in: Autoload gzio since it's needed on some + platforms if kernel is compressed. + +2011-05-14 Vladimir Serbinenko + + * grub-core/kern/mm.c (grub_memalign): Disable auto-unloadding of + unused modules since currently referrence counter isn't reliable and + there isn't much memory to recover there anyway. + +2011-05-14 Vladimir Serbinenko + + * grub-core/kern/dl.c (grub_dl_load_file): Decrease ref counter + rather than resetting it to allow modules to reference themselves + in init. + +2011-05-14 Vladimir Serbinenko + + * grub-core/kern/dl.c (grub_dl_unload): Don't decrease reference + counter on dependencies since grub_dl_unref already handles this. + +2011-05-14 Vladimir Serbinenko + + * grub-core/font/font_cmd.c (loadfont_command): Set grub_errno + on error if not already done. + +2011-05-14 Vladimir Serbinenko + + Fix few potential memory misusage. + + * grub-core/font/font.c (load_font_index): Don't free char_index to + avoid double free. + (grub_font_load): Zero-fill font at alloc for safety. + Close file on error. + (free_font): Free bmp_idx. + +2011-05-14 Vladimir Serbinenko + + * docs/grub.texi (Installation): Fix several outdated claims. + +2011-05-14 Vladimir Serbinenko + + Handle module_license on windows. + + * util/grub-pe2elf.c (MODLICENSE_SECTION): New definition. All following + sections shifted. + (insert_string): Make argument const char * instead of char *. + (write_section_data): Handle long section names. + Handle module_license. + +2011-05-14 Vladimir Serbinenko + + * grub-core/commands/menuentry.c (grub_cmd_menuentry): Correctly + handle class-free menuentries. + (grub_normal_add_menu_entry): Add a check to be sure. + +2011-05-14 Vladimir Serbinenko + + * grub-core/term/at_keyboard.c (set1_e0_mapping): Fix swap between + PgUp and PgDown. + +2011-05-13 Vladimir Serbinenko + + * configure.ac: Bump version to 1.99. + +2011-05-13 Vladimir Serbinenko + + Give ATA device a bit more time on first try in order to allow disks + to spin up. + + * grub-core/disk/ata.c (grub_atapi_identify): Use GRUB_ATA_TOUT_DEV_INIT + if dev->present is 1. Reset dev->present on failure. + (grub_ata_device_initialize): Set dev->present to 1. + * include/grub/ata.h (GRUB_ATA_TOUT_DEV_INIT): New value. + (grub_ata_device): New member 'present'. + +2011-05-13 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Update hash. + +2011-05-13 Vladimir Serbinenko + + Flush caches on DMA memory. + + * grub-core/kern/mips/cache.S (grub_arch_sync_dma_caches): New function. + * grub-core/bus/pci.c (grub_memalign_dma32): Flush caches. + (grub_dma_free): Likewise. + * include/grub/cache.h (grub_arch_sync_dma_caches): New declaration. + +2011-05-13 Vladimir Serbinenko + + * grub-core/boot/mips/yeeloong/fwstart.S: Add explicit set mips3 + to avoid asm treating ld and sd as macros. + +2011-05-13 Vladimir Serbinenko + + * grub-core/boot/mips/startup_raw.S: Flush cache after loading + decompressor. + +2011-05-13 Vladimir Serbinenko + + * grub-core/boot/mips/startup_raw.S: Use jalr rather than bal to call + grub_decompress_core since later would fail if grub_decompress_core + is too far. + +2011-05-13 Vladimir Serbinenko + + * grub-core/kern/mips/dl.c (grub_arch_dl_relocate_symbols): Handle + R_MIPS_JALR since it's used by newer compiler. + +2011-05-10 Vladimir Serbinenko + + * util/grub.d/10_linux.in: Correctly handle the Linux in root. + +2011-05-09 Vladimir Serbinenko + + * grub-core/loader/efi/chainloader.c (grub_chainloader_unload): Set + file_path to 0 for surety. + (grub_chainloader_boot): Set exit_data to NULL. + Unset the loader once done. + (grub_cmd_chainloader): Fix confusing error message if file is empty. + +2011-05-09 Vladimir Serbinenko + + * grub-core/term/at_keyboard.c (fetch_key): Make a printf on + unknown key into a dprintf. + +2011-05-09 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (linux_find_partition): Don't abort + on first non-existant partition. + +2011-05-09 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (open_device): Set data->fd to -1 if + openning fails. + Reported by: Mark Korenberg. + +2011-05-09 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (linux_find_partition): Prevent possible + overflow. + +2011-05-09 Vladimir Serbinenko + + * util/grub-mkimage.c (main): Explicitely flush and sync the output + before closing to ensure that it will be readable by grub-setup. + +2011-05-05 Vladimir Serbinenko + + * grub-core/loader/efi/appleloader.c (MAKE_PIWG_PATH): New macro. + (devpath_1): Use MAKE_PIWG_PATH. + (devpath_2): Likewise. + (devpath_3): Likewise. + (devpath_4): Likewise. + (devpath_5): Likewise. + (devpath_6): Likewise. + + The appleldr.mod was checked that to be binary identical to previous + version. + +2011-05-05 Zach + + Support 2010 Macbooks. + + * grub-core/loader/efi/appleloader.c (devpath_6): New variable. + (devs): Add devpath_6. + +2011-05-05 Vladimir Serbinenko + + * util/grub-mkpasswd-pbkdf2.c (main): Use /dev/urandom and not + /dev/random. /dev/urandom is good enough for our purposes (salting). + +2011-05-05 Vladimir Serbinenko + + * util/grub-mkrescue.in (process_input_dir): Include efiemu??.o. + +2011-05-05 Vladimir Serbinenko + + * grub-core/lib/legacy_parse.c (grub_legacy_parse): Correctly handle + hexadecimal. + +2011-05-05 Vladimir Serbinenko + + * grub-core/efiemu/main.c (grub_efiemu_load_file): Return grub_errno + and not 0 on failure. + +2011-05-03 Colin Watson + + * grub-core/fs/i386/pc/pxe.c (grub_pxefs_dir): Return + GRUB_ERR_BAD_FS rather than GRUB_ERR_IO if the disk is not a pxe + disk; otherwise grub_fs_probe will not fall back to the next + filesystem. + (grub_pxefs_open): Likewise, for consistency. + Reported and tested by: Ezekiel Grave. + +2011-05-03 Colin Watson + + * tests/partmap_test.in: Don't hardcode path to parted. + Reported by: Peter Hjalmarsson. Fixes Savannah bug #33150. + +2011-05-01 Colin Watson + + * docs/grub.texi (GRUB only offers a rescue shell): Suggest the use + of `ls' to find out which devices are available. + +2011-04-25 Vladimir Serbinenko + + * grub-core/loader/i386/linux.c (grub_linux_boot): Supply target rather + than source address for efi mmap buffer. + +2011-04-25 Vladimir Serbinenko + + * grub-core/partmap/amiga.c (amiga_partition_map_iterate): Fix a + wrong action on non-detecting the magic. + +2011-04-25 Vladimir Serbinenko + + * grub-core/gnulib/regex.c: Remove GRUB_MOD_LICENSE since it's + already supplied by another part of the module (fixes compilation on + FreeBSD). + +2011-04-25 Vladimir Serbinenko + + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Make mdraid UUID + match the one used by mdadm. + +2011-04-21 Colin Watson + + * po/README: Add instructions for creating po/LINGUAS. + +2011-04-21 Colin Watson + + Add "SEE ALSO" sections to most man pages. Fixes Debian bug + #551428. + + * docs/man/grub-editenv.h2m (SEE ALSO): New section. + * docs/man/grub-emu.h2m (SEE ALSO): Likewise. + * docs/man/grub-fstest.h2m (SEE ALSO): Likewise. + * docs/man/grub-install.h2m (SEE ALSO): Likewise. + * docs/man/grub-macho2img.h2m (SEE ALSO): Likewise. + * docs/man/grub-menulst2cfg.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkconfig.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkdevicemap.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkfont.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkimage.h2m (SEE ALSO): Likewise. + * docs/man/grub-mklayout.h2m (SEE ALSO): Likewise. + * docs/man/grub-mknetdir.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkpasswd-pbkdf2.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkrelpath.h2m (SEE ALSO): Likewise. + * docs/man/grub-mkrescue.h2m (SEE ALSO): Likewise. + * docs/man/grub-ofpathname.h2m (SEE ALSO): Likewise. + * docs/man/grub-pe2elf.h2m (SEE ALSO): Likewise. + * docs/man/grub-probe.h2m (SEE ALSO): Likewise. + * docs/man/grub-reboot.h2m (SEE ALSO): Likewise. + * docs/man/grub-script-check.h2m (SEE ALSO): Likewise. + * docs/man/grub-set-default.h2m (SEE ALSO): Likewise. + * docs/man/grub-setup.h2m (SEE ALSO): Likewise. + +2011-04-21 Colin Watson + + * grub-core/kern/emu/getroot.c + (grub_find_root_device_from_mountinfo): Remove non-virtual-device + test that was incorrectly reintroduced in r3214. + Reported by: Ian Dall. Fixes Savannah bug #33133. + +2011-04-21 Colin Watson + + Fix stack pointer handling in 16-bit relocator. + + * grub-core/lib/i386/relocator16.S (grub_relocator16_start): Move + grub_relocator16_sp to %esp rather than %ss, and zero-extend it. + Fixes Ubuntu bug #683904. + +2011-04-20 Vladimir Serbinenko + + * configure.ac: Bump version to 1.99~rc2. + +2011-04-20 Vladimir Serbinenko + + * include/grub/dl.h [ASM_FILE]: Adapt for assembly. + * grub-core/lib/i386/setjmp.S: Add missing GRUB_MOD_LICENSE. + * grub-core/lib/x86_64/setjmp.S: Likewise. + * grub-core/lib/mips/setjmp.S: Likewise. + * grub-core/lib/powerpc/setjmp.S: Likewise. + * grub-core/lib/sparc64/setjmp.S: Likewise. + +2011-04-20 Vladimir Serbinenko + + * grub-core/lib/efi/datetime.c: Add missing GRUB_MOD_LICENSE. + * grub-core/lib/efi/datetime.c: Likewise. + +2011-04-19 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_flush): + New function. + (grub_util_biosdisk_close): Use grub_util_biosdisk_flush. + * include/grub/emu/hostdisk.h (grub_util_biosdisk_flush): New proto. + * util/grub-setup.c (setup): Use grub_util_biosdisk_flush. + +2011-04-19 Vladimir Serbinenko + + * grub-core/term/gfxterm.c (grub_gfxterm_fullscreen): Preserve previous + bitmap. + (grub_gfxterm_term_init): Likewise. + +2011-04-19 Vladimir Serbinenko + + Take into account the decorations the computing menu entry width. + + * grub-core/gfxmenu/widget-box.c (get_border_width): New function. + (grub_gfxmenu_create_box): Register get_border_width. + * grub-core/gfxmenu/gui_list.c (draw_menu): Use get_border_width + if available. + * include/grub/gfxwidgets.h (grub_gfxmenu_box): New member + get_border_width. + +2011-04-18 Endres Puschner + + * grub-core/gfxmenu/icon_manager.c (grub_gfxmenu_icon_manager_get_icon): + Don't skip first class. + +2011-04-18 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_read_logical): Support huge + chunks. + * include/grub/err.h (grub_err_t): New enum value GRUB_ERR_BUG. + +2011-04-18 Vladimir Serbinenko + + Complete 64-bit division support. + + * grub-core/kern/misc.c (grub_divmod64): Rename to ... + (grub_divmod64_full): ... this. Support 64-bit divisor and reminder. + * include/grub/misc.h (grub_divmod64): Rename to ... + (grub_divmod64_full): ... this. + (grub_divmod64): New inline function. + +2011-04-18 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Add forgotten comma. + +2011-04-18 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Update fwstart.img hash after + performing the necessary test. + +2011-04-17 Vladimir Serbinenko + + * Makefile.am (multiboot.elf): Add -Wl,--build-id=none. + (kfreebsd.elf): Likewise. + (pc-chainloader.elf): Likewise. + (ntldr.elf): Likewise. + +2011-04-17 Vladimir Serbinenko + + Identify RAID by its UUID rather than (guessed) name. + + * grub-core/disk/raid.c (ascii2hex): New function. + (grub_raid_open): Accept mduuid/%s specification. + * grub-core/kern/emu/getroot.c (get_mdadm_name): Revamped into ... + (get_mdadm_uuid): ... this. + (grub_util_get_grub_dev): Use mduuid/%s if UUID is available. + +2011-04-16 Vladimir Serbinenko + + * grub-core/gfxmenu/gui_image.c (rescale_image): Don't attempt to scale + to negative size. + +2011-04-13 Colin Watson + + * util/grub.d/10_linux.in: Add rootflags=subvol= if / is on a + btrfs subvolume. + * util/grub.d/20_linux_xen.in: Likewise. + +2011-04-13 Colin Watson + + Rewrite /proc/self/mountinfo handling to cope with bind-mounts and + move-mounts appearing out of order. Fixes Ubuntu bug #738345. + + * grub-core/kern/emu/getroot.c (find_root_device_from_mountinfo): + Build a list of relevant visible mounts using the mnt_id and + parent_mnt_id fields, and then scan that list at the end. + +2011-04-12 Colin Watson + + * docs/grub.texi (normal): New section. + (normal_exit): New section. + (Embedded configuration): Add reference to normal. + (GRUB only offers a rescue shell): Likewise. + * docs/grub-dev.texi (Error Handling): Fix typo. + +2011-04-12 Colin Watson + + * NEWS: Drop obsolete entry about probe-only btrfs support. + +2011-04-12 Colin Watson + + * util/import_gcry.py: Fix typo. + +2011-04-11 Vladimir Serbinenko + + * NEWS: Add btrfs support. + +2011-04-11 Vladimir Serbinenko +2011-04-11 Colin Watson + + BtrFS support. Written by me (Vladimir) with important bugfixes and + even more important testing by Colin. + + * Makefile.util.def (libgrubmods.a): Add crc.c and gzio.c + * grub-core/Makefile.core.def (btrfs): Add crc.c. + * grub-core/fs/btrfs.c: Stub replaced with real implementation. + * grub-core/io/gzio.c (grub_gzio): New fields mem_input_size, + mem_input_off and mem_input. All users updated to accept in-RAM input. + (gzio_seek): New function. + (test_zlib_header): Likewise. + (grub_gzio_read): Likewise. + (grub_zlib_decompress): Likewise. + * grub-core/kern/emu/getroot.c (grub_find_root_device_from_mountinfo): + Accept partial and non-virtual mounts. + (grub_guess_root_device): Do rescanning after device_from_mountinfo to + avoid receiving /dev/dm-X as device. + * grub-core/kern/emu/misc.c (grub_make_system_path_relative_to_its_root): + Handle bind and partial mounts. + * grub-core/lib/crc.c: New file. + * include/grub/deflate.h: Likewise. + * include/grub/emu/misc.h (grub_find_root_device_from_mountinfo): New + proto. + * include/grub/lib/crc.h: New file. + +2011-04-11 Vladimir Serbinenko + + Implement automatic module license checking according to new GNU + guidelines. + + * grub-core/kern/dl.c (grub_dl_check_license): New function. + (grub_dl_load_core): Use grub_dl_check_license. + * include/grub/dl.h (GRUB_MOD_SECTION): New macro. + (GRUB_MOD_LICENSE): Likewise. + (GRUB_MOD_DUAL_LICENSE): Likewise. + All modules updated. + +2011-04-11 Colin Watson + + * grub-core/fs/btrfs.c (grub_btrfs_fs) [GRUB_UTIL]: Set + reserved_first_sector to 1. btrfs reserves plenty of space for boot + loaders. + Reported by: Gene Cumm. Fixes Ubuntu bug #757446. + +2011-04-11 Vladimir Serbinenko + + * util/grub-fstest.c (cmd_cmp): Check that sizes match. + +2011-04-11 Vladimir Serbinenko + + * util/grub-fstest.c (read_file): Report GRUB error if file opening + failed. + +2011-04-11 Vladimir Serbinenko + + * grub-core/kern/file.c (grub_file_open): Don't take into account the + parenthesis in the middle of the filename. + +2011-04-10 Vladimir Serbinenko + + * grub-core/loader/mips/linux.c (grub_cmd_initrd): Use correct limits + rather than trying to put initrd way too high. + Reported by: Ryan Lortie + +2011-04-10 Vladimir Serbinenko + + * grub-core/boot/mips/yeeloong/fwstart.S (no_cs5536): Put back + improperly removed string. + +2011-04-10 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_data): New member + is_disk. + (grub_util_biosdisk_open): Don't apply ioctl on non-disk devices. + (open_device) Likewise. + (grub_util_biosdisk_close): Likewise. + Reported by: Mark Korenberg. + +2011-04-10 Alexander Kurtz + + * util/grub-mkconfig_lib.in: Add missing quotes. + +2011-04-10 Colin Watson + + * grub-core/gnulib/argp-parse.c (__argp_input): Don't crash if pstate + is NULL. + +2011-04-10 Vladimir Serbinenko + + Dynamically count the number of lines for the lower banner. + + * grub-core/normal/menu_entry.c (per_term_screen): New member + num_entries. + (print_down): Use num_entries. + (update_screen): Likewise. + (grub_menu_entry_run): Set num_entries. + * grub-core/normal/menu_text.c (menu_viewer_data): New member + num_entries. + (grub_print_message_indented): Move real part to ... + (grub_print_message_indented_real): ... here. Additional argument + dry_run. + (draw_border): Additional argument num_entries. + (print_message): Additional argument dry_run. + (print_entries): Receive menu viewer data. + (grub_menu_init_page): New argment num_entries. + (menu_text_set_chosen_entry): Use num_entries. + (grub_menu_try_text): Likewise. + * grub-core/normal/term.c (print_ucs4_terminal): New argument dry_run. + All users updated. + (grub_ucs4_count_lines): New function. + * include/grub/term.h (grub_term_cursor_x): Moved from here .. + * grub-core/normal/menu_text.c (grub_term_cursor_x): ... to here. + * include/grub/term.h (GRUB_TERM_MESSAGE_HEIGHT): Removed. + (grub_term_border_height): Likewise. + (grub_term_num_entries): Likewise. + +2011-04-10 Vladimir Serbinenko + + * grub-core/boot/mips/yeeloong/fwstart.S: Fix address to error message. + Remove now unused string. + +2011-04-09 Colin Watson + + * docs/grub-dev.texi (Finding your way around): Update for 1.99 + build system. + (Getting started): GRUB is developed in Bazaar now, not Subversion. + + (Comment): Fix typo. + (Getting started): General copy-editing. + (Typical Development Experience): Likewise. + (Error Handling): Likewise. + (Video API): Likewise. + +2011-04-09 Colin Watson + + * docs/grub-dev.texi: Replace MoinMoin syntax with Texinfo syntax + throughout. + +2011-04-08 Vladimir Serbinenko + + * util/grub-mkimage.c (main): Handle special naming of yeeloong + directory. + +2011-04-08 Colin Watson + + * docs/grub-dev.texi: Fix spelling of "developer" throughout. + * grub-core/fs/i386/pc/pxe.c (parse_dhcp_vendor): Fix spelling of + "development". + +2011-04-08 Vladimir Serbinenko + + * grub-core/normal/menu_entry.c (run): Use grub_memcpy rather than + grub_strcpy since the lines aren't necessarily 0-terminated. + +2011-04-08 Vladimir Serbinenko + + * grub-core/lib/legacy_parse.c (legacy_commands): Find doesn't set + root on legacy. + +2011-04-08 Vladimir Serbinenko + + * grub-core/commands/probe.c (options): Argument to set isn't optional. + (GRUB_MOD_INIT): DEVICE isn't optional. + +2011-04-08 Vladimir Serbinenko + + * grub-core/normal/term.c (print_ucs4_terminal): Don't try to put the + word on new line if it's too long anyway. Fixes a hang. + +2011-04-08 Vladimir Serbinenko + + * include/grub/util/raid.h (grub_util_raid_getmembers): Make argument + const. + * util/grub-setup.c (main): Reuse md device name if available. + * util/raid.c (grub_util_raid_getmembers): Receive device name and + not GRUB name as argument. + Based on patch by: Florian Wagner . + +2011-04-08 Vladimir Serbinenko + + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_make_mbi): + Place mbi on low memory for better compatibility. + +2011-04-08 Vladimir Serbinenko + + * include/grub/efiemu/efiemu.h: Use grub_memory_hook_t type. + +2011-04-08 Vladimir Serbinenko +2011-04-08 Colin Watson + + * autogen.sh: Ensure that collate and ctype locale is C. + * conf/Makefile.common: Likewise. + +2011-04-08 Vladimir Serbinenko + + * grub-core/normal/menu.c: Add missing include. + +2011-04-08 Vladimir Serbinenko + + * grub-core/disk/raid.c [GRUB_UTIL]: Add missing include. + +2011-04-08 Martin Zuther + + * util/grub-mkconfig.in: Ignore emacsen backup. + +2011-04-08 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (open_device): Sync on close and not + on open. + (grub_util_biosdisk_close): Likewise. + +2011-04-08 Vladimir Serbinenko + + * grub-core/kern/emu/getroot.c (grub_util_get_grub_dev): Add missing + const attribute and use grub_isdigit. + +2011-04-06 Andrey + + * grub-core/video/fb/video_fb.c (grub_video_fb_setup): Silence older + gcc warning. + +2011-04-06 Vladimir Serbinenko + + * grub-core/lib/relocator.c (grub_relocator_alloc_chunk_align): Add few + useful grub_dprintf's. + +2011-04-06 Vladimir Serbinenko + + * include/grub/fs.h (grub_dirhook_info): Use unsigned for 1-bit fields. + +2011-04-06 Vladimir Serbinenko + + * util/grub.d/00_header.in: Don't use LANG unless unifont is available. + +2011-04-06 Vladimir Serbinenko + + Output errors if theme loading failed. + + * grub-core/gfxmenu/gfxmenu.c (grub_gfxmenu_try): Move the call to + grub_gfxterm_fullscreen on error paths to ... + * grub-core/normal/menu.c (menu_init): ...here. Wait after showing + theme loading error. + +2011-04-06 Vladimir Serbinenko + + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_RAW_SIZE): Let a bit more + space for older compilers. + (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): Likewise. + +2011-04-06 Vladimir Serbinenko + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Detect spares + and report them as not RAID members since they are useless for GRUB. + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise. + +2011-04-02 Vladimir Serbinenko + + Increase LVM implementation robustness in order not to crash on + configurations like pvmove. Previously code assumed that in some places + only lvs or only pvs are used whereas it seems that they are used + interchangeably. + + * grub-core/disk/lvm.c (read_node): New function. + (read_lv): Use read_node. + (grub_lvm_scan_device): Use only first mirror on pvmove'd lvs. + Match volumes only at the end when all lvs are found. Take both + pvs (first) and lvs (second) into account. + * include/grub/lvm.h (grub_lvm_segment): Merge fields stripe_* and + mirror_* into node_*. All users updated. + (grub_lvm_stripe): Merge this ... + (grub_lvm_mirror): ... and this ... + (grub_lvm_node): ... into this. All users updated. + +2011-04-02 Vladimir Serbinenko + + * grub-core/disk/lvm.c (grub_lvm_scan_device): Print errors on the end + of function to allow further scanning for LVMs. + +2011-04-02 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_read): Don't close + on failed seek as it breaks open fd reusage. + +2011-04-02 Vladimir Serbinenko + + * util/grub-install.in: Add a recommendation to use --recheck before + reporting bugs. + +2011-04-02 Vladimir Serbinenko + + * docs/grub.texi (Vendor power-on buttons): Explain how the numbers + are obtained. + +2011-04-02 Vladimir Serbinenko + + GRUB developper manual based on existing Internals section and + contributions by the various authors with active copyright assignment. + + * docs/Makefile.am (info_TEXINFOS): Add grub-dev.texi. + * docs/font_char_metrics.png: New file. + * docs/font_char_metrics.txt: Likewise. + * docs/grub-dev.texi: Likewise. + * docs/grub.texi (Internals): Move from here ... + * docs/grub-dev.texi: ... here. + +2011-04-01 Colin Watson + + Store the loopback device as data on loopback grub_disk structures, + rather than the file it points to. This fixes use of freed memory + if an existing loopback device is replaced. + + * grub-core/disk/loopback.c (grub_loopback_open): Store dev in + disk->data, not dev->file. + (grub_loopback_read): Adjust file assignment to match. + Fixes Ubuntu bug #742967. + +2011-04-01 Colin Watson + + * grub-core/disk/loopback.c (grub_cmd_loopback): Fix a memory leak + when replacing an existing device. + +2011-04-01 Vladimir Serbinenko + + Fix incorrect types in jfs.c. This enables >2TiB disks and fixes some + memory corruptions. + + * grub-core/fs/jfs.c (struct grub_jfs_diropen): Interpret bytes as + unsigned. + (grub_jfs_lookup_symlink): Make ino a grub_uint32_t rather than int. + (grub_jfs_blkno): Use 64-bit quantities for block sectors. + (grub_jfs_read_inode): Likewise. + (grub_jfs_opendir): Likewise. Remove now useless casts. + (grub_jfs_getent): Likewise. + Make ino a grub_uint32_t rather than int. + (grub_jfs_mount): Ensure that blksize and log2_blksize are consistent. + (grub_jfs_read_file): Use 64-bit quantities when necessary. Replace + division and module with bit operations. + (grub_jfs_find_file): Make ino a grub_uint32_t. + (grub_jfs_lookup_symlink): Likewise. Use 64-bit quantities + +2011-04-01 Colin Watson + + * grub-core/normal/menu_entry.c (run): Quieten uninitialised + warning. (This was in fact always initialised before use, but GCC + wasn't smart enough to prove that.) + * grub-core/script/lexer.c (grub_script_lexer_yywrap): Likewise. + +2011-03-31 Vladimir Serbinenko + + * grub-core/kern/x86_64/efi/callwrap.S (efi_wrap_0): Preserve 16-byte + stack alignment. + (efi_wrap_1): Likewise. + (efi_wrap_2): Likewise. + (efi_wrap_3): Likewise. + (efi_wrap_4): Likewise. + (efi_wrap_5): Likewise. + (efi_wrap_6): Likewise. + (efi_wrap_10): Likewise. + Based on information by: Red Hat/Peter Jones. + +2011-03-31 Colin Watson + + * grub-core/mmap/efi/mmap.c (grub_mmap_unregister): Remove + set-but-not-used variable. + +2011-03-31 Colin Watson + + * docs/grub.texi (Simple configuration): Be more explicit about + GRUB_DEFAULT, and add an example. + Reported by: Leslie Rhorer. + +2011-03-30 Colin Watson + + * docs/grub.texi (Commands): Link to "GRUB only offers a rescue + shell". + +2011-03-30 Alexey Shvetsov + + * util/grub.d/10_linux.in: Add gentoo-specific config filename. + * util/grub.d/20_linux_xen.in: Likewise. + +2011-03-30 Vladimir Serbinenko + + * util/grub.d/10_linux.in: Try alternative config filenames where + we parse config file. + * util/grub.d/20_linux_xen.in: Likewise. + +2011-03-30 Alexey Shvetsov + + * util/grub.d/10_linux.in: Add gentoo-specific Linux and initrd names. + * util/grub.d/20_linux_xen.in: Likewise. + +2011-03-30 Vladimir Serbinenko + + * grub-core/disk/raid.c (insert_array): Add few potentially + useful grub_util_info. + (grub_raid_register): Likewise. + +2011-03-30 Vladimir Serbinenko + + * grub-core/kern/emu/getroot.c (grub_util_get_grub_dev) [__linux__]: + Preserve partition number in mdadm code path. + +2011-03-30 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev): Add + few potentially useful grub_util_info. + +2011-03-30 Vladimir Serbinenko + + * grub-core/disk/lvm.c (grub_lvm_scan_device): Remove spurious \n. + +2011-03-30 Colin Watson + + * docs/grub.texi (default): Use @example rather than nested + itemized lists to avoid breaking gendocs. + +2011-03-30 Colin Watson + + * docs/grub.texi (Future): Update. + +2011-03-30 Colin Watson + + * docs/grub.texi (Environment): New chapter. + (Changes from GRUB Legacy): Link to "Environment block" section for + details of limitations. + (Simple configuration): Likewise. Link to documentation of gfxmode + and gfxpayload variables from GRUB_GFXMODE and GRUB_GFXPAYLOAD + respectively. + (Shell-like scripting): Note that normal variables are stored in the + environment. + (gettext): Link to documentation of lang and locale_dir. + (list_env): New section. + (load_env): New section. + (save_env): New section. + + (Reporting bugs): Fix typo. + +2011-03-30 Vladimir Serbinenko + + * docs/grub.texi: Correctly use "terminal_input" and not "terminal" in + the example. + +2011-03-30 Vladimir Serbinenko + + * grub-core/term/at_keyboard.c (set_scancodes) + [!GRUB_MACHINE_MIPS_YEELOONG && !GRUB_MACHINE_QEMU]: Use scancode set 1. + +2011-03-30 Colin Watson + + * docs/grub.texi (Menu-specific commands): Remove some semantics + that were true in GRUB Legacy but not in GRUB 2. + (submenu): New section. + (false): New section. + (read): New section. + (true): New section. + +2011-03-30 Colin Watson + + * docs/grub.texi (Changes from GRUB Legacy): Minor proofreading. + +2011-03-30 Colin Watson + + * docs/grub.texi (Simple configuration): Explain some of the + current limitations of grub-mkconfig. + Reported by: Leslie Rhorer. + +2011-03-29 Vladimir Serbinenko + + Old macs search for boot.efi rather than for bootia32.efi. + + * util/grub-install.in: Copy bootia32.efi to boot.efi. + * util/grub-mkrescue.in: Likewise. + Suggested by: Peter Jones. + +2011-03-29 Vladimir Serbinenko + + * util/grub.d/20_linux_xen.in: Accept old-style xen kernels. + +2011-03-29 Vladimir Serbinenko + + * include/grub/lvm.h (grub_lvm_lv): New field 'visible'. + (grub_lvm_segment): New fields 'type', 'mirror_count' and 'mirrors'. + (grub_lvm_mirror): New struct. + * grub-core/disk/lvm.c (grub_lvm_checkvalue): Commented out. + (grub_lvm_iterate): Iterate only visible volumes. + (grub_lvm_read): Factor out to .. + (read_lv): ... this. Support mirrors. + (grub_lvm_read): New wrapper function. + (grub_lvm_scan_device): Parse mirrors. Skip everything that isn't + stripped or mirrored. + +2011-03-29 Vladimir Serbinenko + + * util/grub.d/10_linux.in: Skip vmlinux-* on x86 platforms. + +2011-03-29 Colin Watson + + * docs/grub.texi (loopback): New section. + +2011-03-29 Colin Watson + + * grub-core/disk/loopback.c (GRUB_MOD_INIT): Stop documenting + removed -p option. + +2011-03-29 Colin Watson + + * docs/grub.texi (BIOS installation): New section, partly based on + previous text in other sections. + (Installing GRUB using grub-install): Replace BIOS discussion with a + cross-reference. + (Images): Likewise. + +2011-03-29 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (find_partition_start) + [HAVE_DIOCGDINFO]: Add safety checks. + +2011-03-29 Vladimir Serbinenko + + * util/grub.d/10_kfreebsd.in: Allow ufs.ko to be missing as it's + per default compiled in kernel and prior to 8.0 isn't shipped at all. + +2011-03-29 Colin Watson + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): If + real_sb->size is zero (e.g. RAID-0), get the disk size from + real_sb->data_size instead. + Fixes Ubuntu bug #743136. + +2011-03-29 Vladimir Serbinenko + + * grub-core/normal/misc.c (grub_normal_print_device_info): Use correct + printf clauses for printing size and start. + +2011-03-29 Vladimir Serbinenko + + * grub-core/fs/ext2.c (grub_ext2_read_inode): Fix an overflow. + Reported and tested by: Timothy Nikkel. + +2011-03-29 Vladimir Serbinenko + + * grub-core/term/gfxterm.c (dirty_region_add): Move core part to ... + (dirty_region_add_real): ... this. + (dirty_region_add): Don't discard margin refresh when performing + scheduled repaint. + +2011-03-29 Vladimir Serbinenko + + * grub-core/lib/relocator.c (allocate_regstart) + [!DEBUG_RELOCATOR_NOMEM_DPRINTF]: Avoid grub_dprintf since not all + terminals are capabple of malloc-free operation. + (allocate_inreg) [!DEBUG_RELOCATOR_NOMEM_DPRINTF]: Likewise. + (malloc_in_range) [!DEBUG_RELOCATOR_NOMEM_DPRINTF]: Likewise. + +2011-03-29 Mario Limonciello + + * util/grub-setup.c: Copy the partition table zone if floppy support + is disabled, even if no partition table is found. + + Otherwise, the BIOS on Dell Latitude E series laptops will freeze + during POST if an invalid partition table is contained in the PBR + of the active partition when GRUB is installed to a partition. + +2011-03-28 Colin Watson + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Remove stale + comment. + +2011-03-28 Colin Watson + + * grub-core/disk/raid.c (grub_raid_register): Adjust debug message + to be specific about what kind of RAID device we're scanning for. + +2011-03-26 Seth Goldberg + + * grub-core/kern/emu/getroot.c (find_root_device_from_libzfs): Don't + return freed string. + +2011-03-26 Vladimir Serbinenko + + * grub-core/fs/iso9660.c (grub_iso9660_label): Rtrim the label. + +2011-03-26 Vladimir Serbinenko + + Use libgeom on FreeBSD to detect partitions. + + * Makefile.util.def (grub-mkimage): Add LIBGEOM to ldadd. + (grub-mkrelpath): Likewise. + (grub-script-check): Likewise. + (grub-editenv): Likewise. + (grub-mkpasswd-pbkdf2): Likewise. + (grub-fstest): Likewise. + (grub-mkfont): Likewise. + (grub-mkdevicemap): Likewise. + (grub-probe): Likewise. + (grub-setup): Likewise. + (grub-ofpathname): Likewise. + (grub-mklayout): Likewise. + (example_unit_test): Likewise. + (grub-menulst2cfg): Likewise. + * grub-core/Makefile.core.def (grub-emu): Likewise. + (grub-emu-lite): Likewise. + * configure.ac: Check for -lgeom on FreeBSD and set LIBGEOM. + * grub-core/kern/emu/hostdisk.c [FreeBSD]: Include libgeom.h. Don't + define HAVE_DIOCGDINFO. + (follow_geom_up) [FreeBSD]: New function. + (find_partition_start) [FreeBSD]: Rewritten using follow_geom_up. + (convert_system_partition_to_system_disk) [FreeBSD]: Likewise. + (grub_util_biosdisk_get_grub_dev) [FreeBSD]: Use FreeBSD path + unconditionally of HAVE_DIOCGDINFO. + +2011-03-26 Vladimir Serbinenko + + Fix FreeBSD compilation problem. + + * grub-core/kern/emu/hostdisk.c (MAJOR) [FreeBSD]: New definition. + (FLOPPY_MAJOR) [FreeBSD]: Likewise. + +2011-03-24 Colin Watson + + * grub-core/video/fb/video_fb.c (grub_video_fb_get_info_and_fini): + Switch back to page zero before loading a kernel, since some kernel + drivers expect that. + Thanks to: Felix Kuehling. + +2011-03-24 Vladimir Serbinenko + + * grub-core/lib/relocator.c (grub_relocator_alloc_chunk_addr) + [DEBUG_RELOCATOR]: Reuse grub_mm_check. + (grub_relocator_alloc_chunk_align) [DEBUG_RELOCATOR]: Likewise. + +2011-03-24 Vladimir Serbinenko + + * include/grub/mm.h (GRUB_MM_CHECK): Rename to ... + (grub_mm_check): ... this. MAke a function-like macro and use GRUB_FILE. + +2011-03-24 Vladimir Serbinenko + + * grub-core/lib/relocator.c (allocate_inreg): Avoid dprintf unless + DEBUG_RELOCATOR is defined since gfxterm can't cope with output when + malloc is disabled. + +2011-03-24 Vladimir Serbinenko + + * grub-core/loader/i386/bsdXX.c (grub_freebsd_load_elfmodule): Account + for modules headers when counting the needed allocation size. + +2011-03-23 Vladimir Serbinenko + + * grub-core/term/gfxterm.c (calculate_normal_character_width): Return 8 + if no ASCII character is found to prevent crash. + +2011-03-23 Alexander Kurtz + + * grub-core/video/bitmap.c (match_extension): Ignore case. + +2011-03-23 Vladimir Serbinenko + + * grub-core/normal/menu_entry.c (init_line): Fix off-by-one error. + +2011-03-23 Vladimir Serbinenko + + * grub-core/script/parser.y: Declare "time" as valid argument. + +2011-03-23 Peter Jones + + Fix incorrect assert failure reporting. + + * grub-core/tests/example_functional_test.c (example_test): Add + a failure comment. + * grub-core/tests/lib/test.c (add_failure): Renamed to ... + (failure_start): ...this. Check that malloc succeeded. + Don't call xvasprintf. Return failure struct. + (failure_append_vtext): New function. + (failure_append_text): Likewise. + (add_failure): Likewise. + (grub_test_assert_helper): Likewise. + * include/grub/test.h (grub_test_assert_helper): New declaration. + (grub_test_assert): Macro rewritten. + +2011-03-23 Vladimir Serbinenko + + * grub-core/normal/main.c (GRUB_MOD_INIT): Export pager variable. + +2011-03-23 Vladimir Serbinenko + + * grub-core/lib/i386/pc/biosnum.c: Add missing include. + +2011-03-23 Vladimir Serbinenko + + * grub-core/disk/usbms.c (grub_usbms_reset): Transform USB-style error + into GRUB-style one. + +2011-03-23 Vladimir Serbinenko + + * grub-core/bus/usb/usbtrans.c (grub_usb_control_msg): Return usb-style + error and not grub_errno. + * grub-core/bus/usb/usbhub.c (grub_usb_add_hub): Likewise. + +2011-03-23 Vladimir Serbinenko + + * grub-core/bus/usb/uhci.c (grub_uhci_detect_dev): Return + GRUB_USB_SPEED_NONE in case of failure and not the error code. + +2011-03-23 Vladimir Serbinenko + + * grub-core/efiemu/i386/pc/cfgtables.c + (grub_machine_efiemu_init_tables): Make declaration a prototype. + * grub-core/loader/xnu.c (grub_xnu_lock): Likewise. + (grub_xnu_unlock): Likewise. + * grub-core/normal/cmdline.c (grub_cmdline_get/cl_set_pos_all): Likewise. + +2011-03-23 Vladimir Serbinenko + + * grub-core/bus/usb/usb.c (attach_hooks): Make static. + * grub-core/bus/usb/usbhub.c (hubs): Likewise. + * grub-core/commands/hashsum.c (aliases): Likewise. + * grub-core/commands/setpci.c (pci_registers): Likewise. + * grub-core/disk/usbms.c (attach_hook): Likewise. + * grub-core/fs/zfs/zfs.c (decomp_table): Likewise. + (zio_checksum_table): Likewise. + * grub-core/gettext/gettext.c (grub_gettext_msg_list): Likewise. + * grub-core/gfxmenu/gfxmenu.c (cached_view): Likewise. + * grub-core/lib/legacy_parse.c (legacy_commands): Likewise. + * grub-core/lib/relocator.c (leftovers): Likewise. + (extra_blocks): Likewise. + * grub-core/loader/i386/bsd.c (relocator): Likewise. + * grub-core/loader/i386/multiboot_mbi.c (modules): Likewise. + (modules_last): Likewise. + * grub-core/loader/i386/xnu.c (table_aliases): Likewise. + (devices): Likewise. + * grub-core/loader/multiboot_mbi2.c (modules): Likewise. + (modules_last): Likewise. + * grub-core/normal/auth.c (users): Likewise. + * grub-core/normal/context.c (initial_menu): Likewise. + (current_menu): Likewise. + * grub-core/normal/crypto.c (crypto_specs): Likewise. + * grub-core/term/serial.c (grub_serial_ports): Likewise. + (grub_serial_terminfo_input_template): Likewise. + (grub_serial_terminfo_output_template): Likewise. + (grub_serial_terminfo_input): Likewise. + (grub_serial_terminfo_output): Likewise. + (registered): Likewise. + * grub-core/term/usb_keyboard.c (attach_hook): Likewise. + +2011-03-23 Vladimir Serbinenko + + * grub-core/video/bochs.c (grub_video_bochs_setup): Use + grub_video_mode_type_t. + * grub-core/video/cirrus.c (grub_video_cirrus_setup): Likewise. + * grub-core/video/i386/pc/vbe.c (grub_video_vbe_setup): Likewise. + * grub-core/video/i386/pc/vga.c (grub_video_vga_setup): Likewise. + +2011-03-23 Vladimir Serbinenko + + * util/grub-install.in: Correct the x86-64 name as x86_64. + +2011-03-11 Colin Watson + + * grub-core/boot/i386/pc/lnxboot.S (real_code_2): Ensure that the + initial chunk read from the kernel always includes GRUB's multiboot + header, which is now outside the first sector. + +2011-03-09 Colin Watson + + * grub-core/loader/i386/linux.c (find_efi_mmap_size): Page-align + cached mmap_size, so that this works correctly when called multiple + times. + Reported by: Daniel Kahn Gillmor. Should fix Debian bug #616638. + +2011-03-09 Colin Watson + + * docs/grub.texi (Simple configuration): Tidy up formatting. + +2011-03-07 Szymon Janc + + * grub-core/fs/zfs/zfs.c (zap_leaf_lookup): + Set-but-not-used variable removed. + +2011-02-12 Vladimir Serbinenko + + Workaround yet another IEEE1275 bug. + + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_flag): New enum value + GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS. + * grub-core/kern/ieee1275/mmap.c (grub_machine_mmap_iterate): Ignore + adress_cells and size:cells if GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS + is set. + * grub-core/kern/ieee1275/cmain.c (grub_ieee1275_find_options): Set + GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS on powermacs. + +2011-02-12 Vladimir Serbinenko + + * grub-core/partmap/msdos.c (pc_partition_map_embed): Fix off by one + error. + +2011-02-11 Colin Watson + + * util/grub.d/20_linux_xen.in: Bail out early if linux_list is + empty, since in that case we can only generate either nothing or a + syntactically invalid configuration file. + Reported by: Michal Suchanek. Fixes Debian bug #612898. + +2011-02-09 Colin Watson + + * docs/grub.texi (Kernel): Add reference to grub-mkrescue. + (Making a GRUB bootable CD-ROM): Likewise. + (Invoking grub-mkrescue): New section. + Reported by: Yann Dirson. Fixes Debian bug #612585. + +2011-02-09 Colin Watson + + * util/grub-install.in: Remove unnecessary brackets from tr + arguments. + * util/grub.d/10_hurd.in: Likewise. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub.d/20_linux_xen.in: Likewise. + Reported by: Jamie Heilman. Fixes Debian bug #612564. + +2011-02-08 Colin Watson + + * include/grub/file.h (not_easly_seekable): Rename to ... + (not_easily_seekable): ... this. Update all users. + +2011-01-28 Colin Watson + + * docs/grub.texi (Making a GRUB bootable CD-ROM): Update to describe + grub-mkrescue. + +2011-01-24 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Refuse to create the images + bigger than the actual flash (512K) in Loongson machines. 512K is also + the biggest chip supported by them. + +2011-01-22 Vladimir Serbinenko + + * grub-core/kern/emu/getroot.c: Include config-util.h explicitly. + +2011-01-22 Anthony DeRobertis + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Check + super_offset field. + +2011-01-22 Vladimir Serbinenko + + * util/grub-install.in: Ignore install device on platforms + where it doesn't make sense. Always use UUIDs except on pc, efi and + sparc64. + Reported by: Daniel Kahn Gillmor. + +2011-01-22 Vladimir Serbinenko + + * grub-core/bus/bonito.c (write_bases): Fix direction of the shift. + +2011-01-22 Vladimir Serbinenko + + * grub-core/partmap/bsdlabel.c: Include grub/emu/misc.h and not grub/util/misc.h. + (iterate_real): Don't rely on partition being non-NULL. + +2011-01-22 Vladimir Serbinenko + + * grub-core/script/argv.c (round_up_exp): unsigned is 32-bit on all + supported platforms. Put a compile time assert for this rather than + generate a warning with 32-bit shift. + +2011-01-22 Vladimir Serbinenko + + * grub-core/disk/scsi.c (grub_scsi_read): Fix binary and check and make + logical expression more readable. + +2011-01-22 Vladimir Serbinenko + + * grub-core/disk/raid.c (insert_array): Ensure uniqueness of p->number + even if some elements have a name. + Reported by: Alexander GQ Gerasiov. + +2011-01-22 Colin Watson + + * util/grub-mkconfig_lib.in (is_path_readable_by_grub): Consider a + path unreadable if `grub-probe -t abstraction' fails, for example if + memberlist fails on an LVM volume group. + Reported by: Darius Jahandarie. + +2011-01-22 Colin Watson + + * docs/grub.texi (Simple configuration): Document + GRUB_PRELOAD_MODULES. + +2011-01-17 Colin Watson + + * .bzrignore: Remove nonexistent grub-pbkdf2. + +2011-01-16 Vladimir Serbinenko + + * configure.ac: Bump version to 1.99~rc1. + +2011-01-15 Vladimir Serbinenko + + * util/grub-mkimage.c (generate_image): Check fwstart.img checksum + for safety. + +2011-01-14 Vladimir Serbinenko + + * grub-core/kern/mips/yeeloong/init.c (grub_machine_init): Init boot + module. + +2011-01-14 Vladimir Serbinenko + + * grub-core/Makefile.core.def (fwstart): Add lost LDFLAGS. + +2011-01-13 Vladimir Serbinenko + + * grub-core/fs/zfs/zfsinfo.c (grub_cmd_zfs_bootfs): Quote bootpath and + diskdevid. + +2011-01-13 Vladimir Serbinenko + + Fix compilation on cygwin. + + * conf/Makefile.common (STRIPFLAGS_KERNEL): Add -F elf32-i386 and + -R .drectve on cygwin. + * conf/i386-pc-cygwin-img-ld.sc: Merge rdata and pdata into data. + * configure.ac: Use $(top_builddir) in TARGET_OBJ2ELF. + (COND_CYGWIN): New condition. + * grub-core/Makefile.am (%.mod): Set TARGET_OBJ2ELF. + * grub-core/genmod.sh.in: Use ${TARGET_OBJ2ELF} and + not @TARGET_OBJ2ELF@. + * util/grub-pe2elf.c (write_symbol_table): Use pe_symtab->type and not + type to determine whether aux is to be used. + +2011-01-12 Vladimir Serbinenko + + * util/ieee1275/ofpath.c (grub_util_devname_to_ofpath): Use the + realpath'ed device string. + Handle floppy (somewhat). + Issue error in unknown case rather than garbage. + Reported by: Axel Beckert. + +2011-01-12 Vladimir Serbinenko + + * util/grub.d/00_header.in (load_video): Handle the case when no video + drivers available. + Thanks to: Axel Beckert. + +2011-01-12 Vladimir Serbinenko + + * util/grub-mkfont.c (write_font_pf2): Use appropriate type for data + variable. Fixes problem on big endian platforms. + +2011-01-12 Vladimir Serbinenko + + * grub-core/Makefile.core.def (ieee1275_fb): Disable on sparc. + It doesn't work well there. + +2011-01-12 Vladimir Serbinenko + + * grub-core/normal/context.c (grub_env_context_close): Silence spurious + warning. + * grub-core/normal/menu.c (grub_menu_execute_entry): Likewise. + * grub-core/partmap/msdos.c (pc_partition_map_embed): Use unsigned + counter. + +2011-01-12 Vladimir Serbinenko + + Use alias->path rather than buggy "canon". + + * grub-core/disk/ieee1275/ofdisk.c (ofdisk_hash_add_real): New function. + (ofdisk_hash_add): New argument curcan. All users updated. + +2011-01-11 Colin Watson + + * configure.ac: Fall back to `true' if `makeinfo' does not exist. + +2011-01-11 Vladimir Serbinenko + + * grub-core/loader/powerpc/ieee1275/linux.c (grub_linux_load32): Apply + loadmask before doing any calculations. Use correct type for offset. + (grub_linux_load64): Likewise. + +2011-01-11 Colin Watson + + * util/grub-mklayout.c (console_grub_equivalences_shift): Terminate + with NULL. + (console_grub_equivalences_unshift): Likewise. + Reported by: Daniel Dehennin. + +2011-01-11 Vladimir Serbinenko + + * grub-core/fs/i386/pc/pxe.c (set_mac_env): Export variable. + (set_env_limn_ro): Likewise. + (GRUB_MOD_INIT): Likewise. + * grub-core/hook/datehook.c (GRUB_MOD_INIT): Likewise. Change to + ARRAY_SIZE while on it. + (GRUB_MOD_FINI): Change to ARRAY_SIZE. + * grub-core/normal/context.c (grub_env_export): Move from here ... + * grub-core/kern/env.c (grub_env_export): ... here. + * grub-core/normal/context.c (grub_cmd_export): Skip exporting root and + prefix. + * grub-core/kern/main.c (grub_main): Export root and prefix. + * include/grub/env.h (grub_env_export): Export. + Reported by: Seth Goldberg. + +2011-01-11 Vladimir Serbinenko + + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_make_mbi): + Take into account space used by ELF sections and multiboot palette. + Reported by: Grégoire Sutre. + +2011-01-11 Vladimir Serbinenko + + * BUGS: New file. + +2011-01-10 Vladimir Serbinenko + + Pass more appropriate video id to Linux. + + * grub-core/loader/i386/linux.c (grub_linux_setup_video): Use + grub_video_get_driver_id and variable gfxpayloadforcelfb to + fill have_vga. + (grub_linux_boot): Rely on grub_linux_setup_video to fill have_vga and + shift params->lfb_size. + * include/grub/i386/linux.h: Make an enume out of have_vga values. + +2011-01-10 Vladimir Serbinenko + + * util/grub-menulst2cfg.c: Add missing include of misc.h. + +2011-01-10 Vladimir Serbinenko + + * grub-core/fs/zfs/zfsinfo.c (grub_cmd_zfs_bootfs): Use comma as + separator and pass bootpath/devid even if only one of them is available. + Reported by: Seth Goldberg. + +2011-01-10 Vladimir Serbinenko + + Don't use post-4G memory on EFI even if 64-bit since some non-compliant + implementations bug on them. + + * grub-core/kern/efi/mm.c (grub_efi_allocate_pages): Skip post-4G + memory. + (filter_memory_map): Likewise. + +2011-01-10 Vladimir Serbinenko + + * util/grub-kbdcomp.in: Add missing prefix and exec_prefix variables. + Reported by: nebuchadnezzar. + +2011-01-10 Vladimir Serbinenko + + * util/grub-kbdcomp.in: Add missing transform and bindir variables. + Reported by: nebuchadnezzar. + +2011-01-10 Vladimir Serbinenko + + Submenu default support. + + * grub-core/normal/menu.c (grub_menu_execute_entry): New parameter + auto_boot. All users updated. + Declared static. + Handle chosen and default with submenus. + (grub_menu_execute_with_fallback): Declared static. + Don't notify failure if autobooted. Upper level does it. + (menuentry_eq): New function. + (get_entry_number): Use menuentry_eq. + (show_menu): New parameter "autobooted". All users updated. + (grub_show_menu): Likewise. + * include/grub/normal.h (grub_show_menu): Likewise. + * include/grub/menu.h (grub_menu_execute_entry): Removed. + (grub_menu_execute_with_fallback): Likewise. + +2011-01-10 Vladimir Serbinenko + + * util/grub-mklayout.c (usage): Update help text. + +2011-01-10 Vladimir Serbinenko + + * grub-core/commands/legacycfg.c (legacy_file): Trim the line. + +2011-01-10 Vladimir Serbinenko + + * util/grub-menulst2cfg.c (main): Trim the line. + +2011-01-10 Vladimir Serbinenko + + * grub-core/kern/i386/pc/init.c (grub_get_conv_memsize): Removed. + (grub_machine_init): Don't check amount of low memory as reportedly + INT 12h can be broken and if low memory is too low we wouldn't have + gotten into grub_machine_init anyway. + +2011-01-10 Vladimir Serbinenko + + * grub-core/kern/i386/pc/mmap.c (grub_get_conv_memsize): New function. + (grub_machine_mmap_iterate): Take low memory into account + +2011-01-10 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_mount): Transform out of range into + badfs. + Reported by: TiCPU. + +2011-01-10 Vladimir Serbinenko + + * grub-core/disk/raid.c (insert_array): Display RAID name in duplicate + members errors. + +2011-01-09 Grégoire Sutre + + * util/grub.d/10_netbsd.in (netbsd_load_fs_module): New function. + (netbsd_entry): Use netbsd_load_fs_module() to load filesystem module. + +2011-01-09 Grégoire Sutre + + * util/grub-mkconfig_lib.in (prepare_grub_to_access_device): Handle + openbsd and netbsd types being in part_bsd module. + +2011-01-08 Vladimir Serbinenko + + * config.h.in (_LARGEFILE_SOURCE): Add missing define. + (_FILE_OFFSET_BITS): Likewise. + Reported by: Seth Goldberg. + +2011-01-08 Grégoire Sutre + + * configure.ac: Check for libdevmapper header. + +2011-01-08 Vladimir Serbinenko + + * grub-core/fs/zfs/zfs.c (dmu_read): Use void * for some pointers to + avoid aliasing. + (fzap_lookup): Likewise. + (dnode_get): Likewise. + (make_mdn): Likewise. + (zfs_mount): Likewise. + (fzap_iterate): Use temporary pointer to avoid aliasing. + (grub_zfs_read): Likewise. + * grub-core/loader/i386/xnu.c (grub_xnu_boot): Likewise. + * grub-core/loader/xnu.c (grub_cmd_xnu_kernel): Use void * for some + pointers to avoid aliasing. + (grub_cmd_xnu_kernel64): Likewise. + (grub_xnu_load_driver): Likewise. + +2011-01-08 Vladimir Serbinenko + + * grub-core/commands/terminal.c (grub_cmd_terminal_input): Silence + aliasing warning. + (grub_cmd_terminal_output): Likewise. + Reported and tested by: Grégoire Sutre. + +2011-01-08 Vladimir Serbinenko + + * grub-core/term/at_keyboard.c (grub_keyboard_getkey): Silence spurious + warning. + Reported and tested by: Grégoire Sutre. + +2011-01-08 Vladimir Serbinenko + + * configure.ac: Do CPU substitution even if it's specified explicitly. + Reported and tested by: Alain Greppin. + +2011-01-08 Vladimir Serbinenko + + * grub-core/Makefile.am (rs_decoder.S): Force compilation with -Os. + Reported and tested by: Alain Greppin. + +2011-01-08 Vladimir Serbinenko + + Satisfy some bison versions need for inttypes.h. + + * grub-core/lib/posix_wrap/inttypes.h: New file. + * grub-core/lib/posix_wrap/sys/types.h (int8_t): New type. + (int16_t): Likewise. + (int32_t): Likewise. + (int64_t): Likewise. + Reported and tested by: Alain Greppin. + +2011-01-08 Vladimir Serbinenko + + * grub-core/loader/i386/bsdXX.c (grub_netbsd_load_elf_meta): + Silence spurious warning. + Reported and tested by: Alain Greppin. + +2011-01-07 Szymon Janc + + * docs/grub.texi (Support automatic decompression): Update with xz + decompression support. + +2011-01-07 Szymon Janc + + Improve loaders' kernel command line handling. + + * grub-core/lib/cmdline.c: New file. + * include/grub/lib/cmdline.h: Likewise. + * grub-core/loader/i386/linux.c (grub_cmd_linux): Use + grub_create_loader_cmdline to create kernel command line. + * grub-core/loader/i386/pc/linux.c (grub_cmd_linux): Likewise. + * grub-core/loader/powerpc/ieee1275/linux.c (grub_cmd_linux): Likewise. + * grub-core/loader/sparc64/ieee1275/linux.c (grub_cmd_linux): Likewise. + * grub-core/Makefile.core.def (linux16): Add lib/cmdline.c on i386_pc. + (linux): Add lib/cmdline.c on common. + +2011-01-07 Vladimir Serbinenko + + * grub-core/fs/xfs.c (grub_xfs_iterate_dir): Take into account that + inopos might be unaligned. + +2011-01-07 Vladimir Serbinenko + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Add missing + endian transformations. + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise. + Based on report by: Doug Nazar. + +2011-01-07 Doug Nazar + + * grub-core/disk/raid5_recover.c (grub_raid5_recover): Add missing + array->members[i].start_sector. + * grub-core/disk/raid6_recover.c (grub_raid6_recover): Likewise. + +2011-01-07 Vladimir Serbinenko + + * util/grub-setup.c (setup): Handle NetBSD and OpenBSD disklabels. + Reported and tested by: Grégoire Sutre. + +2011-01-06 Colin Watson + + * tests/util/grub-shell.in: Set serial terminfo type to `dumb', to + avoid causing test failures by clearing the screen. + +2011-01-06 Colin Watson + + * grub-core/kern/emu/getroot.c (find_root_device_from_mountinfo): + Fix prefix check to handle the case where dir ends with a slash + (most significantly, "/" itself). + Reported by: Michael Vogt. + +2011-01-05 Vladimir Serbinenko + + Run terminfo_cls on initing terminfo output to clear the screen and + move the cursor to (0,0). + + * grub-core/term/ieee1275/ofconsole.c (grub_ofconsole_init_output): + Call grub_terminfo_output_init. + * grub-core/term/serial.c (grub_serial_term_output): Set .init. + * grub-core/term/terminfo.c (grub_terminfo_output_init): New function. + * include/grub/terminfo.h (grub_terminfo_output_init): New declaration. + +2011-01-05 Vladimir Serbinenko + + * util/grub-install.in: Determine ofpathname, nvsetenv and efibootmgr + only when needed. + +2011-01-05 Vladimir Serbinenko + + * grub-core/term/terminfo.c (grub_terminfo_readkey): Handle keys with + CTRL. + +2011-01-05 Vladimir Serbinenko + + The E820 type 5 is BADRAM, not EXEC_CODE. + + * grub-core/loader/i386/bsd.c (GRUB_E820_EXEC_CODE): Removed. + (GRUB_E820_BADRAM): New define. + * grub-core/loader/i386/linux.c (grub_linux_boot): Translate code + into reserved. Propagate BADRAM. + * grub-core/loader/i386/bsd.c (GRUB_E820_EXEC_CODE): Removed. + (GRUB_E820_BADRAM): New define. + +2011-01-04 Vladimir Serbinenko + + * grub-core/lib/efi/relocator.c (grub_relocator_firmware_fill_events): + Ignore the memory post-4G. + (grub_relocator_firmware_alloc_region): Additional debug statement. + +2011-01-04 Vladimir Serbinenko + + * grub-core/kern/emu/getroot.c (grub_util_get_grub_dev): Check md/%s + names. + Reported by: David Pravec. + +2011-01-04 Vladimir Serbinenko + + * grub-core/disk/i386/pc/biosdisk.c (GRUB_MOD_INIT): Workaround buggy + BIOSes. + +2011-01-04 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (grub_reed_solomon_add_redundancy): + Prevent overflow. + (grub_reed_solomon_recover): Likewise. + +2011-01-04 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (main) [TEST]: Reactivate normal test. + +2011-01-04 Vladimir Serbinenko + + * grub-core/lib/reed_solomon.c (scratch) [! STANDALONE]: Remove leftover + variable. + +2011-01-04 Colin Watson + + * grub-core/commands/legacycfg.c (GRUB_MOD_INIT): Fix typo in + descriptions of extract_legacy_entries_source and + extract_legacy_entries_configfile. + Reported by: Seung Soo, Ha. + +2011-01-03 Colin Watson + + * grub-core/bus/pci.c (grub_pci_iterate): Skip remaining functions + on devices that do not implement function 0. + +2011-01-03 Dave Vasilevsky + + * grub-core/fs/hfsplus.c: Make parent unsigned. + (grub_hfsplus_cmp_catkey): Don't compare using subtraction, it + overflows. + (grub_hfsplus_cmp_extkey): Likewise + +2011-01-03 Vladimir Serbinenko + + * util/grub-install.in: Correctly use bootloader_id and not + GRUB_DISTRIBUTOR on efibootmgr line. + +2011-01-03 Vladimir Serbinenko + + * util/grub-mkfont.c (main): Report errors in FT_New_Face. + +2010-12-31 Ian Campbell + + * util/grub.d/20_linux_xen.in (linux_entry): Correctly capitalize + Xen and reorder menu item wording to make it clearer that this entry + will launch Xen. Print separate messages when loading Xen and + Linux. + +2010-12-31 Vladimir Serbinenko + + * grub-core/partmap/amiga.c (GRUB_AMIGA_PART_MAGIC): New define. + (amiga_partition_map_iterate): Check "PART" magic to avoid a very long + loop in case of incorrect amiga partmap. + +2010-12-31 Vladimir Serbinenko + + * grub-core/partmap/amiga.c (GRUB_AMIGA_RDSK_MAGIC): New define. + (amiga_partition_map_iterate): Use grub_memcmp instead of grub_strcmp. + Reported by:EHeM. + +2010-12-31 Vladimir Serbinenko + + * grub-core/loader/i386/bsdXX.c (grub_openbsd_find_ramdisk): Silence + spurious warning. + Reported by: crocket + +2010-12-27 Vladimir Serbinenko + + * grub-core/loader/xnu.c (grub_cmd_xnu_kernel) [! GRUB_MACHINE_EFI]: + Preload EFIemu. + (grub_cmd_xnu_kernel64) [! GRUB_MACHINE_EFI]: Likewise. + +2010-12-27 Vladimir Serbinenko + + * grub-core/loader/xnu.c (grub_cmd_xnu_kext): Abort if no kernel + is loaded + (grub_cmd_xnu_kextdir): Likewise. + (grub_cmd_xnu_splash): Likewise. + +2010-12-27 Vladimir Serbinenko + + Avoid using Reed-Solomon with 0 redundancy. + + * grub-core/kern/i386/pc/startup.S: Remove 0-data check. + * grub-core/lib/reed_solomon.c (decode_block): Do not proceed on 0 data + or 0 redundancy. + (grub_reed_solomon_add_redundancy): Do not proceed with 0 redundancy. + (grub_reed_solomon_recover): Likewise. + +2010-12-27 Vladimir Serbinenko + + Don't use disk subsystem in freebsd_boot. + + * grub-core/loader/i386/bsd.c (freebsd_bootdev): New variable. + (freebsd_biosdev): Likewise. + (grub_freebsd_boot): Use freebsd_bootdev and freebsd_biosdev. + (grub_cmd_freebsd): Set freebsd_bootdev and freebsd_biosdev. + +2010-12-26 Vladimir Serbinenko + + Handling of files of unknown size is currently limited. They can't be + used e.g. for initrd or modules. Moreover gzip handling of not + easily seekable files is buggy. Disable unknown file size for now. May + be inefficient but works. + + * grub-core/io/gzio.c (test_header): Always retrieve the file size. + * grub-core/io/xzio.c (grub_xzio_open): Likewise. + +2010-12-25 Mirko Parthey + + * grub-core/boot/i386/pc/boot.S: Fix %es:%bx pointing to nowhere on + floppy probe. + +2010-12-25 Jeroen Dekkers + + * grub-core/disk/raid.c (insert_array): Don't add spurious members. + +2010-12-25 Shea Levy + + * grub-core/genmod.sh.in: Use @OBJCOPY@ rather than objcopy. + +2010-12-25 Vladimir Serbinenko + + * util/grub.d/30_os-prober.in: Don't emit drivemap directive for + Windows Server 2008. + Reported by: Devin Giddings. + +2010-12-25 Vladimir Serbinenko + + * grub-core/commands/acpihalt.c (grub_acpi_halt): Sleep for 1.5 before + writing an error message because of async power management. + * grub-core/kern/mips/yeeloong/init.c (grub_halt): Likewise. + (grub_reboot): Likewise. + +2010-12-23 Jordan Uggla + + * tests/util/grub-shell.in: Suppress "ACPI shutdown failed" error to + keep unit tests from failing when they shouldn't. + +2010-12-21 Colin Watson + + * include/grub/offsets.h (GRUB_KERNEL_I386_PC_RAW_SIZE): The + previous patch increased the size of the RS code by 20 bytes (at + least with gcc-4.4), so increase this by 20 bytes to match. + (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART): Likewise. + +2010-12-21 Colin Watson + + * grub-core/lib/reed_solomon.c (gauss_solve): Fix size of standalone + scratch area. Make sure to initialise chosen in standalone mode as + well as non-standalone. + Reported by: Robert Hooker and Andy Whitcroft. + Tested by: Andy Whitcroft. + +2010-12-21 Colin Watson + + * grub-core/commands/echo.c (grub_cmd_echo): Make UTF-8-clean by + constructing a new unescaped string and passing it to grub_xputs in + one go, rather than passing characters to grub_printf one at a time. + +2010-12-21 Colin Watson + + * grub-core/fs/udf.c (read_string): Pacify GCC warning by + initialising utf16. + +2010-12-21 Colin Watson + + * util/grub-mkconfig_lib.in (gettext_quoted): Add clarifying + comment. Add an extra layer of quotation, requiring the output of + this function to be used in a printf format string. + (gettext_printf): New function. + * util/grub.d/10_hurd.in: Use gettext_printf where appropriate. + Extract translatable strings from here-documents and use a temporary + variable instead, so that xgettext can find them. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub.d/20_linux_xen.in: Likewise. + + * po/grub.d.sed: New file. + * po/Makefile.in.in ($(DOMAIN).pot-update): Extract gettext_printf + arguments. Set c-format flags on all strings extracted from + util/grub.d/ (xgettext refuses to include these itself for strings + it extracted from a shell file, but these really are c-format). + +2010-12-20 Vladimir Serbinenko + + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_add_module): + Avoid next pointing to nowhere. + +2010-12-19 Vladimir Serbinenko + + * grub-core/fs/affs.c (grub_affs_mount): Read data->bblock.rootblock + rather than assuming than rootblock is exactly in the middle. + (grub_affs_label): Likewise. + +2010-12-19 Vladimir Serbinenko + + * grub-core/fs/affs.c (grub_affs_fs) [GRUB_UTIL]: Explicitly set + reserved_first_sector to 0. + * grub-core/fs/cpio.c (grub_cpio_fs) [GRUB_UTIL]: Likewise. + * grub-core/fs/sfs.c (grub_sfs_fs) [GRUB_UTIL]: Likewise. + * grub-core/fs/xfs.c (grub_xfs_fs) [GRUB_UTIL]: Likewise. + +2010-12-19 Vladimir Serbinenko + + Fix handling of UTF-16 UDF labels. + + * grub-core/fs/udf.c (grub_udf_iterate_dir): Move string-parsing part + (read_string): .. here. + (grub_udf_label): Use read_string. + +2010-12-19 BVK Chaitanya + + * grub-core/normal/menu_entry.c (run): Execute commands from menu + editor under argument scope. + Reported by: Jordan Uggla + +2010-12-18 Vladimir Serbinenko + + * util/grub-mkfont.c (main): Handle errors from FT_Set_Pixel_Sizes. + +2010-12-18 Colin Watson + + * grub-core/normal/term.c (print_more): Make \r or \n scroll one + line, and other keys scroll an entire page (previous handling was + for \r and \n to scroll a page and other keys to scroll two lines). + +2010-12-18 Vladimir Serbinenko + + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_make_mbi): + Set ptrdest to correct get_physical_target_address rather than + incorrect get_virtual_current_address. + +2010-12-18 kashyap garimella + + * grub-core/loader/i386/multiboot_mbi.c (grub_multiboot_load): Use + correct cat to grub_uint8_t * rather than grub_uint32_t *. + +2010-12-10 Colin Watson + + * .bzrignore: Ignore grub-core/rs_decoder.S. + +2010-12-10 Colin Watson + + * grub-core/gettext/gettext.c (grub_gettext_init_ext): Factor out + .mo/.mo.gz opening sequence to ... + (grub_mofile_open_lang): ... here. + (grub_gettext_init_ext): If opening ll_CC fails, try ll. + * util/grub.d/00_header.in (grub_lang): Include country part of + locale. + Reported by: Mario Limonciello. + +2010-12-09 Robert Millan + + * NEWS: Document addition of ZFS support. + +2010-12-04 Colin Watson + + * grub-core/kern/i386/pc/startup.S (grub_console_getkey): Use `>> 1' + rather than `/ 2', as the latter requires -Wa,--divide which would + require bumping our minimum binutils version. + +2010-12-03 BVK Chaitanya + + * util/grub-script-check.c (main): Print script line number on + error. + +2010-12-01 Robert Millan + + * grub-core/fs/zfs/zfs.c: New file. + * grub-core/fs/zfs/zfs_fletcher.c: Likewise. + * grub-core/fs/zfs/zfs_lzjb.c: Likewise. + * grub-core/fs/zfs/zfs_sha256.c: Likewise. + * grub-core/fs/zfs/zfsinfo.c: Likewise. + + * include/grub/zfs/dmu.h: Likewise. + * include/grub/zfs/dmu_objset.h: Likewise. + * include/grub/zfs/dnode.h: Likewise. + * include/grub/zfs/dsl_dataset.h: Likewise. + * include/grub/zfs/dsl_dir.h: Likewise. + * include/grub/zfs/sa_impl.h: Likewise. + * include/grub/zfs/spa.h: Likewise. + * include/grub/zfs/uberblock_impl.h: Likewise. + * include/grub/zfs/vdev_impl.h: Likewise. + * include/grub/zfs/zap_impl.h: Likewise. + * include/grub/zfs/zap_leaf.h: Likewise. + * include/grub/zfs/zfs.h: Likewise. + * include/grub/zfs/zfs_acl.h: Likewise. + * include/grub/zfs/zfs_znode.h: Likewise. + * include/grub/zfs/zil.h: Likewise. + * include/grub/zfs/zio.h: Likewise. + * include/grub/zfs/zio_checksum.h: Likewise. + + * Makefile.util.def: Build ZFS into libgrubmods. + * grub-core/Makefile.core.def: Build zfs.mod. + +2010-11-30 Szymon Janc + + * grub-core/commands/regexp.c (grub_cmd_regexp): Remove unused + variable. + * grub-core/commands/wildcard.c (match_files): Likewise. + +2010-11-30 Robert Millan + + * grub-core/loader/i386/bsd.c + (grub_cmd_freebsd_loadenv, grub_cmd_freebsd_module_elf): Check + whether kernel is loaded using grub_loader_is_loaded(), rather + than `kernel_type', which may still be `KERNEL_TYPE_NONE' under + certain error conditions. + +2010-11-30 Robert Millan + + * grub-core/commands/echo.c: Include `'. + (grub_cmd_echo): Call grub_refresh() after printing a message. + +2010-11-26 Vladimir Serbinenko + + Avoid using tricks for initialising endian variables. + + * grub-core/partmap/gpt.c (grub_gpt_partition_type_bios_boot): + Make const. + (GRUB_MOD_INIT): Don't byte-swap. + * include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_BIOS_BOOT): + Use grub_cpu_to_le16_compile_time and grub_cpu_to_le32_compile_time. + * include/grub/types.h (grub_swap_bytes16_compile_time): New macro. + (grub_swap_bytes32_compile_time): Likewise. + (grub_cpu_to_le32_compile_time): Likewise. + (grub_cpu_to_le16_compile_time): Likewise. + +2010-11-26 Vladimir Serbinenko + + * util/grub-setup.c (setup): Stop recommending --force. People who + understand the dangers of blocklists are able to find this option + anyway and the ones who don't shouldn't use it anyway. + +2010-11-26 Robert Millan + + * grub-core/term/i386/pc/vga_text.c (VGA_TEXT_SCREEN): Beautify. + Update all users. + +2010-11-26 Colin Watson + + Fix LVM-on-RAID probing. + + * util/grub-probe.c (probe): Remember which disk was detected as + RAID (perhaps an LVM physical volume). Use that disk's raidname + rather than that of the top-level disk. + +2010-11-25 BVK Chaitanya + + Fix cmdline argument quotes for setparams command of menuentry + definitions. + + * grub-core/commands/menuentry.c (setparams_prefix): Use single + quotes for arguments. + * grub-core/lib/legacy_parse.c (grub_legacy_escape): Use + grub_strchrsub function instead. + + * include/grub/misc.h (grub_strchrsub): New function. + +2010-11-24 Colin Watson + + * util/deviceiter.c (grub_util_iterate_devices): Save a bit of + effort by skipping "." and ".." entries up-front. + Suggested by: Michael Lazarev. + +2010-11-24 Colin Watson + + * grub-core/Makefile.core.def (xz_decompress): Move -lgcc from + ldflags to ldadd, to fix link line ordering. + (none_decompress): Likewise. + +2010-11-24 Colin Watson + + * grub-core/Makefile.core.def (kernel): Add kern/emu/cache.S for emu + platforms. + (grub-emu-lite): Remove kern/emu/cache.S. + +2010-11-23 Colin Watson + + * util/deviceiter.c (compare_devices): If the by-id link for a + device couldn't be resolved, fall back to sorting by the by-id link + rather than segfaulting. + Reported and tested by: Daniel Mierswa. + +2010-11-23 Colin Watson + + * Makefile.util.def (grub-menulst2cfg): List libraries in ldadd, not + ldflags, to fix link line ordering. + +2010-11-23 Colin Watson + + * grub-core/Makefile.am (gentrigtables): Put -lm after $<; some + linkers are picky about this. + +2010-11-23 Colin Watson + + * grub-core/Makefile.am (command.lst): Adjust sed expression + ordering so that extended and priority commands aren't treated as + ordinary commands. + +2010-11-23 Colin Watson + + * include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_BIOS_BOOT): + Remove byte-swapping function calls, which are not valid in + structure initialisers. + * grub-core/partmap/gpt.c (grub_gpt_partition_type_bios_boot): Make + non-const. + (GRUB_MOD_INIT): Byte-swap data1, data2, and data3 fields of + grub_gpt_partition_type_bios_boot. + +2010-11-22 Colin Watson + + Fix test program build on GNU/kFreeBSD. + + * Makefile.util.def (example_unit_test): Add `$(LIBZFS) + $(LIBNVPAIR)' library dependencies. + +2010-11-22 Colin Watson + + * util/grub-install.in: Fix parsing of --grub-mkrelpath= option. + +2010-11-22 Colin Watson + + * util/grub-install.in: Remove excessive quoting that broke + installations to RAID devices. + +2010-11-19 Vladimir Serbinenko + + * grub-core/loader/i386/linux.c (grub_cmd_linux): Pass correctly the + bootloader version instead of 0. + +2010-11-19 Vladimir Serbinenko + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Fix spurious + warning. + +2010-11-19 Vladimir Serbinenko + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Don't try to + retrieve the metadat sector if size isn't known. + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise. + +2010-11-18 Robert Millan + + * grub-core/fs/btrfs.c (grub_btrfs_mount): Replace grub_strncmp() + with grub_memcmp(). + +2010-11-18 Vladimir Serbinenko + + * grub-core/normal/menu_entry.c (print_up): Fix displacement of up + arrow. + Reported by: Jordan Uggla. + +2010-11-16 Vladimir Serbinenko + + Make better UTF compliant. + + * grub-core/normal/charset.c (grub_utf8_to_utf16): Handle 6- and 7-byte + sequences as incorrect. + (grub_is_valid_utf8): Likewise. + (grub_utf8_to_ucs4): Likewise. + (grub_ucs4_to_utf8): Handle codepoints outside of BMP. + (grub_ucs4_to_utf8_alloc): Likewise. + * include/grub/charset.h (grub_utf16_to_utf8): Likewise. + +2010-11-16 Vladimir Serbinenko + + Make legacy_source behave like source. + + * grub-core/commands/legacycfg.c (legacy_file): Don't call + grub_show_menu. + (grub_cmd_legacy_source): Call grub_show_menu if needed. + +2010-11-16 Colin Watson + + * conf/Makefile.common (CFLAGS_GNULIB): Add -Wno-unused-parameter. + (-Wunused implies -Wunused-parameter, but not vice versa). + +2010-11-16 Colin Watson + + * configure.ac: Make error messages less confusing by testing for + -Wtrampolines rather than -Wno-trampolines (since -Wno-* is always + accepted, but produces a diagnostic if something else is wrong). + +2010-11-15 Vladimir Serbinenko + + * grub-core/term/at_keyboard.c (grub_keyboard_controller_read) + [GRUB_MACHINE_MIPS_YEELOONG || GRUB_MACHINE_QEMU]: ifdef-ed out + (now unused). + (grub_keyboard_controller_init) + [GRUB_MACHINE_MIPS_YEELOONG || GRUB_MACHINE_QEMU]: Don't attempt to + read the initial state since controller isn't inited yet. + +2010-11-15 Vladimir Serbinenko + + * grub-core/lib/relocator.c (malloc_in_range): Take into account that + allocate_regbeg may need to create new chunk header. + +2010-11-14 Vladimir Serbinenko + + Fix quoting in legacy parser. + + * grub-core/lib/legacy_parse.c (grub_legacy_escape): Correctly handle + single quotes. + (grub_legacy_parse): Likewise. + Reported by: Jordan Uggla. + Tested by: Jordan Uggla. + +2010-11-14 Vladimir Serbinenko + + Don't add -lgcc on i386 and x86_64. + + * configure.ac (LIBS): Don't add -lgcc on i386 and x86_64. + * conf/Makefile.common (LDADD_KERNEL): Likewise. + * grub-core/Makefile.core.def (kernel): Use LDADD_KERNEL. + +2010-11-14 Vladimir Serbinenko + + * configure.ac: Add -Wno-trampolines when supported. + +2010-11-14 Modestas Vainius + + * grub-core/kern/emu/getroot.c (grub_util_is_dmraid): Recognise ddf1_ + fakeraid. + +2010-11-14 Giuseppe Caizzone + + Add generic logical block size support for UDF. + + * grub-core/fs/udf.c (GRUB_UDF_LOG2_BLKSIZE): Removed. + (GRUB_UDF_BLKSZ): Removed. + (struct grub_udf_data): New field "lbshift" to hold the logical block + size of the file system in log2 format. All users updated. + (sblocklist): Change type to unsigned. + (grub_udf_mount): Change type of "sblklist" to unsigned. + Move AVDP search before VRS recognition, because the latter requires + knowledge of the logical block size, which is detected during the + former. + Detect and validate logical block size during AVDP search, adding + support for block sizes 512, 1024 and 4096. + Make VRS recognition independent of block size. + +2010-11-14 Giuseppe Caizzone + + Properly handle deleted files on UDF. + + * grub-core/fs/udf.c (grub_udf_iterate_dir): Skip directory entries + whose "characteristics" field has the bit GRUB_UDF_FID_CHAR_DELETED + set. + +2010-11-14 Giuseppe Caizzone + + Support reading files larger than 2 GiB. + + * grub-core/fs/udf.c (grub_udf_iterate_dir): Change type of variable + "offset" to grub_off_t. + (grub_udf_read_file): Likewise for parameter "pos". + +2010-11-14 Vladimir Serbinenko + + * docs/grub.texi (Changes from GRUB Legacy): Note when save_env is + unavailable. + (Simple configuration): Refer to Changes from GRUB Legacy about + save_env availability. + +2010-11-14 Vladimir Serbinenko + + * util/grub-install.in: Ignore empty partition table detection + instead of trying to include part_ module. + +2010-11-14 Vladimir Serbinenko + + * grub-core/disk/lvm.c (GRUB_MOD_FINI): Reset the vg_list. Fixes + LVM on RAID support. + +2010-11-14 Vladimir Serbinenko + + Properly define WORDS_BIGENDIAN in wrapped environments. + + * grub-core/lib/libgcrypt_wrap/cipher_wrap.h (WORDS_BIGENDIAN): New + definition. + * grub-core/lib/posix_wrap/sys/types.h (WORDS_BIGENDIAN): Likewise. + + Reported by: Manoel Rebelo Abranches. + Tested by: Manoel Rebelo Abranches. + +2010-11-13 Vladimir Serbinenko + + * util/grub-mkconfig.in: Fix quoting. + +2010-11-13 Vladimir Serbinenko + + Support big ext2 files. + + * grub-core/fs/ext2.c (grub_ext2_inode): Rename dir_acl to size_high. + (grub_ext2_read_block): Support triple indirect blocks. + (grub_ext2_read_file): Use 64-bit types and read size_high. + (grub_ext2_open): Read size_high. + Reported by: Ximin Luo. + Tested by: Manoel Rebelo Abranches. + +2010-11-13 Vladimir Serbinenko + + * util/grub-install.in: Handle filenames containing spaces. + Reported by: Jordan Uggla. + Tested by: Jordan Uggla. + +2010-11-13 Vladimir Serbinenko + + * util/grub-mkconfig.in (grub_script_check): New variable. + Use grub_script_check instead of grub-script-check. + Reported by: Barry Jackson. + +2010-11-13 Vladimir Serbinenko + + * docs/grub.texi (menu): Correct the order. + Reported by: D. Hugh Redelmeier. + +2010-11-12 Vladimir Serbinenko + + * grub-core/kern/i386/pc/startup.S (multiboot_trampoline): Add missing + jump. + +2010-11-08 Manoel Rebelo Abranches + + * include/grub/elfload.h (grub_elf32_size): New parameter. + All users updated. + Return maximum segments alignment. + (grub_elf64_size): Likewise. + * kern/elf.c (grub_elf32_size): New parameter. All users updated. + Return maximum segments alignment. + (grub_elf64_size): Likewise. + * grub-core/loader/powerpc/ieee1275/linux.c: + (grub_linux_claimmap_iterate): New function. Uses the + "available" property in the "memory" node for memory allocation + for kernel in the PowerPC loader. + (grub_linux_load32): Correctly find linux entry point offset. + (grub_linux_load64): Likewise. + +2010-11-07 Robert Millan + + On mips-yeeloong, build with -march=loongson2f when this flag is + available (GCC >= 4.4). + * conf/Makefile.common [COND_mips_yeeloong] (CFLAGS_PLATFORM): Remove + `-march=mips3'. + * configure.ac: For mips-yeeloong, add -march=loongson2f if available, + or otherwise add -march=mips3. + +2010-11-07 BVK Chaitanya + + Suppress shell expansion on echo '*' and echo "*" like cases. + Reported by: Jordan Uggla. + + * grub-core/script/execute.c (grub_script_arglist_to_argv): Escape + string arguments before shell expansion. + * tests/grub_cmd_echo.in: New testcases. + +2010-11-07 Robert Millan + + * conf/mips-qemu-mips.rmk: Remove stale file from previous + transition. + +2010-11-07 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Handle devices like "sdaa1". + +2010-11-06 Vladimir Serbinenko + + * include/grub/emu/misc.h: Don't include grub/util/libzfs.h. + * include/grub/emu/misc.h (grub_get_libzfs_handle): Move from here ... + * include/grub/util/libzfs.h (grub_get_libzfs_handle): ... here. + +2010-11-06 Vladimir Serbinenko + + * grub-core/fs/ntfs.c (grub_ntfs_uuid): Make uppercase. + +2010-11-06 Vladimir Serbinenko + + * util/grub-install.in: Replace useless recomendation to pass + --modules with a recomendation to report a bug. + +2010-11-06 Vladimir Serbinenko + + Properly register serial terminfo. + Reported by: Jordan Uggla + + * grub-core/term/serial.c (grub_serial_terminfo_input_template): New + const. + (grub_serial_terminfo_output_template): Likewise. + (grub_cmd_serial): Register "serial" with terminfo. + (GRUB_MOD_INIT(serial)): Fill grub_serial_terminfo_input and + grub_serial_terminfo_output. + +2010-11-05 Robert Millan + + * util/grub-mkconfig.in: Remove gfxterm.mod probe (no longer + needed). + +2010-11-05 Robert Millan + + On Yeeloong, pass machine type information to Linux. + + * grub-core/loader/mips/linux.c [GRUB_MACHINE_MIPS_YEELOONG] + (LOONGSON_MACHTYPE): New macro, set to + "machtype=lemote-yeeloong-2f-8.9inches". + [LOONGSON_MACHTYPE] (grub_cmd_linux): Pass LOONGSON_MACHTYPE as + additional argument to Linux. + +2010-11-04 Robert Millan + + * util/deviceiter.c (grub_util_iterate_devices): Increase SCSI + limit to 48 (to cope with Sun Fire X4500), and IDE limit to 96 + (its SATA disks are detected as slaveless IDE master drives on + kFreeBSD). + Reported by Carsten Aulbert. + +2010-11-02 Colin Watson + + * util/bin2h.c (main): Fix spelling error in generated output. + +2010-11-01 Grégoire Sutre + + * grub-core/partmap/bsdlabel.c (iterate_real): Fix an integer overflow. + +2010-11-01 Vladimir Serbinenko + + * grub-core/loader/i386/linux.c (grub_cmd_linux): Autoload vbe.mod if + vga= option is supplied. + +2010-11-01 Vladimir Serbinenko + + * util/grub.d/10_hurd.in: Don't call savedefault on recovery entries. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub.d/20_linux_xen.in: Likewise. + +2010-11-01 Vladimir Serbinenko + + * grub-core/lib/arg.c (grub_arg_parse): Avoid interpreting direct + argument as an argument to no-argument option. + +2010-11-01 Vladimir Serbinenko + + * util/grub.d/10_linux.in: Add missing load_video with explicit + GRUB_GFXPAYLOAD_LINUX. + +2010-11-01 Vladimir Serbinenko + + * Makefile.am (libgrub.pp): Propagate the libgrub.a split. + +2010-11-01 Vladimir Serbinenko + + * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Do not put + elements with invlid index. + * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise. + * grub-core/disk/raid.c (insert_array): Automatically reallocate + members. + * include/grub/raid.h (grub_raid_member): New struct. + (grub_raid_array): Transform devices and start_sector into usage of + grub_raid_member. All users updated + (allocated_devs): New member. + +2010-11-01 Vladimir Serbinenko + + * docs/man/grub-set-default.h2m: Clarify that only saved default entry + is modified + +2010-10-29 BVK Chaitanya + + NetBSD build fix for getline function conflict from gnulib. + + * Makefile.util.def (libgrubkern.a): New library for grub kernel + components that depend on gnulib headers. + (libgrubmods.a): Renamed from earlier libgrub.a. + * conf/Makefile.common: Remove gnulib from *_LIBRARY flags. + +2010-10-26 Vladimir Serbinenko + + * util/grub-setup.c (setup): Refuse to do a cross-disk embeddingless + install rather than creating a broken install. + +2010-10-26 Vladimir Serbinenko + + * util/grub-setup.c (argp): Remove misleading example of installing to + a partition. + +2010-10-26 Vladimir Serbinenko + + * util/grub-setup.c (setup): Clarify the error message. + +2010-10-26 Vladimir Serbinenko + + * include/grub/types.h (grub_target_off_t): Removed no longer used type. + +2010-10-23 Vladimir Serbinenko + + * grub-core/kern/emu/misc.c + (grub_make_system_path_relative_to_its_root) + [HAVE_LIBZFS && HAVE_LIBNVPAIR]: Fix mountpoint return on ZFS. + +2010-10-23 Vladimir Serbinenko + + * grub-core/kern/emu/misc.c + (grub_make_system_path_relative_to_its_root): Revert r2882. + +2010-10-22 Vladimir Serbinenko + + * grub-core/lib/relocator.c (grub_relocator_subchunk): Remove now + useless field head. All users updated. + (free_subchunk): Correct handling of IN_REGION subchunk. + +2010-10-22 Colin Watson + + * docs/grub.texi (Installing GRUB using grub-install): Proofread. + (Supported kernels): Likewise. + +2010-10-18 Grégoire Sutre + + Make mktemp invocations portable. + + * grub-core/genmod.sh.in: Use mktemp with an explicit template, and + exit if mktemp fails. + * tests/grub_script_blockarg.in: Likewise. + * tests/partmap_test.in: Likewise. + * tests/util/grub-shell-tester.in: Likewise. + * tests/util/grub-shell.in: Likewise. + * util/powerpc/ieee1275/grub-mkrescue.in: Likewise. + * Makefile.am: Likewise, and chain shell commands with `&&' + instead of ';'. + * util/grub-mkrescue.in: Use the same explicit template as above, and + exit if mktemp fails. + +2010-10-18 BVK Chaitanya + + * util/grub.d/10_linux.in: Fix built-in initramfs image mode for + Linux kernel, reported by Dennis Schridde. + +2010-10-17 Szymon Janc + + * grub-core/normal/auth.c (grub_auth_check_authentication): + Set-but-not-used variable removed. + +2010-10-17 Vladimir Serbinenko + + * docs/grub.texi (GNU/Linux): Document APM unavailability with + 32-bit linux protocol. + +2010-10-17 Vladimir Serbinenko + + * grub-core/kern/i386/pc/startup.S (grub_console_setcursor): Check + cursor shape for sanity. + +2010-10-17 Vladimir Serbinenko + + * docs/grub.texi (Installation): Document buggy BIOS install. + +2010-10-17 Vladimir Serbinenko + + * docs/grub.texi (Installation): Indent. + +2010-10-17 Vladimir Serbinenko + + * util/grub-setup.c (setup): New parameter allow_floppy. + (arguments): New member allow_floppy. + (argp_parser): Handle --allow-floppy. + (main): Pass allow_floppy. + * util/grub-install.in: New option --allow-floppy passed though to + grub-setup. + +2010-10-17 Vladimir Serbinenko + + * util/grub-install.in: Handle partitionless disks. + +2010-10-17 Vladimir Serbinenko + + * util/grub-setup.c (setup): Don't clean blocklists before readability + verfification. + +2010-10-16 Vladimir Serbinenko + + * docs/grub.texi (Installation): Document embedding zone. Remove + obsolete grub-install example. + +2010-10-16 Szymon Janc + + * grub-core/commands/legacycfg.c (grub_cmd_legacy_kernel): + Set-but-not-used variable ifdef'ed. + * grub-core/lib/legacy_parse.c (grub_legacy_parse): Likewise. + * grub-core/bus/usb/ohci.c (grub_ohci_pci_iter): Set-but-not-used + variable removed. + * grub-core/disk/lvm.c (grub_lvm_scan_device): Likewise. + * grub-core/fs/jfs.c (grub_jfs_find_file): Likewise. + * grub-core/fs/minix.c (grub_minix_dir): Likewise. + * grub-core/fs/sfs.c (grub_sfs_read_extent): Likewise. + * grub-core/fs/ufs.c (grub_ufs_dir): Likewise. + * grub-core/gfxmenu/gui_list.c (grub_gui_list_new): Likewise. + * grub-core/gfxmenu/view.c (redraw_menu_visit): Likewise. + * grub-core/gfxmenu/widget-box.c (draw): Likewise. + * grub-core/lib/relocator.c (malloc_in_range): Likewise. + * grub-core/loader/i386/bsdXX.c (grub_netbsd_load_elf_meta): Likewise. + * grub-core/loader/i386/bsd_pagetable.c (fill_bsd64_pagetable): + Likewise. + +2010-10-16 Vladimir Serbinenko + + * grub-core/commands/acpihalt.c (skip_ext_op): Skip index field op. + * include/grub/acpi.h (GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP): New + enum value. + +2010-10-16 Vladimir Serbinenko + + * grub-core/commands/acpihalt.c (get_sleep_type): Accept \_S5_ as + synonym to _S5_. Needed for some DSDTs. + +2010-10-16 Vladimir Serbinenko + + Userspace ACPI parser debugging. + + * grub-core/commands/acpihalt.c [GRUB_DSDT_TEST]: Include userspace + headers and add relevant defines. Don't include standard headers. + (main) [GRUB_DSDT_TEST]: New function. + * include/grub/acpi.h [GRUB_DSDT_TEST]: Don't include standard headers. + Don't declare functions. + +2010-10-16 Vladimir Serbinenko + + Remove dead grub_efi_mm_fini. + + * grub-core/kern/efi/mm.c (allocated_page): Removed. + (ALLOCATED_PAGES_SIZE): Likewise. + (MAX_ALLOCATED_PAGES): Likewise. + (allocated_pages): Likewise. + (grub_efi_allocate_pages): Don't record allocated pages. + (grub_efi_free_pages): Likewise. + (grub_efi_mm_init): Likewise. + (grub_efi_mm_fini): Removed. + +2010-10-16 Vladimir Serbinenko + + * grub-core/kern/efi/mm.c (BYTES_TO_PAGES): Round up instead of down. + (grub_efi_mm_init): Take into account the memory map size increase. + +2010-10-16 Vladimir Serbinenko + + * grub-core/term/ns8250.c (do_real_config): Set port->broken to 0. + (serial_hw_put): Wait based on real time rather than port reads. Don't + roken ports. + * include/grub/serial.h (grub_serial_port): New field broken. + +2010-10-16 Robert Millan + + * grub-core/kern/emu/misc.c + (grub_make_system_path_relative_to_its_root): Fix premature return + when processing non-root ZFS filesystems. + Reported by Sergio Talens-Oliag. + +2010-10-15 Robert Millan + + * util/grub.d/10_linux.in (list): Expand "vmlinu[zx]" instances to + guarantee compressed ones are processed first. + +2010-10-14 Vladimir Serbinenko + + * grub-core/efiemu/main.c (grub_efiemu_prepare): Handle errors from + grub_efiemu_autocore. + +2010-10-14 Vladimir Serbinenko + + * grub-core/kern/i386/pc/startup.S (bypass_table): Use 0x1b explicitly + rather than 0x1b. + (grub_console_getkey): Use correct jae opcode rather than ja. + +2010-10-12 Robert Millan + + * util/grub-mkconfig.in: Merge `GRUB_DISABLE_LINUX_RECOVERY' and + `GRUB_DISABLE_NETBSD_RECOVERY' into a single `GRUB_DISABLE_RECOVERY' + variable. All references updated. + + * util/grub.d/10_kfreebsd.in: Support recovery boot entries. + +2010-10-08 Vladimir Serbinenko + + Correctly distinguish mdraid flavours. + + * grub-core/disk/raid.c (grub_raid_getname) [GRUB_UTIL]: New function. + (insert_array): New argument raid. + * include/grub/disk.h (grub_disk_dev) [GRUB_UTIL]: New member raidname. + * include/grub/raid.h (grub_raid_array) [GRUB_UTIL]: New member driver. + * util/grub-probe.c (probe): PRint raidname instead of plainly "mdraid". + +2010-10-09 Vladimir Serbinenko + + * grub-core/kern/i386/pc/startup.S (grub_console_getkey): Fix incorrect + handling of special keys. 2010-10-02 Aleš Nesrsta - * grub-core/bus/usb/ohci.c, grub-core/bus/usb/uhci.c: - Increased number of TDs. + * include/grub/scsi.h (grub_make_scsi_id): Fix incorrect usgae of + GRUB_SCSI_ID_BUS_SHIFT instead of GRUB_SCSI_ID_LUN_SHIFT. + +2010-10-02 Aleš Nesrsta + + * grub-core/bus/usb/ohci.c (GRUB_OHCI_TDS): Increase. + * grub-core/bus/usb/uhci.c (N_TD): New definition. All previous implicit + users updated. * grub-core/bus/usb/usbtrans.c (grub_usb_bulk_setup_readwrite): - Corrected endpoint maxpacket size. + Use right endpoint when querying descriptor. 2010-10-01 Vladimir Serbinenko diff --git a/Makefile.am b/Makefile.am index 931ea02e8..99b141e07 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -AUTOMAKE_OPTIONS = subdir-objects +AUTOMAKE_OPTIONS = subdir-objects -Wno-portability DEPDIR = .deps-util SUBDIRS = grub-core/gnulib . grub-core po docs util/bash-completion.d @@ -33,8 +33,8 @@ grub_script.yy.c: grub_script.yy.h CLEANFILES += grub_script.yy.c grub_script.yy.h # For libgrub.a -libgrub.pp: grub_script.tab.h grub_script.yy.h $(libgrub_a_SOURCES) - $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgrub_a_CPPFLAGS) $(CPPFLAGS) \ +libgrub.pp: grub_script.tab.h grub_script.yy.h $(libgrubmods_a_SOURCES) $(libgrubkern_a_SOURCES) + $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgrubmods_a_CPPFLAGS) $(libgrubkern_a_CPPFLAGS) $(CPPFLAGS) \ -D'GRUB_MOD_INIT(x)=@MARKER@x@' $^ > $@ || (rm -f $@; exit 1) CLEANFILES += libgrub.pp @@ -101,8 +101,7 @@ CLEANFILES += widthspec.h # Install config.h into platformdir platform_HEADERS = config.h -pkglib_DATA += grub-mkconfig_lib -pkglib_DATA += update-grub_lib +pkgdata_DATA += grub-mkconfig_lib if COND_i386_coreboot @@ -147,28 +146,28 @@ 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 + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -DTARGET_MULTIBOOT=1 -Wl,--build-id=none -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 + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,--build-id=none -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 + $(TARGET_CC) -o $@ $< -DTARGET_CHAINLOADER=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,--build-id=none -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 + $(TARGET_CC) -o $@ $< -DTARGET_NTLDR=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,--build-id=none -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 + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,--build-id=none -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 $@ @@ -189,31 +188,31 @@ 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 + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 $@ + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 $@ + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 + TDIR=`mktemp -d "$${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` && 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 $@ diff --git a/Makefile.util.def b/Makefile.util.def index c1fd077f7..9902584ba 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -1,9 +1,43 @@ AutoGen definitions Makefile.tpl; library = { - name = libgrub.a; - cflags = '$(CFLAGS_GCRY)'; - cppflags = '$(CPPFLAGS_GCRY)'; + name = libgrubkern.a; + cflags = '$(CFLAGS_GNULIB)'; + cppflags = '$(CPPFLAGS_GNULIB)'; + + common = util/misc.c; + common = grub-core/kern/command.c; + common = grub-core/kern/device.c; + common = grub-core/kern/disk.c; + common = util/getroot.c; + common = util/raid.c; + common = grub-core/kern/emu/hostdisk.c; + common = grub-core/kern/emu/misc.c; + common = grub-core/kern/emu/mm.c; + common = grub-core/kern/env.c; + common = grub-core/kern/err.c; + common = grub-core/kern/file.c; + common = grub-core/kern/fs.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/kern/partition.c; + common = grub-core/lib/crypto.c; + common = grub-core/disk/luks.c; + common = grub-core/disk/geli.c; + common = grub-core/disk/cryptodisk.c; + common = grub-core/disk/AFSplitter.c; + common = grub-core/lib/pbkdf2.c; + common = grub-core/commands/extcmd.c; + common = grub-core/lib/arg.c; + common = grub-core/disk/ldm.c; + common = grub-core/disk/diskfilter.c; + common = grub-core/partmap/gpt.c; +}; + +library = { + name = libgrubmods.a; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(top_srcdir)/grub-core/lib/minilzo -I$(srcdir)/grub-core/lib/xzembed -DMINILZO_HAVE_CONFIG_H'; common_nodist = grub_script.tab.c; common_nodist = grub_script.yy.c; @@ -11,15 +45,9 @@ library = { common_nodist = grub_script.yy.h; common_nodist = grub_script.tab.h; - common = util/misc.c; - common = grub-core/kern/misc.c; - common = grub-core/kern/emu/mm.c; - common = grub-core/kern/emu/misc.c; - common = grub-core/kern/emu/getroot.c; - common = grub-core/kern/emu/hostdisk.c; - common = grub-core/commands/blocklist.c; - common = grub-core/commands/extcmd.c; + common = grub-core/commands/xnu_uuid.c; + common = grub-core/commands/testload.c; common = grub-core/commands/ls.c; common = grub-core/disk/dmraid_nvidia.c; common = grub-core/disk/loopback.c; @@ -28,16 +56,17 @@ library = { common = grub-core/disk/mdraid1x_linux.c; common = grub-core/disk/raid5_recover.c; common = grub-core/disk/raid6_recover.c; - common = grub-core/disk/raid.c; common = grub-core/fs/affs.c; - common = grub-core/fs/afs_be.c; common = grub-core/fs/afs.c; - common = grub-core/fs/befs_be.c; - common = grub-core/fs/befs.c; + common = grub-core/fs/bfs.c; common = grub-core/fs/btrfs.c; common = grub-core/fs/cpio.c; + common = grub-core/fs/cpio_be.c; + common = grub-core/fs/odc.c; + common = grub-core/fs/newc.c; common = grub-core/fs/ext2.c; common = grub-core/fs/fat.c; + common = grub-core/fs/exfat.c; common = grub-core/fs/fshelp.c; common = grub-core/fs/hfs.c; common = grub-core/fs/hfsplus.c; @@ -45,42 +74,41 @@ library = { common = grub-core/fs/jfs.c; common = grub-core/fs/minix.c; common = grub-core/fs/minix2.c; + common = grub-core/fs/minix3.c; common = grub-core/fs/nilfs2.c; common = grub-core/fs/ntfs.c; common = grub-core/fs/ntfscomp.c; common = grub-core/fs/reiserfs.c; + common = grub-core/fs/romfs.c; common = grub-core/fs/sfs.c; + common = grub-core/fs/squash4.c; common = grub-core/fs/tar.c; common = grub-core/fs/udf.c; common = grub-core/fs/ufs2.c; common = grub-core/fs/ufs.c; common = grub-core/fs/xfs.c; - common = grub-core/kern/command.c; - common = grub-core/kern/device.c; - common = grub-core/kern/disk.c; - common = grub-core/kern/env.c; - common = grub-core/kern/err.c; - common = grub-core/kern/file.c; - common = grub-core/kern/fs.c; - common = grub-core/kern/list.c; - common = grub-core/kern/partition.c; - common = grub-core/lib/arg.c; - common = grub-core/lib/crypto.c; + common = grub-core/fs/zfs/zfscrypt.c; + common = grub-core/fs/zfs/zfs.c; + common = grub-core/fs/zfs/zfsinfo.c; + common = grub-core/fs/zfs/zfs_lzjb.c; + common = grub-core/fs/zfs/zfs_sha256.c; + common = grub-core/fs/zfs/zfs_fletcher.c; common = grub-core/lib/envblk.c; common = grub-core/lib/hexdump.c; - common = grub-core/lib/libgcrypt-grub/cipher/sha512.c; - common = grub-core/lib/libgcrypt-grub/cipher/crc.c; common = grub-core/lib/LzFind.c; common = grub-core/lib/LzmaEnc.c; - common = grub-core/lib/pbkdf2.c; + common = grub-core/lib/crc.c; + common = grub-core/lib/adler32.c; + common = grub-core/lib/crc64.c; common = grub-core/normal/datetime.c; common = grub-core/normal/misc.c; common = grub-core/partmap/acorn.c; common = grub-core/partmap/amiga.c; common = grub-core/partmap/apple.c; - common = grub-core/partmap/gpt.c; common = grub-core/partmap/msdos.c; common = grub-core/partmap/sun.c; + common = grub-core/partmap/plan.c; + common = grub-core/partmap/dvh.c; common = grub-core/partmap/sunpc.c; common = grub-core/partmap/bsdlabel.c; common = grub-core/script/function.c; @@ -88,15 +116,24 @@ library = { common = grub-core/script/main.c; common = grub-core/script/script.c; common = grub-core/script/argv.c; + common = grub-core/io/gzio.c; + common = grub-core/io/lzopio.c; + common = grub-core/kern/ia64/dl_helper.c; + common = grub-core/lib/minilzo/minilzo.c; + common = grub-core/lib/xzembed/xz_dec_bcj.c; + common = grub-core/lib/xzembed/xz_dec_lzma2.c; + common = grub-core/lib/xzembed/xz_dec_stream.c; }; program = { name = grub-bin2h; common = util/bin2h.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; - mansection = 1; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; + installdir = noinst; }; program = { @@ -107,10 +144,12 @@ program = { common = util/resolve.c; extra_dist = util/grub-mkimagexx.c; - ldadd = libgrub.a; - ldadd = '$(LIBLZMA)'; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBLZMA)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; cppflags = '-DGRUB_PKGLIBROOTDIR=\"$(pkglibrootdir)\"'; }; @@ -120,9 +159,11 @@ program = { common = util/grub-mkrelpath.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -131,9 +172,11 @@ program = { common = util/grub-script-check.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -142,9 +185,11 @@ program = { common = util/grub-editenv.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -153,9 +198,11 @@ program = { common = util/grub-mkpasswd-pbkdf2.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; cflags = '$(CFLAGS_GCRY)'; cppflags = '$(CPPFLAGS_GCRY)'; }; @@ -172,9 +219,11 @@ program = { mansection = 1; common = util/grub-pe2elf.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL)'; condition = COND_GRUB_PE2ELF; }; @@ -189,9 +238,27 @@ program = { cflags = '$(CFLAGS_GCRY)'; cppflags = '$(CPPFLAGS_GCRY)'; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +}; + +program = { + name = grub-mount; + mansection = 1; + common_nodist = grub_fstest_init.c; + common = util/grub-mount.c; + common = grub-core/kern/emu/hostfs.c; + common = grub-core/disk/host.c; + + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) -lfuse'; + condition = COND_GRUB_MOUNT; }; program = { @@ -202,10 +269,12 @@ program = { cflags = '$(freetype_cflags)'; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(freetype_libs)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; condition = COND_GRUB_MKFONT; }; @@ -216,14 +285,13 @@ program = { common = util/grub-mkdevicemap.c; common = util/deviceiter.c; - nosparc64 = util/devicemap.c; + common = util/devicemap.c; - sparc64_ieee1275 = util/ieee1275/ofpath.c; - sparc64_ieee1275 = util/ieee1275/devicemap.c; - - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -231,10 +299,13 @@ program = { installdir = sbin; mansection = 8; common = util/grub-probe.c; + common = util/ieee1275/ofpath.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -242,15 +313,16 @@ program = { installdir = sbin; mansection = 8; common = util/grub-setup.c; - common = util/raid.c; common = util/lvm.c; common = grub-core/lib/reed_solomon.c; sparc64_ieee1275 = util/ieee1275/ofpath.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubkern.a; + ldadd = libgrubgcry.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; enable = i386_pc; enable = sparc64_ieee1275; @@ -259,12 +331,16 @@ program = { program = { name = grub-ofpathname; installdir = sbin; + mansection = 8; ieee1275 = util/ieee1275/grub-ofpathname.c; ieee1275 = util/ieee1275/ofpath.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBGEOM)'; + enable = sparc64_ieee1275; }; @@ -274,9 +350,11 @@ program = { common = util/grub-mklayout.c; - ldadd = libgrub.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; data = { @@ -311,6 +389,13 @@ script = { condition = COND_HOST_KFREEBSD; }; +script = { + name = '10_illumos'; + common = util/grub.d/10_illumos.in; + installdir = grubconf; + condition = COND_HOST_ILLUMOS; +}; + script = { name = '10_netbsd'; common = util/grub.d/10_netbsd.in; @@ -356,13 +441,20 @@ script = { x86 = util/grub-mkrescue.in; powerpc_ieee1275 = util/powerpc/ieee1275/grub-mkrescue.in; enable = i386_pc; - enable = x86_efi; + enable = i386_efi; + enable = x86_64_efi; enable = i386_qemu; enable = i386_multiboot; enable = i386_coreboot; enable = powerpc_ieee1275; }; +script = { + mansection = 1; + name = grub-mkstandalone; + common = util/grub-mkstandalone.in; +}; + script = { mansection = 8; installdir = sbin; @@ -407,12 +499,6 @@ script = { installdir = noinst; }; -script = { - name = update-grub_lib; - common = util/update-grub_lib.in; - installdir = noinst; -}; - script = { name = grub-kbdcomp; common = util/grub-kbdcomp.in; @@ -583,9 +669,26 @@ program = { common = grub-core/kern/misc.c; common = grub-core/tests/lib/test.c; cflags = -Wno-format; - ldadd = libgrub.a; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; - ldadd = '$(LIBDEVMAPPER)'; + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; +}; + +program = { + testcase; + name = printf_test; + common = tests/printf_unit_test.c; + common = tests/lib/unit_test.c; + common = grub-core/kern/list.c; + common = grub-core/kern/misc.c; + common = grub-core/tests/lib/test.c; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -595,7 +698,9 @@ program = { common = grub-core/lib/legacy_parse.c; common = grub-core/lib/i386/pc/vesa_modes_table.c; - ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; diff --git a/NEWS b/NEWS index 7fce921d6..2a93c2526 100644 --- a/NEWS +++ b/NEWS @@ -29,7 +29,7 @@ New in 1.99: * New `lsacpi' command. -* Basic btrfs support (detection and UUID). +* Btrfs support. * New `--boot-directory' option to `grub-install', `grub-reboot', and `grub-set-default', with clearer semantics than the previous @@ -51,9 +51,7 @@ New in 1.99: * 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). +* ZFS support. * Support 1.x versions of mdadm metadata. @@ -85,10 +83,6 @@ New in 1.99: * 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. diff --git a/acinclude.m4 b/acinclude.m4 index 7c38155d4..5c623baee 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -316,14 +316,14 @@ fi dnl Check if the C compiler generates calls to `__enable_execute_stack()'. AC_DEFUN([grub_CHECK_ENABLE_EXECUTE_STACK],[ AC_MSG_CHECKING([whether `$CC' generates calls to `__enable_execute_stack()']) -AC_LANG_CONFTEST([[ +AC_LANG_CONFTEST([AC_LANG_SOURCE([[ void f (int (*p) (void)); void g (int i) { int nestedfunc (void) { return i; } f (nestedfunc); } -]]) +]])]) if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -S conftest.c]) && test -s conftest.s; then true else @@ -346,7 +346,9 @@ AC_DEFUN([grub_CHECK_STACK_PROTECTOR],[ ssp_possible=yes] AC_MSG_CHECKING([whether `$CC' accepts `-fstack-protector']) # Is this a reliable test case? -AC_LANG_CONFTEST([[void foo (void) { volatile char a[8]; a[3]; }]]) +AC_LANG_CONFTEST([AC_LANG_SOURCE([[ +void foo (void) { volatile char a[8]; a[3]; } +]])]) [# `$CC -c -o ...' might not be portable. But, oh, well... Is calling # `ac_compile' like this correct, after all? if eval "$ac_compile -S -fstack-protector -o conftest.s" 2> /dev/null; then] @@ -364,7 +366,9 @@ AC_DEFUN([grub_CHECK_STACK_ARG_PROBE],[ [# Smashing stack arg probe. sap_possible=yes] AC_MSG_CHECKING([whether `$CC' accepts `-mstack-arg-probe']) -AC_LANG_CONFTEST([[void foo (void) { volatile char a[8]; a[3]; }]]) +AC_LANG_CONFTEST([AC_LANG_SOURCE([[ +void foo (void) { volatile char a[8]; a[3]; } +]])]) [if eval "$ac_compile -S -mstack-arg-probe -o conftest.s" 2> /dev/null; then] AC_MSG_RESULT([yes]) [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? @@ -399,7 +403,7 @@ AC_DEFUN([grub_CHECK_PIE],[ pie_possible=yes] AC_MSG_CHECKING([whether `$CC' has `-fPIE' as default]) # Is this a reliable test case? -AC_LANG_CONFTEST([[ +AC_LANG_CONFTEST([AC_LANG_SOURCE([[ #ifdef __PIE__ int main() { return 0; @@ -407,7 +411,7 @@ int main() { #else #error NO __PIE__ DEFINED #endif -]]) +]])]) [# `$CC -c -o ...' might not be portable. But, oh, well... Is calling # `ac_compile' like this correct, after all? diff --git a/autogen.sh b/autogen.sh index 96b1e33e2..db719cd1d 100755 --- a/autogen.sh +++ b/autogen.sh @@ -2,6 +2,10 @@ set -e +export LC_CTYPE=C +export LC_COLLATE=C +unset LC_ALL + autogen --version >/dev/null || exit 1 echo "Importing unicode..." @@ -22,7 +26,7 @@ if [ "x${GRUB_CONTRIB}" != x ]; then [ "${GRUB_CONTRIB}" = grub-core/contrib ] || ln -s ../contrib grub-core/contrib fi -UTIL_DEFS=Makefile.util.def +UTIL_DEFS='Makefile.util.def Makefile.utilgcry.def' CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def' for extra in contrib/*/Makefile.util.def; do diff --git a/conf/Makefile.common b/conf/Makefile.common index 81bb3567e..ed84e76d8 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -2,6 +2,10 @@ CFLAGS_PLATFORM= +export LC_COLLATE := C +export LC_CTYPE := C +unexport LC_ALL + # Platform specific options if COND_i386_pc CFLAGS_PLATFORM += -mrtd -mregparm=3 @@ -21,13 +25,13 @@ endif if COND_i386_ieee1275 CFLAGS_PLATFORM += -mrtd -mregparm=3 endif -if COND_mips_yeeloong - CFLAGS_PLATFORM += -march=mips3 -mexplicit-relocs +if COND_mips_loongson + CFLAGS_PLATFORM += -mexplicit-relocs CPPFLAGS_PLATFORM = -DUSE_ASCII_FAILBACK - CCASFLAGS_PLATFORM = -march=mips3 endif if COND_mips CFLAGS_PLATFORM += -mflush-func=grub_cpu_flush_cache + CCASFLAGS_PLATFORM = -march=mips3 endif if COND_sparc64_ieee1275 CFLAGS_PLATFORM += -mno-app-regs @@ -45,12 +49,33 @@ CPPFLAGS_DEFAULT += -I$(top_srcdir)/include CPPFLAGS_DEFAULT += -I$(top_builddir)/include CCASFLAGS_DEFAULT = -DASM_FILE=1 -LDADD_KERNEL = -lgcc +LDADD_KERNEL = + +if ! COND_i386_pc +if ! COND_i386_efi +if ! COND_i386_qemu +if ! COND_i386_coreboot +if ! COND_i386_multiboot +if ! COND_i386_ieee1275 +if ! COND_x86_64_efi +LDADD_KERNEL += -lgcc +endif +endif +endif +endif +endif +endif +endif + CFLAGS_KERNEL = $(CFLAGS_CPU) $(CFLAGS_PLATFORM) -ffreestanding LDFLAGS_KERNEL = $(LDFLAGS_CPU) $(LDFLAGS_PLATFORM) -nostdlib -Wl,-N -static-libgcc CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) +if COND_CYGWIN +STRIPFLAGS_KERNEL = -F elf32-i386 -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve +else STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment +endif CFLAGS_MODULE = $(CFLAGS_CPU) $(CFLAGS_PLATFORM) -ffreestanding LDFLAGS_MODULE = $(LDFLAGS_CPU) $(LDFLAGS_PLATFORM) -nostdlib -Wl,-N,-r,-d @@ -67,9 +92,9 @@ LDFLAGS_PROGRAM = CPPFLAGS_PROGRAM = CCASFLAGS_PROGRAM = -CFLAGS_LIBRARY = $(CFLAGS_PROGRAM) -CPPFLAGS_LIBRARY = $(CPPFLAGS_PROGRAM) -CCASFLAGS_LIBRARY = $(CCASFLAGS_PROGRAM) +CFLAGS_LIBRARY = +CPPFLAGS_LIBRARY = +CCASFLAGS_LIBRARY = # Other variables @@ -80,7 +105,7 @@ platformdir = $(pkglibrootdir)/$(target_cpu)-$(platform) CFLAGS_GCRY = -Wno-error -Wno-missing-field-initializers CPPFLAGS_GCRY = -I$(top_srcdir)/grub-core/lib/libgcrypt_wrap -CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused +CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/gnulib -I$(top_srcdir)/grub-core/gnulib CFLAGS_POSIX = -fno-builtin @@ -112,7 +137,7 @@ KERNEL_HEADER_FILES = man_MANS = noinst_DATA = -pkglib_DATA = +pkgdata_DATA = bin_SCRIPTS = sbin_SCRIPTS = bin_PROGRAMS = @@ -122,7 +147,6 @@ check_SCRIPTS = grubconf_DATA = check_PROGRAMS = noinst_SCRIPTS = -pkglib_SCRIPTS = noinst_PROGRAMS = grubconf_SCRIPTS = noinst_LIBRARIES = diff --git a/conf/i386-pc-cygwin-img-ld.sc b/conf/i386-pc-cygwin-img-ld.sc index a41cac75e..3b579d344 100644 --- a/conf/i386-pc-cygwin-img-ld.sc +++ b/conf/i386-pc-cygwin-img-ld.sc @@ -13,15 +13,9 @@ SECTIONS __data_start__ = . ; *(.data) __data_end__ = . ; - } - .rdata : - { __rdata_start__ = . ; *(.rdata) __rdata_end__ = . ; - } - .pdata : - { *(.pdata) edata = . ; } diff --git a/conf/mips-qemu-mips.rmk b/conf/mips-qemu-mips.rmk deleted file mode 100644 index be2b9f555..000000000 --- a/conf/mips-qemu-mips.rmk +++ /dev/null @@ -1,28 +0,0 @@ -# -*- makefile -*- -LINK_BASE = 0x80010000 -target_machine=qemu-mips -COMMON_CFLAGS += -march=mips3 -COMMON_ASFLAGS += -march=mips3 -include $(srcdir)/conf/mips.mk - -pkglib_PROGRAMS = kernel.img -kernel_img_SOURCES = kern/$(target_cpu)/startup.S \ - kern/main.c kern/device.c kern/$(target_cpu)/init.c \ - kern/$(target_cpu)/$(target_machine)/init.c \ - kern/disk.c kern/dl.c kern/err.c kern/file.c kern/fs.c \ - kern/misc.c kern/mm.c kern/term.c \ - kern/rescue_parser.c kern/rescue_reader.c \ - kern/list.c kern/command.c kern/corecmd.c \ - kern/parser.c kern/partition.c kern/env.c kern/$(target_cpu)/dl.c \ - kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c kern/time.c \ - symlist.c kern/$(target_cpu)/cache.S -kernel_img_CFLAGS = $(COMMON_CFLAGS) -kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,$(LINK_BASE),-Bstatic -kernel_img_FORMAT = binary - -# For serial.mod. -pkglib_MODULES += serial.mod -serial_mod_SOURCES = term/serial.c -serial_mod_CFLAGS = $(COMMON_CFLAGS) -serial_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/config.h.in b/config.h.in index 6d7d95dec..d6a1db31a 100644 --- a/config.h.in +++ b/config.h.in @@ -1,3 +1,10 @@ +#undef _LARGEFILE_SOURCE +#undef _FILE_OFFSET_BITS +#define _LARGEFILE_SOURCE +#define _FILE_OFFSET_BITS 64 +#if defined(__PPC__) && !defined(__powerpc__) +#define __powerpc__ 1 +#endif #if defined (GRUB_UTIL) || !defined (GRUB_MACHINE) #include #define NESTED_FUNC_ATTR @@ -32,6 +39,10 @@ #define NEED_ENABLE_EXECUTE_STACK @NEED_ENABLE_EXECUTE_STACK@ /* Define to 1 if GCC generates calls to __register_frame_info(). */ #define NEED_REGISTER_FRAME_INFO @NEED_REGISTER_FRAME_INFO@ +/* Define to 1 to enable disk cache statistics. */ +#define DISK_CACHE_STATS @DISK_CACHE_STATS@ + +#define RE_ENABLE_I18N 1 #if defined(__i386__) #define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (1))) diff --git a/configure.ac b/configure.ac index 66d4a6877..3c43759d3 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ dnl type, so there is no conflict. Variables with the prefix "TARGET_" dnl (such as TARGET_CC, TARGET_CFLAGS, etc.) are used for the target dnl type. -AC_INIT([GRUB],[1.99~beta0],[bug-grub@gnu.org]) +AC_INIT([GRUB],[1.99],[bug-grub@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) @@ -72,7 +72,7 @@ case "$target_cpu" in amd64) target_cpu=x86_64 ;; sparc) target_cpu=sparc64 ;; mipsel|mips64el) - target_cpu=mips; + target_cpu=mipsel; machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPSEL=1"; ;; mips|mips64) @@ -96,22 +96,21 @@ if test "x$with_platform" = x; then powerpc-*) platform=ieee1275 ;; powerpc64-*) platform=ieee1275 ;; sparc64-*) platform=ieee1275 ;; - mips-*) platform=yeeloong ;; + mipsel-*) platform=loongson ;; + mips-*) platform=arc ;; + ia64-*) platform=efi ;; *) AC_MSG_ERROR([unsupported CPU: "$target_cpu"]) ;; esac else platform="$with_platform" fi -# Adjust CPU unless target was explicitly specified. -if test -z "$target_alias"; then - case "$target_cpu"-"$platform" in - x86_64-efi) ;; - x86_64-emu) ;; - x86_64-*) target_cpu=i386 ;; - powerpc64-ieee1275) target_cpu=powerpc ;; - esac -fi +case "$target_cpu"-"$platform" in + x86_64-efi) ;; + x86_64-emu) ;; + x86_64-*) target_cpu=i386 ;; + powerpc64-ieee1275) target_cpu=powerpc ;; +esac # Check if the platform is supported, make final adjustments. case "$target_cpu"-"$platform" in @@ -125,8 +124,15 @@ case "$target_cpu"-"$platform" in i386-qemu) ;; powerpc-ieee1275) ;; sparc64-ieee1275) ;; - mips-qemu-mips) ;; - mips-yeeloong) ;; + ia64-efi) ;; + mips-qemu_mips) ;; + mips-qemu-mips) platform=qemu_mips;; + mips-arc) ;; + mipsel-qemu_mips) ;; + mipsel-qemu-mips) platform=qemu_mips;; + mipsel-yeeloong) platform=loongson ;; + mipsel-fuloong) platform=loongson ;; + mipsel-loongson) ;; *-emu) ;; *) AC_MSG_ERROR([platform "$platform" is not supported for target CPU "$target_cpu"]) ;; esac @@ -148,6 +154,7 @@ case "$host_os" in linux*) host_kernel=linux ;; freebsd* | kfreebsd*-gnu) host_kernel=kfreebsd ;; netbsd*) host_kernel=netbsd ;; + solaris*) host_kernel=illumos ;; cygwin) host_kernel=windows ;; esac @@ -159,14 +166,19 @@ case "$platform" in qemu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_QEMU=1" ;; pc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;; emu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;; - yeeloong) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_YEELOONG=1 -DGRUB_MACHINE_MIPS_BONITO=1" ;; - qemu-mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1 -DGRUB_MACHINE_MIPS_BONITO=1" ;; + loongson) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_LOONGSON=1 -DGRUB_MACHINE_MIPS_BONITO=1" ;; + qemu_mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1 -DGRUB_MACHINE_MIPS_BONITO=1" ;; + arc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;; esac case "$target_cpu" in - mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS=1" ;; + mips |mipsel) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS=1" ;; sparc64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_SPARC64=1" ;; esac -machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE=`echo ${target_cpu}_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`" +if test x${target_cpu} = xmipsel ; then + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE=`echo mips_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`" +else + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE=`echo ${target_cpu}_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,` -DGRUB_TARGET_CPU_`echo ${target_cpu} | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`=1" +fi HOST_CPPFLAGS="$HOST_CPPFLAGS $machine_CPPFLAGS" TARGET_CPPFLAGS="$TARGET_CPPFLAGS $machine_CPPFLAGS" @@ -222,8 +234,8 @@ for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do done done -if test "x$FONT_SOURCE" = x && ( test "x$platform" = xqemu || test "x$platform" = xyeeloong ); then - AC_MSG_ERROR([qemu and yeeloong ports need unifont]) +if test "x$FONT_SOURCE" = x && ( test "x$platform" = xqemu || test "x$platform" = xloongson || test "x$platform" = xqemu_mips); then + AC_MSG_ERROR([qemu and loongson ports need unifont]) fi AC_SUBST([FONT_SOURCE]) @@ -249,7 +261,7 @@ else fi # These are not a "must". -AC_PATH_PROG(MAKEINFO, makeinfo) +AC_PATH_PROGS(MAKEINFO, makeinfo true) # # Checks for host programs. @@ -286,7 +298,7 @@ fi # Check for functions and headers. AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf getextmntent) -AC_CHECK_HEADERS(libzfs.h libnvpair.h sys/param.h sys/mount.h sys/mnttab.h sys/mkdev.h) +AC_CHECK_HEADERS(libzfs.h libnvpair.h sys/param.h sys/mount.h sys/mnttab.h sys/mkdev.h limits.h) AC_CHECK_MEMBERS([struct statfs.f_fstypename],,,[$ac_includes_default #include @@ -401,6 +413,23 @@ if test "x$grub_cv_cc_fno_dwarf2_cfi_asm" = xyes; then TARGET_CFLAGS="$TARGET_CFLAGS -fno-dwarf2-cfi-asm" fi +# By default, GCC 4.6 generates .eh_frame sections containing unwind +# information in some cases where it previously did not. GRUB doesn't need +# these and they just use up vital space. Restore the old compiler +# behaviour. +AC_CACHE_CHECK([whether -fno-asynchronous-unwind-tables works], [grub_cv_cc_fno_asynchronous_unwind_tables], [ + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-dwarf2-cfi-asm" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_fno_asynchronous_unwind_tables=yes], + [grub_cv_cc_fno_asynchronous_unwind_tables=no]) + CFLAGS="$SAVE_CFLAGS" +]) + +if test "x$grub_cv_cc_fno_asynchronous_unwind_tables" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-asynchronous-unwind-tables" +fi + grub_apple_target_cc if test x$grub_cv_apple_target_cc = xyes ; then TARGET_CPPFLAGS="$TARGET_CPPFLAGS -DAPPLE_CC=1" @@ -440,7 +469,7 @@ fi # For platforms where ELF is not the default link format. AC_MSG_CHECKING([for command to convert module to ELF format]) case "${host_os}" in - cygwin) TARGET_OBJ2ELF='$(grub_utildir)/grub-pe2elf'; + cygwin) TARGET_OBJ2ELF='$(top_builddir)/grub-pe2elf'; # FIXME: put proper test here NEED_REGISTER_FRAME_INFO=1 ;; @@ -448,10 +477,45 @@ case "${host_os}" in esac AC_MSG_RESULT([$TARGET_OBJ2ELF]) + +AC_ARG_ENABLE([efiemu], + [AS_HELP_STRING([--enable-efiemu], + [build and install the efiemu runtimes (default=guessed)])]) +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" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_efiemu=yes], + [grub_cv_cc_efiemu=no]) + ]) + if test x$grub_cv_cc_efiemu = xno; then + efiemu_excuse="cannot compile with -m64 -mcmodel=large -mno-red-zone -nostdlib" + fi +fi +if test x"$enable_efiemu" = xyes && test x"$efiemu_excuse" != x ; then + AC_MSG_ERROR([efiemu runtime was explicitly requested but can't be compiled]) +fi +if test x"$efiemu_excuse" = x ; then +enable_efiemu=yes +else +enable_efiemu=no +fi +AC_SUBST([enable_efiemu]) + if test "x$target_m32" = x1; then # Force 32-bit mode. TARGET_CFLAGS="$TARGET_CFLAGS -m32" TARGET_CCASFLAGS="$TARGET_CCASFLAGS -m32" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -m32" TARGET_LDFLAGS="$TARGET_LDFLAGS -m32" TARGET_MODULE_FORMAT="elf32" fi @@ -460,6 +524,7 @@ if test "x$target_m64" = x1; then # Force 64-bit mode. TARGET_CFLAGS="$TARGET_CFLAGS -m64" TARGET_CCASFLAGS="$TARGET_CCASFLAGS -m64" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -m64" TARGET_LDFLAGS="$TARGET_LDFLAGS -m64" TARGET_MODULE_FORMAT="elf64" fi @@ -562,8 +627,11 @@ else CFLAGS="$TARGET_CFLAGS -nostdlib -Wl,--defsym,___main=0x8100 -Wno-error" fi CPPFLAGS="$TARGET_CPPFLAGS" -LDFLAGS="$TARGET_LDFLAGS" +if test x$target_cpu = xi386 || test x$target_cpu = xx86_64 ; then +LIBS= +else LIBS=-lgcc +fi grub_ASM_USCORE if test x$grub_cv_asm_uscore = xyes; then @@ -573,7 +641,7 @@ CFLAGS="$CFLAGS -Wl,--defsym,abort=main" fi # Check for libgcc symbols -AC_CHECK_FUNCS(__bswapsi2 __bswapdi2 __ashldi3 __ashrdi3 __lshrdi3 __trampoline_setup __ucmpdi2 _restgpr_14_x) +AC_CHECK_FUNCS(__bswapsi2 __bswapdi2 __ashldi3 __ashrdi3 __lshrdi3 __trampoline_setup __ucmpdi2 _restgpr_14_x __ia64_trampoline __udivsi3 __umoddi3 __udivdi3 __divsi3 __modsi3 __umodsi3 __moddi3 __divdi3 __ctzdi2 __ctzsi2) if test "x$TARGET_APPLE_CC" = x1 ; then CFLAGS="$TARGET_CFLAGS -nostdlib" @@ -602,39 +670,6 @@ if test "x$target_cpu" = xi386; then grub_I386_ASM_ADDR32 fi -AC_ARG_ENABLE([efiemu], - [AS_HELP_STRING([--enable-efiemu], - [build and install the efiemu runtimes (default=guessed)])]) -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" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [grub_cv_cc_efiemu=yes], - [grub_cv_cc_efiemu=no]) - ]) - if test x$grub_cv_cc_efiemu = xno; then - efiemu_excuse="cannot compile with -m64 -mcmodel=large -mno-red-zone -nostdlib" - fi -fi -if test x"$enable_efiemu" = xyes && test x"$efiemu_excuse" != x ; then - AC_MSG_ERROR([efiemu runtime was explicitly requested but can't be compiled]) -fi -if test x"$efiemu_excuse" = x ; then -enable_efiemu=yes -else -enable_efiemu=no -fi -AC_SUBST([enable_efiemu]) - if test "$platform" != emu; then AC_CACHE_CHECK([whether -nostdinc -isystem works], [grub_cv_cc_isystem], [ SAVED_CPPFLAGS="$CPPFLAGS" @@ -651,6 +686,23 @@ if test x"$grub_cv_cc_isystem" = xyes ; then fi fi +AC_CACHE_CHECK([whether -Wno-trampolines work], [grub_cv_cc_wnotrampolines], [ + SAVED_CFLAGS="$CFLAGS" + # Test for -Wtrampolines rather than -Wno-trampolines to reduce confusion + # in the event of later failures (since -Wno-* is always accepted, but + # produces a diagnostic if something else is wrong). + CFLAGS="$TARGET_CFLAGS -Wtrampolines" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +int va_arg_func (int fixed, va_list args);]], [[]])], + [grub_cv_cc_wnotrampolines=yes], + [grub_cv_cc_wnotrampolines=no]) + CFLAGS="$SAVED_CFLAGS" +]) + +if test x"$grub_cv_cc_wnotrampolines" = xyes ; then + TARGET_CFLAGS="$TARGET_CFLAGS -Wno-trampolines" +fi + # Restore the flags. CC="$tmp_CC" CFLAGS="$tmp_CFLAGS" @@ -669,6 +721,17 @@ AC_ARG_ENABLE([mm-debug], [AC_DEFINE([MM_DEBUG], [1], [Define to 1 if you enable memory manager debugging.])]) +AC_ARG_ENABLE([cache-stats], + AS_HELP_STRING([--enable-cache-stats], + [enable disk cache statistics collection])) + +if test x$enable_cache_stats = xyes; then + DISK_CACHE_STATS=1 +else + DISK_CACHE_STATS=0 +fi +AC_SUBST([DISK_CACHE_STATS]) + AC_ARG_ENABLE([grub-emu-usb], [AS_HELP_STRING([--enable-grub-emu-usb], [build and install the `grub-emu' debugging utility with USB support (default=guessed)])]) @@ -818,10 +881,44 @@ enable_grub_mkfont=yes else enable_grub_mkfont=no fi +if test x"$enable_grub_mkfont" = xno && test "x$platform" = xloongson; then + AC_MSG_ERROR([loongson port needs grub-mkfont]) +fi AC_SUBST([enable_grub_mkfont]) AC_SUBST([freetype_cflags]) AC_SUBST([freetype_libs]) +AC_ARG_ENABLE([grub-mount], + [AS_HELP_STRING([--enable-grub-mount], + [build and install the `grub-mount' utility (default=guessed)])]) +if test x"$enable_grub_mount" = xno ; then + grub_mount_excuse="explicitly disabled" +fi + +if test x"$grub_mount_excuse" = x ; then + AC_CHECK_LIB([fuse], [fuse_main_real], [], + [grub_mount_excuse="need FUSE library"]) +fi + +if test x"$grub_mount_excuse" = x ; then + # Check for fuse headers. + SAVED_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26" + AC_CHECK_HEADERS([fuse/fuse.h], [], + [grub_mount_excuse=["need FUSE headers"]]) + CPPFLAGS="$SAVED_CPPFLAGS" +fi + +if test x"$enable_grub_mount" = xyes && test x"$grub_mount_excuse" != x ; then + AC_MSG_ERROR([grub-mount was explicitly requested but can't be compiled]) +fi +if test x"$grub_mount_excuse" = x ; then +enable_grub_mount=yes +else +enable_grub_mount=no +fi +AC_SUBST([enable_grub_mount]) + AC_ARG_ENABLE([device-mapper], [AS_HELP_STRING([--enable-device-mapper], [enable Linux device-mapper support (default=guessed)])]) @@ -829,6 +926,12 @@ if test x"$enable_device_mapper" = xno ; then device_mapper_excuse="explicitly disabled" fi +if test x"$device_mapper_excuse" = x ; then + # Check for device-mapper header. + AC_CHECK_HEADER([libdevmapper.h], [], + [device_mapper_excuse="need libdevmapper header"]) +fi + if test x"$device_mapper_excuse" = x ; then # Check for device-mapper library. AC_CHECK_LIB([devmapper], [dm_task_create], [], @@ -850,6 +953,15 @@ fi AC_SUBST([LIBDEVMAPPER]) +LIBGEOM= +if test x$host_kernel = xkfreebsd; then + AC_CHECK_LIB([geom], [geom_gettree], [], + [AC_MSG_ERROR([Your platform requires libgeom])]) + LIBGEOM="-lgeom" +fi + +AC_SUBST([LIBGEOM]) + AC_CHECK_LIB([lzma], [lzma_code], [LIBLZMA="-llzma" AC_DEFINE([HAVE_LIBLZMA], [1], @@ -896,49 +1008,59 @@ AC_SUBST(NEED_REGISTER_FRAME_INFO) AM_CONDITIONAL([COND_emu], [test x$platform = xemu]) AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc]) AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi]) +AM_CONDITIONAL([COND_ia64_efi], [test x$target_cpu = xia64 -a x$platform = xefi]) AM_CONDITIONAL([COND_i386_qemu], [test x$target_cpu = xi386 -a x$platform = xqemu]) AM_CONDITIONAL([COND_i386_ieee1275], [test x$target_cpu = xi386 -a x$platform = xieee1275]) AM_CONDITIONAL([COND_i386_coreboot], [test x$target_cpu = xi386 -a x$platform = xcoreboot]) AM_CONDITIONAL([COND_i386_multiboot], [test x$target_cpu = xi386 -a x$platform = xmultiboot]) AM_CONDITIONAL([COND_x86_64_efi], [test x$target_cpu = xx86_64 -a x$platform = xefi]) -AM_CONDITIONAL([COND_mips_yeeloong], [test x$target_cpu = xmips -a x$platform = xyeeloong]) -AM_CONDITIONAL([COND_mips_qemu_mips], [test x$target_cpu = xmips -a x$platform = xqemu_mips]) +AM_CONDITIONAL([COND_mips_loongson], [test x$target_cpu = xmipsel -a x$platform = xloongson]) +AM_CONDITIONAL([COND_mips_qemu_mips], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")" -a x$platform = xqemu_mips]) +AM_CONDITIONAL([COND_mips_arc], [test x$target_cpu = xmips -a x$platform = xarc]) AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275]) AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275]) -AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips]) +AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel]) AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd]) AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux]) AM_CONDITIONAL([COND_HOST_NETBSD], [test x$host_kernel = xnetbsd]) AM_CONDITIONAL([COND_HOST_WINDOWS], [test x$host_kernel = xwindows]) AM_CONDITIONAL([COND_HOST_KFREEBSD], [test x$host_kernel = xkfreebsd]) +AM_CONDITIONAL([COND_HOST_ILLUMOS], [test x$host_kernel = xillumos]) AM_CONDITIONAL([COND_MAN_PAGES], [test x$cross_compiling = xno -a x$HELP2MAN != x]) AM_CONDITIONAL([COND_GRUB_EMU_USB], [test x$enable_grub_emu_usb = xyes]) AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes]) AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes]) AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes]) +AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes]) AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x]) AM_CONDITIONAL([COND_GRUB_PE2ELF], [test x$TARGET_OBJ2ELF != x]) AM_CONDITIONAL([COND_APPLE_CC], [test x$TARGET_APPLE_CC = x1]) AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) +AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) AM_CONDITIONAL([COND_HAVE_ASM_USCORE], [test x$HAVE_ASM_USCORE = x1]) +AM_CONDITIONAL([COND_CYGWIN], [test x$host_os = xcygwin]) # Output files. +cpudir="${target_cpu}" +if test x${cpudir} = xmipsel; then + cpudir=mips; +fi grub_CHECK_LINK_DIR if test x"$link_dir" = xyes ; then - AC_CONFIG_LINKS([include/grub/cpu:include/grub/$target_cpu]) + AC_CONFIG_LINKS([include/grub/cpu:include/grub/$cpudir]) if test "$platform" != emu ; then - AC_CONFIG_LINKS([include/grub/machine:include/grub/$target_cpu/$platform]) + AC_CONFIG_LINKS([include/grub/machine:include/grub/$cpudir/$platform]) fi else mkdir -p include/grub 2>/dev/null rm -rf include/grub/cpu - cp -rp $srcdir/include/grub/$target_cpu include/grub/cpu 2>/dev/null + cp -rp $srcdir/include/grub/$cpudir include/grub/cpu 2>/dev/null if test "$platform" != emu ; then rm -rf include/grub/machine - cp -rp $srcdir/include/grub/$target_cpu/$platform include/grub/machine 2>/dev/null + cp -rp $srcdir/include/grub/$cpudir/$platform include/grub/machine 2>/dev/null fi fi @@ -983,6 +1105,11 @@ echo With memory debugging: Yes else echo With memory debugging: No fi +if [ x"$enable_cache_stats" = xyes ]; then +echo With disk cache statistics: Yes +else +echo With disk cache statistics: No +fi if [ x"$efiemu_excuse" = x ]; then echo efiemu runtime: Yes else @@ -993,5 +1120,10 @@ echo grub-mkfont: Yes else echo grub-mkfont: No "($grub_mkfont_excuse)" fi +if [ x"$grub_mount_excuse" = x ]; then +echo grub-mount: Yes +else +echo grub-mount: No "($grub_mount_excuse)" +fi echo "*******************************************************" ] diff --git a/docs/Makefile.am b/docs/Makefile.am index 8d9fb8445..6e1500601 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS = subdir-objects # AM_MAKEINFOFLAGS = --no-split --no-validate -info_TEXINFOS = grub.texi +info_TEXINFOS = grub.texi grub-dev.texi grub_TEXINFOS = fdl.texi diff --git a/docs/font_char_metrics.png b/docs/font_char_metrics.png new file mode 100644 index 000000000..8d10d1f64 Binary files /dev/null and b/docs/font_char_metrics.png differ diff --git a/docs/font_char_metrics.txt b/docs/font_char_metrics.txt new file mode 100644 index 000000000..92f1371fd --- /dev/null +++ b/docs/font_char_metrics.txt @@ -0,0 +1 @@ +Please fill this in. diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi new file mode 100644 index 000000000..51b47872d --- /dev/null +++ b/docs/grub-dev.texi @@ -0,0 +1,1843 @@ +\input texinfo +@c -*-texinfo-*- +@c %**start of header +@setfilename grub-dev.info +@include version-dev.texi +@settitle GNU GRUB Developers Manual @value{VERSION} +@c Unify all our little indices for now. +@syncodeindex fn cp +@syncodeindex vr cp +@syncodeindex ky cp +@syncodeindex pg cp +@syncodeindex tp cp +@c %**end of header + +@footnotestyle separate +@paragraphindent 3 +@finalout + +@copying +This developer manual is for GNU GRUB (version @value{VERSION}, +@value{UPDATED}). + +Copyright @copyright{} 1999,2000,2001,2002,2004,2005,2006,2008,2009,2010,2011 Free Software Foundation, Inc. + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 or +any later version published by the Free Software Foundation; with no +Invariant Sections. +@end quotation +@end copying + +@dircategory Kernel +@direntry +* grub-dev: (grub-dev). The GRand Unified Bootloader Dev +@end direntry + +@setchapternewpage odd + +@titlepage +@sp 10 +@title the GNU GRUB developer manual +@subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}. +@author Yoshinori K. Okuji +@author Colin D Bennett +@author Vesa Jääskeläinen +@author Colin Watson +@author Robert Millan +@author Carles Pina +@c The following two commands start the copyright page. +@page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@c Output the table of contents at the beginning. +@contents + +@finalout +@headings double + +@ifnottex +@node Top +@top GNU GRUB developer manual + +This is the developer documentation of GNU GRUB, the GRand Unified Bootloader, +a flexible and powerful boot loader program for a wide range of +architectures. + +This edition documents version @value{VERSION}. + +@insertcopying +@end ifnottex + +@menu +* Getting the source code:: +* Finding your way around:: +* Coding style:: +* Contributing Changes:: +* Porting:: +* Error Handling:: +* CIA:: +* BIOS port memory map:: +* Video Subsystem:: +* PFF2 Font File Format:: +* Graphical Menu Software Design:: +* Copying This Manual:: Copying This Manual +* Index:: +@end menu + + +@node Getting the source code +@chapter Getting the source code + +GRUB is maintained using the @uref{http://bazaar-vcs.org/, Bazaar revision +control system}. To fetch the primary development branch: + +@example +bzr get http://bzr.savannah.gnu.org/r/grub/trunk/grub +@end example + +The GRUB developers maintain several other branches with work in progress. +Of these, the most interesting is the experimental branch, which is a +staging area for new code which we expect to eventually merge into trunk but +which is not yet ready: + +@example +bzr get http://bzr.savannah.gnu.org/r/grub/branches/experimental +@end example + +Once you have used @kbd{bzr get} to fetch an initial copy of a branch, you +can use @kbd{bzr pull} to keep it up to date. If you have modified your +local version, you may need to resolve conflicts when pulling. + +@node Coding style +@chapter Coding style +@c By YoshinoriOkuji, VesaJääskeläinen and ColinBennett + +Basically we follow the @uref{http://www.gnu.org/prep/standards_toc.html, GNU Coding Standards}. We define additional conventions for GRUB here. + +@menu +* Naming Conventions:: +* Functions:: +* Variables:: +* Types:: +* Macros:: +* Comments:: +* Multi-Line Comments:: +@end menu + +@node Naming Conventions +@section Naming Conventions + +All global symbols (i.e. functions, variables, types, and macros) must have the prefix grub_ or GRUB_. The all capital form is used only by macros. + +@node Functions +@section Functions + +If a function is global, its name must be prefixed with grub_ and must consist of only small letters. If the function belongs to a specific function module, the name must also be prefixed with the module name. For example, if a function is for file systems, its name is prefixed with grub_fs_. If a function is for FAT file system but not for all file systems, its name is prefixed with grub_fs_fat_. The hierarchy is noted this way. + +After a prefix, a function name must start with a verb (such as get or is). It must not be a noun. Some kind of abbreviation is permitted, as long as it wouldn't make code less readable (e.g. init). + +If a function is local, its name may not start with any prefix. It must start with a verb. + +@node Variables +@section Variables + +The rule is mostly the same as functions, as noted above. If a variable is global, its name must be prefixed with grub_ and must consist of only small letters. If the variable belongs to a specific function module, the name must also be prefixed with the module name. For example, if a function is for dynamic loading, its name is prefixed with grub_dl_. If a variable is for ELF but not for all dynamic loading systems, its name is prefixed with grub_dl_elf_. + +After a prefix, a variable name must start with a noun or an adjective (such as name or long) and it should end with a noun. Some kind of abbreviation is permitted, as long as it wouldn't make code less readable (e.g. i18n). + +If a variable is global in the scope of a single file (i.e. it is declared with static), its name may not start with any prefix. It must start with a noun or an adjective. + +If a variable is local, you may choose any shorter name, as long as it wouldn't make code less readable (e.g. i). + +@node Types +@section Types + +The name of a type must be prefixed with grub_ and must consist of only small letters. If the type belongs to a specific function module, the name must also be prefixed with the module name. For example, if a type is for OS loaders, its name is prefixed with grub_loader_. If a type is for Multiboot but not for all OS loaders, its name is prefixed with grub_loader_linux_. + +The name must be suffixed with _t, to emphasize the fact that it is a type but not a variable or a function. + +@node Macros +@section Macros + +If a macro is global, its name must be prefixed with GRUB_ and must consist of only large letters. Other rules are the same as functions or variables, depending on whether a macro is used like a function or a variable. + +@node Comments +@section Comments + +All comments shall be C-style comments, of the form @samp{/* @dots{} */}. + +Comments shall be placed only on a line by themselves. They shall not be placed together with code, variable declarations, or other non-comment entities. A comment should be placed immediately preceding the entity it describes. + +Acceptable: +@example +/* The page # that is the front buffer. */ +int displayed_page; +/* The page # that is the back buffer. */ +int render_page; +@end example + +Unacceptable: +@example +int displayed_page; /* The page # that is the front buffer. */ +int render_page; /* The page # that is the back buffer. */ +@end example + +@node Multi-Line Comments +@section Multi-Line Comments + +Comments spanning multiple lines shall be formatted with all lines after the first aligned with the first line. + +Asterisk characters should not be repeated a the start of each subsequent line. + +Acceptable: +@example +/* This is a comment + which spans multiple lines. + It is long. */ +@end example + +Unacceptable: +@example +/* + * This is a comment + * which spans multiple lines. + * It is long. */ +@end example + +The opening @samp{/*} and closing @samp{*/} should be placed together on a line with text. + +@node Finding your way around +@chapter Finding your way around + +Here is a brief map of the GRUB code base. + +GRUB uses Autoconf and Automake, with most of the Automake input generated +by AutoGen. The top-level build rules are in @file{configure.ac}, +@file{grub-core/Makefile.core.def}, and @file{Makefile.util.def}. Each +block in a @file{*.def} file represents a build target, and specifies the +source files used to build it on various platforms. The @file{*.def} files +are processed into AutoGen input by @file{gentpl.py} (which you only need to +look at if you are extending the build system). If you are adding a new +module which follows an existing pattern, such as a new command or a new +filesystem implementation, it is usually easiest to grep +@file{grub-core/Makefile.core.def} and @file{Makefile.util.def} for an +existing example of that pattern to find out where it should be added. + +In general, code that may be run at boot time is in a subdirectory of +@file{grub-core}, while code that is only run from within a full operating +system is in a subdirectory of the top level. + +Low-level boot code, such as the MBR implementation on PC BIOS systems, is +in the @file{grub-core/boot/} directory. + +The GRUB kernel is in @file{grub-core/kern/}. This contains core facilities +such as the device, disk, and file frameworks, environment variable +handling, list processing, and so on. The kernel should contain enough to +get up to a rescue prompt. Header files for kernel facilities, among +others, are in @file{include/}. + +Terminal implementations are in @file{grub-core/term/}. + +Disk access code is spread across @file{grub-core/disk/} (for accessing the +disk devices themselves), @file{grub-core/partmap/} (for interpreting +partition table data), and @file{grub-core/fs/} (for accessing filesystems). +Note that, with the odd specialised exception, GRUB only contains code to +@emph{read} from filesystems and tries to avoid containing any code to +@emph{write} to filesystems; this lets us confidently assure users that GRUB +cannot be responsible for filesystem corruption. + +PCI and USB bus handling is in @file{grub-core/bus/}. + +Video handling code is in @file{grub-core/video/}. The graphical menu +system uses this heavily, but is in a separate directory, +@file{grub-core/gfxmenu/}. + +Most commands are implemented by files in @file{grub-core/commands/}, with +the following exceptions: + +@itemize +@item +A few core commands live in @file{grub-core/kern/corecmd.c}. + +@item +Commands related to normal mode live under @file{grub-core/normal/}. + +@item +Commands that load and boot kernels live under @file{grub-core/loader/}. + +@item +The @samp{loopback} command is really a disk device, and so lives in +@file{grub-core/disk/loopback.c}. + +@item +The @samp{gettext} command lives under @file{grub-core/gettext/}. + +@item +The @samp{loadfont} and @samp{lsfonts} commands live under +@file{grub-core/font/}. + +@item +The @samp{serial}, @samp{terminfo}, and @samp{background_image} commands +live under @file{grub-core/term/}. + +@item +The @samp{efiemu_*} commands live under @file{grub-core/efiemu/}. +@end itemize + +There are a few other special-purpose exceptions; grep for them if they +matter to you. + +Utility programs meant to be run from a full operating system are in +@file{util/}. + +@node Contributing Changes +@chapter Contributing changes +@c By YoshinoriOkuji, VesaJääskeläinen, ColinWatson + +Contributing changes to GRUB 2 is welcomed activity. However we have a +bit of control what kind of changes will be accepted to GRUB 2. +Therefore it is important to discuss your changes on grub-devel mailing list +(see MailingLists). On this page there are some basic details on the +development process and activities. + +First of all you should come up with the idea yourself what you want to +contribute. If you do not have that beforehand you are advised to study this +manual and try GRUB 2 out to see what you think is missing from there. + +Here are additional pointers: +@itemize +@item @url{https://savannah.gnu.org/task/?group=grub GRUB's Task Tracker} +@item @url{https://savannah.gnu.org/bugs/?group=grub GRUB's Bug Tracker} +@end itemize + +If you intended to make changes to GRUB Legacy (<=0.97) those are not accepted +anymore. + +@menu +* Getting started:: +* Typical Developer Experience:: +* When you are approved for write access to project's files:: +@end menu + +@node Getting started +@section Getting started + +@itemize +@item Always use latest GRUB 2 source code. So get that first. + +For developers it is recommended always to use the newest development version of GRUB 2. If development takes a long period of time, please remember to keep in sync with newest developments regularly so it is much easier to integrate your change in the future. GRUB 2 is being developed in a Bazaar (bzr) repository. + +Please check Savannah's GRUB project page for details how to get newest bzr: +@uref{http://savannah.gnu.org/bzr/?group=grub, GRUB 2 bzr Repository} + +@item Compile it and try it out. + +It is always good idea to first see that things work somehow and after that +to start to implement new features or develop fixes to bugs. + +@item Study the code. + +There are sometimes odd ways to do things in GRUB 2 code base. +This is mainly related to limited environment where GRUB 2 is being executed. +You usually do not need to understand it all so it is better to only try to +look at places that relates to your work. Please do not hesitate to ask for +help if there is something that you do not understand. + +@item Develop a new feature. + +Now that you know what to do and how it should work in GRUB 2 code base, please +be free to develop it. If you have not so far announced your idea on grub-devel +mailing list, please do it now. This is to make sure you are not wasting your +time working on the solution that will not be integrated to GRUB 2 code base. + +You might want to study our coding style before starting development so you +do not need to change much of the code when your patch is being reviewed. +(see @ref{Coding style}) + +For every accepted patch there has to exist a ChangeLog entry. Our ChangeLog +consist of changes within source code and are not describing about what the +change logically does. Please see examples from previous entries. + +Also remember that GRUB 2 is licensed under GPLv3 license and that usually +means that you are not allowed to copy pieces of code from other projects. +Even if the source project's license would be compatible with GPLv3, please +discuss it beforehand on grub-devel mailing list. + +@item Test your change. + +Test that your change works properly. Try it out a couple of times, preferably on different systems, and try to find problems with it. + +@item Publish your change. + +When you are happy with your change, first make sure it is compilable with +latest development version of GRUB 2. After that please send a patch to +grub-devel for review. Please describe in your email why you made the change, +what it changes and so on. Please be prepared to receive even discouraging +comments about your patch. There is usually at least something that needs +to be improved in every patch. + +Please use unified diff to make your patch (good match of arguments for diff is @samp{-pruN}). + +@item Respond to received feedback. + +If you are asked to modify your patch, please do that and resubmit it for +review. If your change is large you are required to submit a copyright +agreement to FSF. Please keep in mind that if you are asked to submit +for copyright agreement, process can take some time and is mandatory +in order to get your changes integrated. + +If you are not on grub-devel to respond to questions, most likely your patch +will not be accepted. Also if problems arise from your changes later on, +it would be preferable that you also fix the problem. So stay around +for a while. + +@item Your patch is accepted. + +Good job! Your patch will now be integrated into GRUB 2 mainline, and if it didn't break anything it will be publicly available in the next release. + +Now you are welcome to do further improvements :) +@end itemize + +@node Typical Developer Experience +@section Typical Developer Experience + +The typical experience for a developer in this project is the following: + +@enumerate +@item You find yourself wanting to do something (e.g. fixing a bug). +@item You show some result in the mailing list or the IRC. +@item You are getting to be known to other developers. +@item You accumulate significant amount of contribution, so copyright assignment is processed. +@item You are free to check in your changes on your own, legally speaking. +@end enumerate + +At this point, it is rather annoying that you ought to ask somebody else every +change to be checked in. For efficiency, it is far better, if you can commit +it yourself. Therefore, our policy is to give you the write permission to our +official repository, once you have shown your skill and will, +and the FSF clerks have dealt with your copyright assignment. + +@node When you are approved for write access to project's files +@section When you are approved for write access to project's files + +As you might know, GRUB is hosted on +@url{https://savannah.gnu.org/projects/grub Savannah}, thus the membership +is managed by Savannah. This means that, if you want to be a member of this +project: + +@enumerate +@item You need to create your own account on Savannah. +@item You can submit ``Request for Inclusion'' from ``My Groups'' on Savannah. +@end enumerate + +Then, one of the admins can approve your request, and you will be a member. +If you don't want to use the Savannah interface to submit a request, you can +simply notify the admins by email or something else, alternatively. But you +still need to create an account beforehand. + +NOTE: we sometimes receive a ``Request for Inclusion'' from an unknown person. +In this case, the request would be just discarded, since it is too dangerous +to allow a stranger to be a member, which automatically gives him a commit +right to the repository, both for a legal reason and for a technical reason. + +If your intention is to just get started, please do not submit a inclusion +request. Instead, please subscribe to the mailing list, and communicate first +(e.g. sending a patch, asking a question, commenting on another message...). + +@node Porting +@chapter Porting + +GRUB2 is designed to be easily portable accross platforms. But because of the +nature of bootloader every new port must be done separately. Here is how I did +MIPS (loongson and ARC) and Xen ports. Note than this is more of suggestions, +not absolute truth. + +First of all grab any architecture specifications you can find in public +(please avoid NDA). + +First stage is ``Hello world''. I've done it outside of GRUB for simplicity. +Your task is to have a small program which is loadable as bootloader and +clearly shows its presence to you. If you have easily accessible console +you can just print a message. If you have a mapped framebuffer you know address +of, you can draw a square. If you have a debug facility, just hanging without +crashing might be enough. For the first stage you can choose to load the +bootloader across the network since format for network image is often easier +than for local boot and it skips the need of small intermediary stages and +nvram handling. Additionally you can often have a good idea of the needed +format by running ``file'' on any netbootable executable for given platform. + +This program should probably have 2 parts: an assembler and C one. Assembler one +handles BSS cleaning and other needed setup (on some platforms you may need +to switch modes or copy the executable to its definitive position). So your code +may look like (x86 assembly for illustration purposes) + +@example + .globl _start +_start: + movl $_bss_start, %edi + movl $_end, %ecx + subl %edi, %ecx + xorl %eax, %eax + cld + rep + stosb + call main +@end example + +@example + +static const char msg[] = "Hello, world"; + +void +putchar (int c) +@{ + ... +@} + +void +main (void) +@{ + const char *ptr = msg; + while (*ptr) + putchar (*ptr++); + while (1); +@} +@end example + +Sometimes you need a third file: assembly stubs for ABI-compatibility. + +Once this file is functional it's time to move it into GRUB2. The startup +assembly file goes to grub-core/kern/$cpu/$platform/startup.S. You should also +include grub/symbol.h and replace call to entry point with call to +EXT_C(grub_main). The C file goes to grub-core/kern/$cpu/$platform/init.c +and its entry point is renamed to void grub_machine_init (void). Keep final +infinite loop for now. Stubs file if any goes to +grub-core/kern/$cpu/$platform/callwrap.S. Sometimes either $cpu or $platform +is dropped if file is used on several cpus respectivelyplatforms. +Check those locations if they already have what you're looking for. + +Then modify in configure.ac the following parts: + +CPU names: + +@example +case "$target_cpu" in + i[[3456]]86) target_cpu=i386 ;; + amd64) target_cpu=x86_64 ;; + sparc) target_cpu=sparc64 ;; + s390x) target_cpu=s390 ;; + ... +esac +@end example + +Sometimes CPU have additional architecture names which don't influence booting. +You might want to have some canonical name to avoid having bunch of identical +platforms with different names. + +NOTE: it doesn't influence compile optimisations which depend solely on +chosen compiler and compile options. + +@example +if test "x$with_platform" = x; then + case "$target_cpu"-"$target_vendor" in + i386-apple) platform=efi ;; + i386-*) platform=pc ;; + x86_64-apple) platform=efi ;; + x86_64-*) platform=pc ;; + powerpc-*) platform=ieee1275 ;; + ... + esac +else + ... +fi +@end example + +This part deals with guessing the platform from CPU and vendor. Sometimes you +need to use 32-bit mode for booting even if OS runs in 64-bit one. If so add +your platform to: + +@example +case "$target_cpu"-"$platform" in + x86_64-efi) ;; + x86_64-emu) ;; + x86_64-*) target_cpu=i386 ;; + powerpc64-ieee1275) target_cpu=powerpc ;; +esac +@end example + +Add your platform to the list of supported ones: + +@example +case "$target_cpu"-"$platform" in + i386-efi) ;; + x86_64-efi) ;; + i386-pc) ;; + i386-multiboot) ;; + i386-coreboot) ;; + ... +esac +@end example + +If explicit -m32 or -m64 is needed add it to: + +@example +case "$target_cpu" in + i386 | powerpc) target_m32=1 ;; + x86_64 | sparc64) target_m64=1 ;; +esac +@end example + +Finally you need to add a conditional to the following block: + +@example +AM_CONDITIONAL([COND_mips_arc], [test x$target_cpu = xmips -a x$platform = xarc]) +AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275]) +AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275]) +@end example + +Next stop is gentpl.py. You need to add your platform to the list of supported +ones (sorry that this list is duplicated): + +@example +GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", + "i386_multiboot", "i386_ieee1275", "x86_64_efi", + "mips_loongson", "sparc64_ieee1275", + "powerpc_ieee1275", "mips_arc", "ia64_efi", + "mips_qemu_mips", "s390_mainframe" ] +@end example + +You may also want already to add new platform to one or several of available +groups. In particular we always have a group for each CPU even when only +one platform for given CPU is available. + +Then comes grub-core/Makefile.core.def. In the block ``kernel'' you'll need +to define ldflags for your platform ($cpu_$platform_ldflags). You also need to +declare startup asm file ($cpu_$platform_startup) as well as any other files +(e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). +At this stage you will also need to add dummy dl.c and cache.S with functions +grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and +void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They +won't be used for now. + +You will need to create directory include/$cpu/$platform and a file +include/$cpu/types.h. The later folowing this template: + +@example +#ifndef GRUB_TYPES_CPU_HEADER +#define GRUB_TYPES_CPU_HEADER 1 + +/* The size of void *. */ +#define GRUB_TARGET_SIZEOF_VOID_P 4 + +/* The size of long. */ +#define GRUB_TARGET_SIZEOF_LONG 4 + +/* mycpu is big-endian. */ +#define GRUB_TARGET_WORDS_BIGENDIAN 1 +/* Alternatively: mycpu is little-endian. */ +#undef GRUB_TARGET_WORDS_BIGENDIAN + +#endif /* ! GRUB_TYPES_CPU_HEADER */ +@end example + +You will also need to add a dummy file to datetime and setjmp modules to +avoid any of it having no files. It can be just completely empty at this stage. + +You'll need to make grub-mkimage.c (util/grub_mkimage.c) aware of the needed +format. For most commonly used formats like ELF, PE, aout or raw the support +is already present and you'll need to make it follow the existant code paths +for your platform adding adjustments if necessary. When done compile: + +@example +./autogen.sh +./configure --target=$cpu --with-platform=$platform TARGET_CC=.. OBJCOPY=... STRIP=... +make > /dev/null +@end example + +And create image + +@example +./grub-mkimage -d grub-core -O $format_id -o test.img +@end example + +And it's time to test your test.img. + +If it works next stage is to have heap, console and timer. + +To have the heap working you need to determine which regions are suitable for +heap usage, allocate them from firmware and map (if applicable). Then call +grub_mm_init_region (vois *start, grub_size_t s) for every of this region. +As a shortcut for early port you can allocate right after _end or have +a big static array for heap. If you do you'll probably need to come back to +this later. As for output console you should distinguish between an array of +text, terminfo or graphics-based console. Many of real-world examples don't +fit perfectly into any of these categories but one of the models is easier +to be used as base. In second and third case you should add your platform to +terminfokernel respectively videoinkernel group. A good example of array of +text is i386-pc (kern/i386/pc/init.c and term/i386/pc/console.c). +Of terminfo is ieee1275 (kern/ieee1275/init.c and term/ieee1275/console.c). +Of video is loongson (kern/mips/loongson/init.c). Note that terminfo has +to be inited in 2 stages: one before (to get at least rudimentary console +as early as possible) and another after the heap (to get full-featured console). +For the input there are string of keys, terminfo and direct hardware. For string +of keys look at i386-pc (same files), for termino ieee1275 (same files) and for +hardware loongson (kern/mips/loongson/init.c and term/at_keyboard.c). + +For the timer you'll need to call grub_install_get_time_ms (...) with as sole +argument a function returning a grub_uint64_t of a number of milliseconds +elapsed since arbitrary point in the past. + +Once these steps accomplished you can remove the inifinite loop and you should +be able to get to the minimal console. Next step is to have module loading +working. For this you'll need to fill kern/$cpu/dl.c and kern/$cpu/cache.S +with real handling of relocations and respectively the real sync of I and D +caches. Also you'll need to decide where in the image to store the modules. +Usual way is to have it concatenated at the end. In this case you'll need to +modify startup.S to copy modules out of bss to let's say ALIGN_UP (_end, 8) +before cleaning out bss. You'll probably find useful to add total_module_size +field to startup.S. In init.c you need to set grub_modbase to the address +where modules can be found. You may need grub_modules_get_end () to avoid +declaring the space occupied by modules as usable for heap. You can test modules +with: + +@example +./grub-mkimage -d grub-core -O $format_id -o test.img hello +@end example + +and then running ``hello'' in the shell. + +Once this works, you should think of implementing disk access. Look around +disk/ for examples. + +Then, very importantly, you probably need to implement the actual loader +(examples available in loader/) + +Last step to have minimally usable port is to add support to grub-install to +put GRUB in a place where firmware or platform will pick it up. + +Next steps are: filling datetime.c, setjmp.S, network (net/drivers), +video (video/), halt (lib/), reboot (lib/). + +Please add your platform to Platform limitations and Supported kernels chapter +in user documentation and mention any steps you skipped which result in reduced +features or performance. Here is the quick checklist of features. Some of them +are less important than others and skipping them is completely ok, just needs +to be mentioned in user documentation. + +Checklist: +@itemize +@item Is heap big enough? +@item Which charset is supported by console? +@item Does platform have disk driver? +@item Do you have network card support? +@item Are you able to retrieve datetime (with date)? +@item Are you able to set datetime (with date)? +@item Is serial supported? +@item Do you have direct disk support? +@item Do you have direct keyboard support? +@item Do you have USB support? +@item Do you support loading through network? +@item Do you support loading from disk? +@item Do you support chainloading? +@item Do you support network chainloading? +@item Does cpuid command supports checking all +CPU features that the user might want conditionalise on +(64-bit mode, hypervisor,...) +@item Do you support hints? How reliable are they? +@item Does platform have ACPI? If so do ``acpi'' and ``lsacpi'' modules work? +@item Do any of platform-specific operations mentioned in the relevant section of +user manual makes sense on your platform? +@item Does your platform support PCI? If so is there an appropriate driver for +GRUB? +@item Do you support badram? +@end itemize + +@node Error Handling +@chapter Error Handling + +Error handling in GRUB 2 is based on exception handling model. As C language +doesn't directly support exceptions, exception handling behavior is emulated +in software. + +When exception is raised, function must return to calling function. If calling +function does not provide handling of the exception it must return back to its +calling function and so on, until exception is handled. If exception is not +handled before prompt is displayed, error message will be shown to user. + +Exception information is stored on @code{grub_errno} global variable. If +@code{grub_errno} variable contains value @code{GRUB_ERR_NONE}, there is no active +exception and application can continue normal processing. When @code{grub_errno} has +other value, it is required that application code either handles this error or +returns instantly to caller. If function is with return type @code{grub_err_t} is +about to return @code{GRUB_ERR_NONE}, it should not set @code{grub_errno} to that +value. Only set @code{grub_errno} in cases where there is error situation. + +Simple exception forwarder. +@example +grub_err_t +forwarding_example (void) +@{ + /* Call function that might cause exception. */ + foobar (); + + /* No special exception handler, just forward possible exceptions. */ + if (grub_errno != GRUB_ERR_NONE) + @{ + return grub_errno; + @} + + /* All is OK, do more processing. */ + + /* Return OK signal, to caller. */ + return GRUB_ERR_NONE; +@} +@end example + +Error reporting has two components, the actual error code (of type +@code{grub_err_t}) and textual message that will be displayed to user. List of +valid error codes is listed in header file @file{include/grub/err.h}. Textual +error message can contain any textual data. At time of writing, error message +can contain up to 256 characters (including terminating NUL). To ease error +reporting there is a helper function @code{grub_error} that allows easier +formatting of error messages and should be used instead of writing directly to +global variables. + +Example of error reporting. +@example +grub_err_t +failing_example () +@{ + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "Failed to read %s, tried %d times.", + "test.txt", + 10); +@} +@end example + +If there is a special reason that error code does not need to be taken account, +@code{grub_errno} can be zeroed back to @code{GRUB_ERR_NONE}. In cases like this all +previous error codes should have been handled correctly. This makes sure that +there are no unhandled exceptions. + +Example of zeroing @code{grub_errno}. +@example +grub_err_t +probe_example () +@{ + /* Try to probe device type 1. */ + probe_for_device (); + if (grub_errno == GRUB_ERR_NONE) + @{ + /* Device type 1 was found on system. */ + register_device (); + return GRUB_ERR_NONE; + @} + /* Zero out error code. */ + grub_errno = GRUB_ERR_NONE; + + /* No device type 1 found, try to probe device type 2. */ + probe_for_device2 (); + if (grub_errno == GRUB_ERR_NONE) + @{ + /* Device type 2 was found on system. */ + register_device2 (); + return GRUB_ERR_NONE; + @} + /* Zero out error code. */ + grub_errno = GRUB_ERR_NONE; + + /* Return custom error message. */ + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No device type 1 or 2 found."); +@} +@end example + +Some times there is a need to continue processing even if there is a error +state in application. In situations like this, there is a needed to save old +error state and then call other functions that might fail. To aid in this, +there is a error stack implemented. Error state can be pushed to error stack +by calling function @code{grub_error_push ()}. When processing has been completed, +@code{grub_error_pop ()} can be used to pop error state from stack. Error stack +contains predefined amount of error stack items. Error stack is protected for +overflow and marks these situations so overflow error does not get unseen. +If there is no space available to store error message, it is simply discarded +and overflow will be marked as happened. When overflow happens, it most likely +will corrupt error stack consistency as for pushed error there is no matching +pop, but overflow message will be shown to inform user about the situation. +Overflow message will be shown at time when prompt is about to be drawn. + +Example usage of error stack. +@example +/* Save possible old error message. */ +grub_error_push (); + +/* Do your stuff here. */ +call_possibly_failing_function (); + +if (grub_errno != GRUB_ERR_NONE) + @{ + /* Inform rest of the code that there is error (grub_errno + is set). There is no pop here as we want both error states + to be displayed. */ + return; + @} + +/* Restore old error state by popping previous item from stack. */ +grub_error_pop (); +@end example + +@node CIA +@chapter CIA +@c By Robert Millan and Carles Pina +If you have commit access, please setup CIA in your Bazaar +config so those in IRC receive notification of your commits. + +In @file{~/.bazaar/bazaar.conf}, add "cia_send_revno = true". +Optionally, you can also add "cia_user = myusername" if you'd +like CIA service to use a specific account (for statistical purpose). + +In the @file{.bzr/branch/branch.conf} of your checkout branch, +"set nickname = /path_to_this_branch" and "cia_project = GNU GRUB". + +Additionally, please set cia_send_revno in the [DEFAULT] section +of your @file{~/.bazaar/bazaar.conf}. E.g.: + +@example +[DEFAULT] +cia_send_revno = true +@end example + +Remember to install cia-clients (Debian/Ubuntu package) to be able to use CIA. + +Keep in mind Bazaar sends notifications for all commits to branches that have +this setting, regardless of whether they're bound branches (checkouts) or not. +So if you make local commits in a non-bound branch and it bothers you that +others can read them, do not use this setting. + +@node BIOS port memory map +@chapter BIOS port memory map +@c By Yoshinori K Okuji + +@multitable @columnfractions .15 .25 .5 +@headitem Start @tab End @tab Usage +@item 0 @tab 0x1000 - 1 @tab BIOS and real mode interrupts +@item 0x07BE @tab 0x07FF @tab Partition table passed to another boot loader +@item ? @tab 0x2000 - 1 @tab Real mode stack +@item 0x7C00 @tab 0x7D00 - 1 @tab Boot sector +@item 0x8000 @tab ? @tab GRUB kernel +@item 0x68000 @tab 0x78000 - 1 @tab Disk buffer +@item ? @tab 0x80000 - 1 @tab Protected mode stack +@item 0x80000 @tab ? @tab Heap +@item ? @tab 0xA0000 - 1 @tab Extended BIOS Data Area +@item 0xA0000 @tab 0xC0000 - 1 @tab Video RAM +@item 0xC0000 @tab 0x100000 - 1 @tab BIOS +@item 0x100000 @tab ? @tab Heap and module code +@end multitable + +@node Video Subsystem +@chapter Video Subsystem +@c By VesaJääskeläinen +This document contains specification for Video Subsystem for GRUB2. +Currently only the usage interface is described in this document. +Internal structure of how video drivers are registering and how video +driver manager works are not included here. + +@menu +* Video API:: +* Bitmap API:: +* Example usage of Video API:: +@end menu + +@node Video API +@section Video API + +@subsection grub_video_setup + +@itemize +@item Prototype: +@example +grub_err_t +grub_video_setup (unsigned int width, unsigned int height, unsigned int mode_type); +@end example +@item Description: + +Driver will use information provided to it to select best possible video mode and switch to it. Supported values for @code{mode_type} are @code{GRUB_VIDEO_MODE_TYPE_INDEX_COLOR} for index color modes, @code{GRUB_VIDEO_MODE_TYPE_RGB} for direct RGB color modes and @code{GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED} for double buffering. When requesting RGB mode, highest bits per pixel mode will be selected. When requesting Index color mode, mode with highest number of colors will be selected. If all parameters are specified as zero, video adapter will try to figure out best possible mode and initialize it, platform specific differences are allowed here. If there is no mode matching request, error X will be returned. If there are no problems, function returns @code{GRUB_ERR_NONE}. + +This function also performs following task upon succesful mode switch. Active rendering target is changed to screen and viewport is maximized to allow whole screen to be used when performing graphics operations. In RGB modes, emulated palette gets 16 entries containing default values for VGA palette, other colors are defined as black. When switching to Indexed Color mode, driver may set default VGA palette to screen if the video card allows the operation. + +@end itemize + +@subsection grub_video_restore +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_restore (void); +@end example +@item Description: + +Video subsystem will deinitialize activated video driver to restore old state of video device. This can be used to switch back to text mode. +@end itemize + +@subsection grub_video_get_info +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_get_info (struct grub_video_mode_info *mode_info); +@end example +@example +struct grub_video_mode_info +@{ + /* Width of the screen. */ + unsigned int width; + /* Height of the screen. */ + unsigned int height; + /* Mode type bitmask. Contains information like is it Index color or + RGB mode. */ + unsigned int mode_type; + /* Bits per pixel. */ + unsigned int bpp; + /* Bytes per pixel. */ + unsigned int bytes_per_pixel; + /* Pitch of one scanline. How many bytes there are for scanline. */ + unsigned int pitch; + /* In index color mode, number of colors. In RGB mode this is 256. */ + unsigned int number_of_colors; + /* Optimization hint how binary data is coded. */ + enum grub_video_blit_format blit_format; + /* How many bits are reserved for red color. */ + unsigned int red_mask_size; + /* What is location of red color bits. In Index Color mode, this is 0. */ + unsigned int red_field_pos; + /* How many bits are reserved for green color. */ + unsigned int green_mask_size; + /* What is location of green color bits. In Index Color mode, this is 0. */ + unsigned int green_field_pos; + /* How many bits are reserved for blue color. */ + unsigned int blue_mask_size; + /* What is location of blue color bits. In Index Color mode, this is 0. */ + unsigned int blue_field_pos; + /* How many bits are reserved in color. */ + unsigned int reserved_mask_size; + /* What is location of reserved color bits. In Index Color mode, + this is 0. */ + unsigned int reserved_field_pos; +@}; +@end example +@item Description: + +Software developer can use this function to query properties of active rendering taget. Information provided here can be used by other parts of GRUB, like image loaders to convert loaded images to correct screen format to allow more optimized blitters to be used. If there there is no configured video driver with active screen, error @code{GRUB_ERR_BAD_DEVICE} is returned, otherwise @code{mode_info} is filled with valid information and @code{GRUB_ERR_NONE} is returned. +@end itemize + +@subsection grub_video_get_blit_format +@itemize +@item Prototype: + +@example +enum grub_video_blit_format +grub_video_get_blit_format (struct grub_video_mode_info *mode_info); +@end example +@example +enum grub_video_blit_format + @{ + /* Follow exactly field & mask information. */ + GRUB_VIDEO_BLIT_FORMAT_RGBA, + /* Make optimization assumption. */ + GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8, + /* Follow exactly field & mask information. */ + GRUB_VIDEO_BLIT_FORMAT_RGB, + /* Make optimization assumption. */ + GRUB_VIDEO_BLIT_FORMAT_R8G8B8, + /* When needed, decode color or just use value as is. */ + GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR + @}; +@end example +@item Description: + +Used to query how data could be optimized to suit specified video mode. Returns exact video format type, or a generic one if there is no definition for the type. For generic formats, use @code{grub_video_get_info} to query video color coding settings. +@end itemize + +@subsection grub_video_set_palette +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_set_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data); +@end example +@example +struct grub_video_palette_data +@{ + grub_uint8_t r; /* Red color value (0-255). */ + grub_uint8_t g; /* Green color value (0-255). */ + grub_uint8_t b; /* Blue color value (0-255). */ + grub_uint8_t a; /* Reserved bits value (0-255). */ +@}; +@end example +@item Description: + +Used to setup indexed color palettes. If mode is RGB mode, colors will be set to emulated palette data. In Indexed Color modes, palettes will be set to hardware. Color values will be converted to suit requirements of the video mode. @code{start} will tell what hardware color index (or emulated color index) will be set to according information in first indice of @code{palette_data}, after that both hardware color index and @code{palette_data} index will be incremented until @code{count} number of colors have been set. +@end itemize + +@subsection grub_video_get_palette +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_get_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data); +@end example +@example +struct grub_video_palette_data +@{ + grub_uint8_t r; /* Red color value (0-255). */ + grub_uint8_t g; /* Green color value (0-255). */ + grub_uint8_t b; /* Blue color value (0-255). */ + grub_uint8_t a; /* Reserved bits value (0-255). */ +@}; +@end example +@item Description: + +Used to query indexed color palettes. If mode is RGB mode, colors will be copied from emulated palette data. In Indexed Color modes, palettes will be read from hardware. Color values will be converted to suit structure format. @code{start} will tell what hardware color index (or emulated color index) will be used as a source for first indice of @code{palette_data}, after that both hardware color index and @code{palette_data} index will be incremented until @code{count} number of colors have been read. +@end itemize + +@subsection grub_video_set_viewport +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_set_viewport (unsigned int x, unsigned int y, unsigned int width, unsigned int height); +@end example +@item Description: + +Used to specify viewport where draw commands are performed. When viewport is set, all draw commands coordinates relate to those specified by @code{x} and @code{y}. If draw commands try to draw over viewport, they are clipped. If developer requests larger than possible viewport, width and height will be clamped to fit screen. If @code{x} and @code{y} are out of bounds, all functions drawing to screen will not be displayed. In order to maximize viewport, use @code{grub_video_get_info} to query actual screen dimensions and provide that information to this function. +@end itemize + +@subsection grub_video_get_viewport +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_get_viewport (unsigned int *x, unsigned int *y, unsigned int *width, unsigned int *height); +@end example +@item Description: + +Used to query current viewport dimensions. Software developer can use this to choose best way to render contents of the viewport. +@end itemize + +@subsection grub_video_map_color +@itemize +@item Prototype: + +@example +grub_video_color_t +grub_video_map_color (grub_uint32_t color_name); +@end example +@item Description: + +Map color can be used to support color themes in GRUB. There will be collection of color names that can be used to query actual screen mapped color data. Examples could be @code{GRUB_COLOR_CONSOLE_BACKGROUND}, @code{GRUB_COLOR_CONSOLE_TEXT}. The actual color defines are not specified at this point. +@end itemize + +@subsection grub_video_map_rgb +@itemize +@item Prototype: + +@example +grub_video_color_t +grub_video_map_rgb (grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue); +@end example +@item Description: + +Map RGB values to compatible screen color data. Values are expected to be in range 0-255 and in RGB modes they will be converted to screen color data. In index color modes, index color palette will be searched for specified color and then index is returned. +@end itemize + +@subsection grub_video_map_rgba +@itemize +@item Prototype: + +@example +grub_video_color_t +grub_video_map_rgba (grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue, grub_uint8_t alpha); +@end example +@item Description: + +Map RGBA values to compatible screen color data. Values are expected to be in range 0-255. In RGBA modes they will be converted to screen color data. In index color modes, index color palette will be searched for best matching color and its index is returned. +@end itemize + +@subsection grub_video_unmap_color +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_unmap_color (grub_video_color_t color, grub_uint8_t *red, grub_uint8_t *green, grub_uint8_t *blue, grub_uint8_t *alpha); +@end example +@item Description: + +Unmap color value from @code{color} to color channels in @code{red}, @code{green}, @code{blue} and @code{alpha}. Values will be in range 0-255. Active rendering target will be used for color domain. In case alpha information is not available in rendering target, it is assumed to be opaque (having value 255). +@end itemize + +@subsection grub_video_fill_rect +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_fill_rect (grub_video_color_t color, int x, int y, unsigned int width, unsigned int height); +@end example +@item Description: + +Fill specified area limited by given coordinates within specified viewport. Negative coordinates are accepted in order to allow easy moving of rectangle within viewport. If coordinates are negative, area of the rectangle will be shrinken to follow size limits of the viewport. + +Software developer should use either @code{grub_video_map_color}, @code{grub_video_map_rgb} or @code{grub_video_map_rgba} to map requested color to @code{color} parameter. +@end itemize + +@subsection grub_video_blit_glyph +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_blit_glyph (struct grub_font_glyph *glyph, grub_video_color_t color, int x, int y); +@end example +@example +struct grub_font_glyph @{ + /* TBD. */ +@}; +@end example +@item Description: + +Used to blit glyph to viewport in specified coodinates. If glyph is at edge of viewport, pixels outside of viewport will be clipped out. Software developer should use either @code{grub_video_map_rgb} or @code{grub_video_map_rgba} to map requested color to @code{color} parameter. +@end itemize + +@subsection grub_video_blit_bitmap +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_blit_bitmap (struct grub_video_bitmap *bitmap, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, unsigned int width, unsigned int height); +@end example +@example +struct grub_video_bitmap +@{ + /* TBD. */ +@}; + +enum grub_video_blit_operators + @{ + GRUB_VIDEO_BLIT_REPLACE, + GRUB_VIDEO_BLIT_BLEND + @}; +@end example +@item Description: + +Used to blit bitmap to viewport in specified coordinates. If part of bitmap is outside of viewport region, it will be clipped out. Offsets affect bitmap position where data will be copied from. Negative values for both viewport coordinates and bitmap offset coordinates are allowed. If data is looked out of bounds of bitmap, color value will be assumed to be transparent. If viewport coordinates are negative, area of the blitted rectangle will be shrinken to follow size limits of the viewport and bitmap. Blitting operator @code{oper} specifies should source pixel replace data in screen or blend with pixel alpha value. + +Software developer should use @code{grub_video_bitmap_create} or @code{grub_video_bitmap_load} to create or load bitmap data. +@end itemize + +@subsection grub_video_blit_render_target +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_blit_render_target (struct grub_video_render_target *source, enum grub_video_blit_operators oper, int x, int y, int offset_x, int offset_y, unsigned int width, unsigned int height); +@end example +@example +struct grub_video_render_target @{ + /* This is private data for video driver. Should not be accessed from elsewhere directly. */ +@}; + +enum grub_video_blit_operators + @{ + GRUB_VIDEO_BLIT_REPLACE, + GRUB_VIDEO_BLIT_BLEND + @}; +@end example +@item Description: + +Used to blit source render target to viewport in specified coordinates. If part of source render target is outside of viewport region, it will be clipped out. If blitting operator is specified and source contains alpha values, resulting pixel color components will be calculated using formula ((src_color * src_alpha) + (dst_color * (255 - src_alpha)) / 255, if target buffer has alpha, it will be set to src_alpha. Offsets affect render target position where data will be copied from. If data is looked out of bounds of render target, color value will be assumed to be transparent. Blitting operator @code{oper} specifies should source pixel replace data in screen or blend with pixel alpha value. +@end itemize + +@subsection grub_video_scroll +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_scroll (grub_video_color_t color, int dx, int dy); +@end example +@item Description: + +Used to scroll viewport to specified direction. New areas are filled with specified color. This function is used when screen is scroller up in video terminal. +@end itemize + +@subsection grub_video_swap_buffers +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_swap_buffers (void); +@end example +@item Description: + +If double buffering is enabled, this swaps frontbuffer and backbuffer, in order to show values drawn to back buffer. Video driver is free to choose how this operation is techincally done. +@end itemize + +@subsection grub_video_create_render_target +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_create_render_target (struct grub_video_render_target **result, unsigned int width, unsigned int height, unsigned int mode_type); +@end example +@example +struct grub_video_render_target @{ + /* This is private data for video driver. Should not be accessed from elsewhere directly. */ +@}; +@end example +@item Description: + +Driver will use information provided to it to create best fitting render target. @code{mode_type} will be used to guide on selecting what features are wanted for render target. Supported values for @code{mode_type} are @code{GRUB_VIDEO_MODE_TYPE_INDEX_COLOR} for index color modes, @code{GRUB_VIDEO_MODE_TYPE_RGB} for direct RGB color modes and @code{GRUB_VIDEO_MODE_TYPE_ALPHA} for alpha component. +@end itemize + +@subsection grub_video_delete_render_target +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_delete_render_target (struct grub_video_render_target *target); +@end example +@item Description: + +Used to delete previously created render target. If @code{target} contains @code{NULL} pointer, nothing will be done. If render target is correctly destroyed, GRUB_ERR_NONE is returned. +@end itemize + +@subsection grub_video_set_active_render_target +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_set_active_render_target (struct grub_video_render_target *target); +@end example +@item Description: + +Sets active render target. If this comand is successful all drawing commands will be done to specified @code{target}. There is also special values for target, @code{GRUB_VIDEO_RENDER_TARGET_DISPLAY} used to reference screen's front buffer, @code{GRUB_VIDEO_RENDER_TARGET_FRONT_BUFFER} used to reference screen's front buffer (alias for @code{GRUB_VIDEO_RENDER_TARGET_DISPLAY}) and @code{GRUB_VIDEO_RENDER_TARGET_BACK_BUFFER} used to reference back buffer (if double buffering is enabled). If render target is correclty switched GRUB_ERR_NONE is returned. In no any event shall there be non drawable active render target. + +@end itemize +@subsection grub_video_get_active_render_target +@itemize +@item Prototype: + +@example +grub_err_t +grub_video_get_active_render_target (struct grub_video_render_target **target); +@end example +@item Description: + +Returns currently active render target. It returns value in @code{target} that can be subsequently issued back to @code{grub_video_set_active_render_target}. +@end itemize + +@node Example usage of Video API +@section Example usage of Video API +@subsection Example of screen setup +@example +grub_err_t rc; +/* Try to initialize video mode 1024 x 768 with direct RGB. */ +rc = grub_video_setup (1024, 768, GRUB_VIDEO_MODE_TYPE_RGB); +if (rc != GRUB_ERR_NONE) +@{ + /* Fall back to standard VGA Index Color mode. */ + rc = grub_video_setup (640, 480, GRUB_VIDEO_MODE_TYPE_INDEX); + if (rc != GRUB_ERR_NONE) + @{ + /* Handle error. */ + @} +@} +@end example +@subsection Example of setting up console viewport +@example +grub_uint32_t x, y, width, height; +grub_video_color_t color; +struct grub_font_glyph glyph; +grub_err_t rc; +/* Query existing viewport. */ +grub_video_get_viewport (&x, &y, &width, &height); +/* Fill background. */ +color = grub_video_map_color (GRUB_COLOR_BACKGROUND); +grub_video_fill_rect (color, 0, 0, width, height); +/* Setup console viewport. */ +grub_video_set_viewport (x + 10, y + 10, width - 20, height - 20); +grub_video_get_viewport (&x, &y, &width, &height); +color = grub_video_map_color (GRUB_COLOR_CONSOLE_BACKGROUND); +grub_video_fill_rect (color, 0, 0, width, height); +/* Draw text to viewport. */ +color = grub_video_map_color (GRUB_COLOR_CONSOLE_TEXT); +grub_font_get_glyph ('X', &glyph); +grub_video_blit_glyph (&glyph, color, 0, 0); +@end example + +@node Bitmap API +@section Bitmap API +@itemize +@subsection grub_video_bitmap_create +@item Prototype: +@example +grub_err_t grub_video_bitmap_create (struct grub_video_bitmap **bitmap, unsigned int width, unsigned int height, enum grub_video_blit_format blit_format) +@end example + +@item Description: + +Creates a new bitmap with given dimensions and blitting format. Allocated bitmap data can then be modified freely and finally blitted with @code{grub_video_blit_bitmap} to rendering target. +@end itemize + +@subsection grub_video_bitmap_destroy +@itemize +@item Prototype: +@example +grub_err_t grub_video_bitmap_destroy (struct grub_video_bitmap *bitmap); +@end example + +@item Description: + +When bitmap is no longer needed, it can be freed from memory using this command. @code{bitmap} is previously allocated bitmap with @code{grub_video_bitmap_create} or loaded with @code{grub_video_bitmap_load}. +@end itemize + +@subsection grub_video_bitmap_load +@itemize +@item Prototype: +@example +grub_err_t grub_video_bitmap_load (struct grub_video_bitmap **bitmap, const char *filename); +@end example + +@item Description: + +Tries to load given bitmap (@code{filename}) using registered bitmap loaders. In case bitmap format is not recognized or supported error @code{GRUB_ERR_BAD_FILE_TYPE} is returned. +@end itemize + +@subsection grub_video_bitmap_get_width +@itemize +@item Prototype: +@example +unsigned int grub_video_bitmap_get_width (struct grub_video_bitmap *bitmap); +@end example + +@item Description: + +Returns bitmap width. +@end itemize + +@subsection grub_video_bitmap_get_height +@itemize +@item Prototype: +@example +unsigned int grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap); +@end example + +@item Description: + +Return bitmap height. +@end itemize + +@subsection grub_video_bitmap_get_mode_info +@itemize +@item Prototype: +@example +void grub_video_bitmap_get_mode_info (struct grub_video_bitmap *bitmap, struct grub_video_mode_info *mode_info); +@end example + +@item Description: + +Returns bitmap format details in form of @code{grub_video_mode_info}. +@end itemize + +@subsection grub_video_bitmap_get_data +@itemize +@item Prototype: +@example +void *grub_video_bitmap_get_data (struct grub_video_bitmap *bitmap); +@end example + +@item Description: + +Return pointer to bitmap data. Contents of the pointed data can be freely modified. There is no extra protection against going off the bounds so you have to be carefull how to access the data. +@end itemize + +@node PFF2 Font File Format +@chapter PFF2 Font File Format + +@c Author: Colin D. Bennett +@c Date: 8 January 2009 + +@menu +* Introduction:: +* File Structure:: +* Font Metrics:: +@end menu + + +@node Introduction +@section Introduction + +The goal of this format is to provide a bitmap font format that is simple to +use, compact, and cleanly supports Unicode. + + +@subsection Goals of the GRUB Font Format + +@itemize +@item Simple to read and use. +Since GRUB will only be reading the font files, +we are more concerned with making the code to read the font simple than we +are with writing the font. + +@item Compact storage. +The fonts will generally be stored in a small boot +partition where GRUB is located, and this may be on a removable storage +device such as a CD or USB flash drive where space is more limited than it +is on most hard drives. + +@item Unicode. +GRUB should not have to deal with multiple character +encodings. The font should always use Unicode character codes for simple +internationalization. +@end itemize + +@subsection Why Another Font Format? + +There are many existing bitmap font formats that GRUB could use. However, +there are aspects of these formats that may make them less than suitable for +use in GRUB at this time: + +@table @samp +@item BDF +Inefficient storage; uses ASCII to describe properties and +hexadecimal numbers in ASCII for the bitmap rows. +@item PCF +Many format variations such as byte order and bitmap padding (rows +padded to byte, word, etc.) would result in more complex code to +handle the font format. +@end table + +@node File Structure +@section File Structure + +A file @strong{section} consists of a 4-byte name, a 32-bit big-endian length (not +including the name or length), and then @var{length} more section-type-specific +bytes. + +The standard file extension for PFF2 font files is @file{.pf2}. + + +@subsection Section Types + +@table @samp +@item FILE +@strong{File type ID} (ASCII string). This must be the first section in the file. It has length 4 +and the contents are the four bytes of the ASCII string @samp{PFF2}. + +@item NAME +@strong{Font name} (ASCII string). This is the full font name including family, +weight, style, and point size. For instance, "Helvetica Bold Italic 14". + +@item FAMI +@strong{Font family name} (ASCII string). For instance, "Helvetica". This should +be included so that intelligent font substitution can take place. + +@item WEIG +@strong{Font weight} (ASCII string). Valid values are @samp{bold} and @samp{normal}. +This should be included so that intelligent font substitution can take +place. + +@item SLAN +@strong{Font slant} (ASCII string). Valid values are @samp{italic} and @samp{normal}. +This should be included so that intelligent font substitution can take +place. + +@item PTSZ +@strong{Font point size} (uint16be). + +@item MAXW +@strong{Maximum character width in pixels} (uint16be). + +@item MAXH +@strong{Maximum character height in pixels} (uint16be). + +@item ASCE +@strong{Ascent in pixels} (uint16be). @xref{Font Metrics}, for details. + +@item DESC +@strong{Descent in pixels} (uint16be). @xref{Font Metrics}, for details. + +@item CHIX +@strong{Character index.} +The character index begins with a 32-bit big-endian unsigned integer +indicating the total size of the section, not including this size value. +For each character, there is an instance of the following entry structure: + +@itemize +@item @strong{Unicode code point.} (32-bit big-endian integer.) + +@item @strong{Storage flags.} (byte.) + +@itemize +@item Bits 2..0: + +If equal to 000 binary, then the character data is stored +uncompressed beginning at the offset indicated by the character's +@strong{offset} value. + +If equal to 001 binary, then the character data is stored within a +compressed character definition block that begins at the offset +within the file indicated by the character's @strong{offset} value. +@end itemize + +@item @strong{Offset.} (32-bit big-endian integer.) + +A marker that indicates the remainder of the file is data accessed via +the character index (CHIX) section. When reading this font file, the rest +of the file can be ignored when scanning the sections. The length should +be set to -1 (0xFFFFFFFF). + +Supported data structures: + +Character definition +Each character definition consists of: + +@itemize +@item @strong{Width.} +Width of the bitmap in pixels. The bitmap's extents +represent the glyph's bounding box. @code{uint16be}. + +@item @strong{Height.} +Height of the bitmap in pixels. The bitmap's extents +represent the glyph's bounding box. @code{uint16be}. + +@item @strong{X offset.} +The number of pixels to shift the bitmap by +horizontally before drawing the character. @code{int16be}. + +@item @strong{Y offset.} +The number of pixels to shift the bitmap by +vertically before drawing the character. @code{int16be}. + +@item @strong{Device width.} +The number of pixels to advance horizontally from +this character's origin to the origin of the next character. +@code{int16be}. + +@item @strong{Bitmap data.} +This is encoded as a string of bits. It is +organized as a row-major, top-down, left-to-right bitmap. The most +significant bit of each byte is taken to be the leftmost or uppermost +bit in the byte. For the sake of compact storage, rows are not padded +to byte boundaries (i.e., a single byte may contain bits belonging to +multiple rows). The last byte of the bitmap @strong{is} padded with zero +bits in the bits positions to the right of the last used bit if the +bitmap data does not fill the last byte. + +The length of the @strong{bitmap data} field is (@var{width} * @var{height} + 7) / 8 +using integer arithmetic, which is equivalent to ceil(@var{width} * +@var{height} / 8) using real number arithmetic. + +It remains to be determined whether bitmap fonts usually make all +glyph bitmaps the same height, or if smaller glyphs are stored with +bitmaps having a lesser height. In the latter case, the baseline +would have to be used to calculate the location the bitmap should be +anchored at on screen. +@end itemize + +@end itemize +@end table + +@node Font Metrics +@section Font Metrics + +@itemize +@item Ascent. +The distance from the baseline to the top of most characters. +Note that in some cases characters may extend above the ascent. + +@item Descent. +The distance from the baseline to the bottom of most characters. Note that +in some cases characters may extend below the descent. + +@item Leading. +The amount of space, in pixels, to leave between the descent of one line of +text and the ascent of the next line. This metrics is not specified in the +current file format; instead, the font rendering engine calculates a +reasonable leading value based on the other font metrics. + +@item Horizonal leading. +The amount of space, in pixels, to leave horizontally between the left and +right edges of two adjacent glyphs. The @strong{device width} field determines +the effective leading value that is used to render the font. + +@end itemize +@image{font_char_metrics,,,,.png} + +An illustration of how the various font metrics apply to characters. + + + +@node Graphical Menu Software Design +@chapter Graphical Menu Software Design + +@c By Colin D. Bennett +@c Date: 17 August 2008 + +@menu +* Introduction_2:: +* Startup Sequence:: +* GUI Components:: +* Command Line Window:: +@end menu + +@node Introduction_2 +@section Introduction + +The @samp{gfxmenu} module provides a graphical menu interface for GRUB 2. It +functions as an alternative to the menu interface provided by the @samp{normal} +module, which uses the grub terminal interface to display a menu on a +character-oriented terminal. + +The graphical menu uses the GRUB video API, which is currently for the VESA +BIOS extensions (VBE) 2.0+. This is supported on the i386-pc platform. +However, the graphical menu itself does not depend on using VBE, so if another +GRUB video driver were implemented, the @samp{gfxmenu} graphical menu would work +on the new video driver as well. + + +@node Startup Sequence +@section Startup Sequence + +@itemize +@item grub_enter_normal_mode [normal/main.c] +@item grub_normal_execute [normal/main.c] +@item read_config_file [normal/main.c] +@item (When @file{gfxmenu.mod} is loaded with @command{insmod}, it will call @code{grub_menu_viewer_register()} to register itself.) +@item GRUB_MOD_INIT (gfxmenu) [gfxmenu/gfxmenu.c] +@item grub_menu_viewer_register [kern/menu_viewer.c] +@item grub_menu_viewer_show_menu [kern/menu_viewer.c] +@item get_current_menu_viewer() [kern/menu_viewer.c] +@item show_menu() [gfxmenu/gfxmenu.c] +@item grub_gfxmenu_model_new [gfxmenu/model.c] +@item grub_gfxmenu_view_new [gfxmenu/view.c] +@item set_graphics_mode [gfxmenu/view.c] +@item grub_gfxmenu_view_load_theme [gfxmenu/theme_loader.c] +@end itemize + + +@node GUI Components +@section GUI Components + +The graphical menu implements a GUI component system that supports a +container-based layout system. Components can be added to containers, and +containers (which are a type of component) can then be added to other +containers, to form a tree of components. Currently, the root component of +this tree is a @samp{canvas} component, which allows manual layout of its child +components. + +Components (non-container): + +@itemize +@item label +@item image +@item progress_bar +@item circular_progress +@item list (currently hard coded to be a boot menu list) +@end itemize + +Containers: + +@itemize +@item canvas +@item hbox +@item vbox +@end itemize + +The GUI component instances are created by the theme loader in +@file{gfxmenu/theme_loader.c} when a theme is loaded. Theme files specify +statements such as @samp{+vbox@{ +label @{ text="Hello" @} +label@{ text="World" @} @}} +to add components to the component tree root. By nesting the component +creation statements in the theme file, the instantiated components are nested +the same way. + +When a component is added to a container, that new child is considered @strong{owned} +by the container. Great care should be taken if the caller retains a +reference to the child component, since it will be destroyed if its parent +container is destroyed. A better choice instead of storing a pointer to the +child component is to use the component ID to find the desired component. +Component IDs do not have to be unique (it is often useful to have multiple +components with an ID of "__timeout__", for instance). + +In order to access and use components in the component tree, there are two +functions (defined in @file{gfxmenu/gui_util.c}) that are particularly useful: + +@itemize + +@item @code{grub_gui_find_by_id (root, id, callback, userdata)}: + +This function ecursively traverses the component tree rooted at @var{root}, and +for every component that has an ID equal to @var{id}, calls the function pointed +to by @var{callback} with the matching component and the void pointer @var{userdata} +as arguments. The callback function can do whatever is desired to use the +component passed in. + +@item @code{grub_gui_iterate_recursively (root, callback, userdata)}: + +This function calls the function pointed to by @var{callback} for every +component that is a descendant of @var{root} in the component tree. When the +callback function is called, the component and the void pointer @var{userdata} +as arguments. The callback function can do whatever is desired to use the +component passed in. +@end itemize + +@node Command Line Window +@section Command Line Window + +The terminal window used to provide command line access within the graphical +menu is managed by @file{gfxmenu/view.c}. The @samp{gfxterm} terminal is used, and +it has been modified to allow rendering to an offscreen render target to allow +it to be composed into the double buffering system that the graphical menu +view uses. This is bad for performance, however, so it would probably be a +good idea to make it possible to temporarily disable double buffering as long +as the terminal window is visible. There are still unresolved problems that +occur when commands are executed from the terminal window that change the +graphics mode. It's possible that making @code{grub_video_restore()} return to +the graphics mode that was in use before @code{grub_video_setup()} was called +might fix some of the problems. + + +@node Copying This Manual +@appendix Copying This Manual + +@menu +* GNU Free Documentation License:: License for copying this manual. +@end menu + +@include fdl.texi + + +@node Index +@unnumbered Index + +@c Currently, we use only the Concept Index. +@printindex cp + +@bye diff --git a/docs/grub.texi b/docs/grub.texi index 3a72bbacb..2441b2eed 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -36,6 +36,7 @@ Invariant Sections. * grub-install: (grub)Invoking grub-install. Install GRUB on your drive * grub-mkconfig: (grub)Invoking grub-mkconfig. Generate GRUB configuration * grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2. +* grub-mkrescue: (grub)Invoking grub-mkrescue. Make a GRUB rescue image @end direntry @setchapternewpage odd @@ -86,18 +87,22 @@ This edition documents version @value{VERSION}. * Images:: GRUB image files * Filesystem:: Filesystem syntax and semantics * Interface:: The menu and the command-line +* Environment:: GRUB environment variables * Commands:: The list of available builtin commands +* Internationalisation:: Topics relating to language support * Security:: Authentication and authorisation +* Platform limitations:: The list of platform-specific limitations +* Platform-specific operations:: Platform-specific operations * 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 * Invoking grub-mkpasswd-pbkdf2:: Generate GRUB password hashes +* Invoking grub-mkrescue:: Make a GRUB rescue image * Obtaining and Building GRUB:: How to obtain and build GRUB * Reporting bugs:: Where you should send a bug report * Future:: Some future plans on GRUB -* Internals:: Hacking GRUB * Copying This Manual:: Copying This Manual * Index:: @end menu @@ -109,8 +114,8 @@ This edition documents version @value{VERSION}. @menu * Overview:: What exactly GRUB is and how to use it * History:: From maggot to house fly -* Features:: GRUB features * Changes from GRUB Legacy:: Differences from previous versions +* Features:: GRUB features * Role of a boot loader:: The role of a boot loader @end menu @@ -227,7 +232,8 @@ scripting language: variables, conditionals, and loops are available. @item A small amount of persistent storage is available across reboots, using the @command{save_env} and @command{load_env} commands in GRUB and the -@command{grub-editenv} utility. +@command{grub-editenv} utility. This is not available in all configurations +(@pxref{Environment block}). @item GRUB 2 has more reliable ways to find its own files and those of target @@ -337,16 +343,24 @@ devices, partitions, and files in a directory depending on context. @item Support multiple filesystem types Support multiple filesystem types transparently, plus a useful explicit blocklist notation. The currently supported filesystem types are @dfn{Amiga -Fast FileSystem (AFFS)}, @dfn{AtheOS fs}, @dfn{BeFS}, @dfn{cpio}, @dfn{Linux -ext2/ext3/ext4}, @dfn{DOS FAT12/FAT16/FAT32}, @dfn{HFS}, @dfn{HFS+}, -@dfn{ISO9660}, @dfn{JFS}, @dfn{Minix fs}, @dfn{nilfs2}, @dfn{NTFS}, -@dfn{ReiserFS}, @dfn{Amiga Smart FileSystem (SFS)}, @dfn{tar}, @dfn{UDF}, -@dfn{BSD UFS/UFS2}, and @dfn{XFS}. @xref{Filesystem}, for more information. +Fast FileSystem (AFFS)}, @dfn{AtheOS fs}, @dfn{BeFS}, +@dfn{BtrFS} (including raid0, raid1, raid10, gzip and lzo), +@dfn{cpio} (little- and big-endian bin, odc and newc variants), +@dfn{Linux ext2/ext3/ext4}, @dfn{DOS FAT12/FAT16/FAT32}, @dfn{exFAT}, @dfn{HFS}, +@dfn{HFS+}, @dfn{ISO9660} (including Joliet, Rock-ridge and multi-chunk files), +@dfn{JFS}, @dfn{Minix fs} (versions 1, 2 and 3), @dfn{nilfs2}, +@dfn{NTFS} (including compression), @dfn{ReiserFS}, @dfn{ROMFS}, +@dfn{Amiga Smart FileSystem (SFS)}, @dfn{Squash4}, @dfn{tar}, @dfn{UDF}, +@dfn{BSD UFS/UFS2}, @dfn{XFS}, and @dfn{ZFS} (including lzjb, gzip, +zle, mirror, stripe, raidz1/2/3 and encryption in AES-CCM and AES-GCM). +@xref{Filesystem}, for more information. @item Support automatic decompression -Can decompress files which were compressed by @command{gzip}. This -function is both automatic and transparent to the user (i.e. all -functions operate upon the uncompressed contents of the specified +Can decompress files which were compressed by @command{gzip} or +@command{xz}@footnote{Only CRC32 data integrity check is supported (xz default +is CRC64 so one should use --check=crc32 option). LZMA BCJ filters are +supported.}. This function is both automatic and transparent to the user +(i.e. all functions operate upon the uncompressed contents of the specified files). This greatly reduces a file size and loading time, a particularly great benefit for floppies.@footnote{There are a few pathological cases where loading a very badly organized ELF kernel might @@ -523,51 +537,40 @@ system (@pxref{Obtaining and Building GRUB}). You can do this either from the source tarball, or as a package for your OS. After you have done that, you need to install the boot loader on a -drive (floppy or hard disk). There are two ways of doing that - either -using the utility @command{grub-install} (@pxref{Invoking -grub-install}) on a UNIX-like OS, or by running GRUB itself from a -floppy. These are quite similar, however the utility might probe a -wrong BIOS drive, so you should be careful. - -Also, if you install GRUB on a UNIX-like OS, please make sure that you -have an emergency boot disk ready, so that you can rescue your computer -if, by any chance, your hard drive becomes unusable (unbootable). +drive (floppy or hard disk) by using the utility +@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS. GRUB comes with boot images, which are normally put in the directory -@file{/usr/lib/grub/i386-pc}. Hereafter, the directory where GRUB images are -initially placed (normally @file{/usr/lib/grub/i386-pc}) will be +@file{/usr/lib/grub/-} (for BIOS-based machines +@file{/usr/lib/grub/i386-pc}). Hereafter, the directory where GRUB images are +initially placed (normally @file{/usr/lib/grub/-}) will be called the @dfn{image directory}, and the directory where the boot -loader needs to find them (usually @file{/boot/grub}) will be called +loader needs to find them (usually @file{/boot}) will be called the @dfn{boot directory}. @menu * Installing GRUB using grub-install:: * Making a GRUB bootable CD-ROM:: * Device map:: +* BIOS installation:: @end menu @node Installing GRUB using grub-install @section Installing GRUB using grub-install -@strong{Caution:} This procedure is definitely less safe, because -there are several ways in which your computer can become -unbootable. For example, most operating systems don't tell GRUB how to -map BIOS drives to OS devices correctly---GRUB merely @dfn{guesses} -the mapping. This will succeed in most cases, but not -always. Therefore, GRUB provides you with a map file called the -@dfn{device map}, which you must fix if it is wrong. @xref{Device -map}, for more details. +For information on where GRUB should be installed on PC BIOS platforms, +@pxref{BIOS installation}. -If you still do want to install GRUB under a UNIX-like OS (such +In order to install GRUB under a UNIX-like OS (such as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking grub-install}) as the superuser (@dfn{root}). The usage is basically very simple. You only need to specify one argument to the program, namely, where to install the boot loader. The -argument can be either a device file (like @samp{/dev/hda}) or a -partition specified in GRUB's notation. For example, under Linux the -following will install GRUB into the MBR of the first IDE disk: +argument has to be either a device file (like @samp{/dev/hda}). +For example, under Linux the following will install GRUB into the MBR +of the first IDE disk: @example # @kbd{grub-install /dev/hda} @@ -579,48 +582,34 @@ Likewise, under GNU/Hurd, this has the same effect: # @kbd{grub-install /dev/hd0} @end example -If it is the first BIOS drive, this is the same as well: - -@example -# @kbd{grub-install '(hd0)'} -@end example - -Or you can omit the parentheses: - -@example -# @kbd{grub-install hd0} -@end example - -But all the above examples assume that GRUB should use images under -the root directory. If you want GRUB to use images under a directory -other than the root directory, you need to specify the option -@option{--root-directory}. The typical usage is that you create a GRUB +But all the above examples assume that GRUB should put images under +the @file{/boot} directory. If you want GRUB to put images under a directory +other than @file{/boot}, you need to specify the option +@option{--boot-directory}. The typical usage is that you create a GRUB boot floppy with a filesystem. Here is an example: @example @group # @kbd{mke2fs /dev/fd0} # @kbd{mount -t ext2 /dev/fd0 /mnt} -# @kbd{grub-install --root-directory=/mnt fd0} +# @kbd{mkdir /mnt/boot} +# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0} # @kbd{umount /mnt} @end group @end example -Another example is when you have a separate boot partition -which is mounted at @file{/boot}. Since GRUB is a boot loader, it -doesn't know anything about mountpoints at all. Thus, you need to run -@command{grub-install} like this: +Some BIOSes have a bug of exposing the first partition of a USB drive as a +floppy instead of exposing the USB drive as a hard disk (they call it +``USB-FDD'' boot). In such cases, you need to install like this: @example -# @kbd{grub-install --root-directory=/boot /dev/hda} +# @kbd{losetup /dev/loop0 /dev/sdb1} +# @kbd{mount /dev/loop0 /mnt/usb} +# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} @end example -By the way, as noted above, it is quite difficult to guess BIOS drives -correctly under a UNIX-like OS. Thus, @command{grub-install} will prompt -you to check if it could really guess the correct mappings, after the -installation. The format is defined in @ref{Device map}. Please be -quite careful. If the output is wrong, it is unlikely that your -computer will be able to boot with no problem. +This install doesn't conflict with standard install as long as they are in +separate directories. Note that @command{grub-install} is actually just a shell script and the real task is done by @command{grub-mkimage} and @command{grub-setup}. @@ -629,7 +618,6 @@ using @command{grub-install}. Don't do that, however, unless you are very familiar with the internals of GRUB. Installing a boot loader on a running OS may be extremely dangerous. - @node Making a GRUB bootable CD-ROM @section Making a GRUB bootable CD-ROM @@ -639,15 +627,22 @@ using BIOS functions.}. This means that you can use the whole CD-ROM from GRUB and you don't have to make a floppy or hard disk image file, which can cause compatibility problems. -For booting from a CD-ROM, GRUB uses a special Stage 2 called -@file{stage2_eltorito}. The only GRUB files you need to have in your -bootable CD-ROM are this @file{stage2_eltorito} and optionally a config file -@file{grub.cfg}. You don't need to use @file{stage1} or @file{stage2}, -because El Torito is quite different from the standard boot process. +For booting from a CD-ROM, GRUB uses a special image called +@file{cdboot.img}, which is concatenated with @file{core.img}. The +@file{core.img} used for this should be built with at least the +@samp{iso9660} and @samp{biosdisk} modules. Your bootable CD-ROM will +usually also need to include a configuration file @file{grub.cfg} and some +other GRUB modules. -Here is an example of procedures to make a bootable CD-ROM -image. First, make a top directory for the bootable image, say, -@samp{iso}: +To make a simple generic GRUB rescue CD, you can use the +@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}): + +@example +$ @kbd{grub-mkrescue -o grub.iso} +@end example + +You will often need to include other files in your image. To do this, first +make a top directory for the bootable image, say, @samp{iso}: @example $ @kbd{mkdir iso} @@ -659,33 +654,24 @@ Make a directory for GRUB: $ @kbd{mkdir -p iso/boot/grub} @end example -Copy the file @file{stage2_eltorito}: - -@example -$ @kbd{cp /usr/lib/grub/i386-pc/stage2_eltorito iso/boot/grub} -@end example - If desired, make the config file @file{grub.cfg} under @file{iso/boot/grub} (@pxref{Configuration}), and copy any files and directories for the disc to the directory @file{iso/}. -Finally, make a ISO9660 image file like this: +Finally, make the image: @example -$ @kbd{mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \ - -boot-load-size 4 -boot-info-table -o grub.iso iso} +$ @kbd{grub-mkrescue -o grub.iso iso} @end example This produces a file named @file{grub.iso}, which then can be burned -into a CD (or a DVD). @kbd{mkisofs} has already set up the disc to boot -from the @kbd{boot/grub/stage2_eltorito} file, so there is no need to -setup GRUB on the disc. (Note that the @kbd{-boot-load-size 4} bit is -required for compatibility with the BIOS on many older machines.) +into a CD (or a DVD), or written to a USB mass storage device. -You can use the device @samp{(cd)} to access a CD-ROM in your -config file. This is not required; GRUB automatically sets the root device -to @samp{(cd)} when booted from a CD-ROM. It is only necessary to refer to -@samp{(cd)} if you want to access other drives as well. +The root device will be set up appropriately on entering your +@file{grub.cfg} configuration file, so you can refer to file names on the CD +without needing to use an explicit device name. This makes it easier to +produce rescue images that will work on both optical drives and USB mass +storage devices. @node Device map @@ -732,6 +718,72 @@ comments in the file if needed, as the GRUB utilities assume that a line is just a comment if the first character is @samp{#}. +@node BIOS installation +@section BIOS installation + +@heading MBR + +The partition table format traditionally used on PC BIOS platforms is called +the Master Boot Record (MBR) format; this is the format that allows up to +four primary partitions and additional logical partitions. With this +partition table format, there are two ways to install GRUB: it can be +embedded in the area between the MBR and the first partition (called by +various names, such as the "boot track", "MBR gap", or "embedding area", and +which is usually at least 31 KiB), or the core image can be installed in a +file system and a list of the blocks that make it up can be stored in the +first sector of that partition. + +Each of these has different problems. There is no way to reserve space in +the embedding area with complete safety, and some proprietary software is +known to use it to make it difficult for users to work around licensing +restrictions; and systems are sometimes partitioned without leaving enough +space before the first partition. On the other hand, installing to a +filesystem means that GRUB is vulnerable to its blocks being moved around by +filesystem features such as tail packing, or even by aggressive fsck +implementations, so this approach is quite fragile; and this approach can +only be used if the @file{/boot} filesystem is on the same disk that the +BIOS boots from, so that GRUB does not have to rely on guessing BIOS drive +numbers. + +The GRUB development team generally recommends embedding GRUB before the +first partition, unless you have special requirements. You must ensure that +the first partition starts at least 31 KiB (63 sectors) from the start of +the disk; on modern disks, it is often a performance advantage to align +partitions on larger boundaries anyway, so the first partition might start 1 +MiB from the start of the disk. + +@heading GPT + +Some newer systems use the GUID Partition Table (GPT) format. This was +specified as part of the Extensible Firmware Interface (EFI), but it can +also be used on BIOS platforms if system software supports it; for example, +GRUB and GNU/Linux can be used in this configuration. With this format, it +is possible to reserve a whole partition for GRUB, called the BIOS Boot +Partition. GRUB can then be embedded into that partition without the risk +of being overwritten by other software and without being contained in a +filesystem which might move its blocks around. + +When creating a BIOS Boot Partition on a GPT system, you should make sure +that it is at least 31 KiB in size. (GPT-formatted disks are not usually +particularly small, so we recommend that you make it larger than the bare +minimum, such as 1 MiB, to allow plenty of room for growth.) You must also +make sure that it has the proper partition type. Using GNU Parted, you can +set this using a command such as the following: + +@example +# @kbd{parted /dev/@var{disk} set @var{partition-number} bios_grub on} +@end example + +If you are using gdisk, set the partition type to @samp{0xEF02}. With +partitioning programs that require setting the GUID directly, it should be +@samp{21686148-6449-6e6f-744e656564454649}. + +@strong{Caution:} Be very careful which partition you select! When GRUB +finds a BIOS Boot Partition during installation, it will automatically +overwrite part of it. Make sure that the partition does not contain any +other data. + + @node Booting @chapter Booting @@ -741,6 +793,7 @@ magic. @menu * General boot methods:: How to boot OSes with GRUB generally +* Loopback booting:: Notes on booting from loopbacks * OS-specific notes:: Notes on some operating systems @end menu @@ -812,6 +865,31 @@ required. @xref{DOS/Windows}. Chain-loading is only supported on PC BIOS and EFI platforms. +@node Loopback booting +@section Loopback booting +GRUB is able to read from an image (be it one of CD or HDD) stored on +any of its accessible storages (refer to @pxref{loopback} command). +However the OS itself should be able to find its root. This usually +involves running a userspace program running before the real root +is discovered. This is achieved by GRUB loading a specially made +small image and passing it as ramdisk to the kernel. This is achieved +by commands @command{kfreebsd_module}, @command{knetbsd_module_elf}, +@command{kopenbsd_ramdisk}, @command{initrd} (@pxref{initrd}), +@command{initrd16} (@pxref{initrd}), @command{multiboot_module}, +@command{multiboot2_module} or @command{xnu_ramdisk} +depending on the loader. Note that for knetbsd the image must be put +inside miniroot.kmod and the whole miniroot.kmod has to be loaded. In +kopenbsd payload this is disabled by default. Aditionally behaviour of +initial ramdisk depends on command line options. Several distributors provide +the image for this purpose or it's integrated in their standard ramdisk and +activated by special option. Consult your kernel and distribution manual for +more details. Other loaders like appleloader, chainloader (BIOS, EFI, coreboot), +freedos, ntldr and plan9 provide no possibility of loading initial ramdisk and +as far as author is aware the payloads in question don't support either initial +ramdisk or discovering loopback boot in other way and as such not bootable this +way. Please consider alternative boot methods like copying all files +from the image to actual partition. Consult your OS documentation for +more details @node OS-specific notes @section Some caveats on OS-specific issues @@ -888,6 +966,14 @@ grub> @kbd{linux /vmlinuz root=/dev/sda1 acpi=off} See the documentation in the Linux source tree for complete information on the available options. +With @command{linux} GRUB uses 32-bit protocol. Some BIOS services like APM +or EDD aren't available with this protocol. In this case you need to use +@command{linux16} + +@example +grub> @kbd{linux16 /vmlinuz root=/dev/sda1 acpi=off} +@end example + @item If you use an initrd, execute the command @command{initrd} (@pxref{initrd}) after @command{linux}: @@ -896,6 +982,12 @@ after @command{linux}: grub> @kbd{initrd /initrd} @end example +If you used @command{linux16} you need to use @command{initrd16}: + +@example +grub> @kbd{initrd16 /initrd} +@end example + @item Finally, run the command @command{boot} (@pxref{boot}). @end enumerate @@ -978,6 +1070,16 @@ generates @file{grub.cfg} files suitable for most cases. It is suitable for use when upgrading a distribution, and will discover available kernels and attempt to generate menu entries for them. +@command{grub-mkconfig} does have some limitations. While adding extra +custom menu entries to the end of the list can be done by editing +@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg}, +changing the order of menu entries or changing their titles may require +making complex changes to shell scripts stored in @file{/etc/grub.d/}. This +may be improved in the future. In the meantime, those who feel that it +would be easier to write @file{grub.cfg} directly are encouraged to do so +(@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system +provided by their distribution to automatically run @command{grub-mkconfig}. + The file @file{/etc/default/grub} controls the operation of @command{grub-mkconfig}. It is sourced by a shell script, and so must be valid POSIX shell input; normally, it will just be a sequence of @@ -993,11 +1095,25 @@ Valid keys in @file{/etc/default/grub} are as follows: @table @samp @item GRUB_DEFAULT The default menu entry. This may be a number, in which case it identifies -the Nth entry in the generated menu counted from zero, or the full name of a -menu entry, or the special string @samp{saved}. Using the full name may be +the Nth entry in the generated menu counted from zero, or the title of a +menu entry, or the special string @samp{saved}. Using the title may be useful if you want to set a menu entry as the default even though there may be a variable number of entries before it. +For example, if you have: + +@verbatim +menuentry 'Example GNU/Linux distribution' --class gnu-linux { + ... +} +@end verbatim + +then you can make this the default using: + +@example +GRUB_DEFAULT='Example GNU/Linux distribution' +@end example + If you set this to @samp{saved}, then the default menu entry will be that saved by @samp{GRUB_SAVEDEFAULT}, @command{grub-set-default}, or @command{grub-reboot}. @@ -1010,6 +1126,8 @@ it as a new default entry for use by future runs of GRUB. This is only useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with @command{grub-set-default} or @command{grub-reboot}. Unset by default. +This option relies on the environment block, which may not be available in +all situations (@pxref{Environment block}). @item GRUB_TIMEOUT Boot the default entry this many seconds after the menu is displayed, unless @@ -1073,7 +1191,7 @@ A command to configure the serial port when using the serial console. Command-line arguments to add to menu entries for the Linux kernel. @item GRUB_CMDLINE_LINUX_DEFAULT -Unless @samp{GRUB_DISABLE_LINUX_RECOVERY} is set to @samp{true}, two menu +Unless @samp{GRUB_DISABLE_RECOVERY} is set to @samp{true}, two menu entries will be generated for each Linux kernel: one default entry and one entry for recovery mode. This option lists command-line arguments to add only to the default menu entry, after those listed in @@ -1086,8 +1204,14 @@ NetBSD. @item GRUB_CMDLINE_XEN @itemx GRUB_CMDLINE_XEN_DEFAULT -As @samp{GRUB_CMDLINE_LINUX} and @samp{GRUB_CMDLINE_LINUX_DEFAULT}, but for -Linux and Xen. +The values of these options are appended to the values of +@samp{GRUB_CMDLINE_LINUX} and @samp{GRUB_CMDLINE_LINUX_DEFAULT} for Linux +and Xen menu entries. + +@item GRUB_CMDLINE_LINUX_XEN_REPLACE +@item GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT +The values of these options replace the values of @samp{GRUB_CMDLINE_LINUX} +and @samp{GRUB_CMDLINE_LINUX_DEFAULT} for Linux and Xen menu entries. @item GRUB_DISABLE_LINUX_UUID Normally, @command{grub-mkconfig} will generate menu entries that use @@ -1096,13 +1220,9 @@ the Linux kernel, using a @samp{root=UUID=...} kernel parameter. This is usually more reliable, but in some cases it may not be appropriate. To disable the use of UUIDs, set this option to @samp{true}. -@item GRUB_DISABLE_LINUX_RECOVERY +@item GRUB_DISABLE_RECOVERY If this option is set to @samp{true}, disable the generation of recovery -mode menu entries for Linux. - -@item GRUB_DISABLE_NETBSD_RECOVERY -If this option is set to @samp{true}, disable the generation of recovery -mode menu entries for NetBSD. +mode menu entries. @item GRUB_VIDEO_BACKEND If graphical video support is required, either because the @samp{gfxterm} @@ -1118,7 +1238,8 @@ listed in @file{/boot/grub/video.lst}. Set the resolution used on the @samp{gfxterm} graphical terminal. Note that you can only use modes which your graphics card supports via VESA BIOS Extensions (VBE), so for example native LCD panel resolutions may not be -available. The default is @samp{640x480}. +available. The default is @samp{auto}, which tries to select a preferred +resolution. @xref{gfxmode}. @item GRUB_BACKGROUND Set a background image for use with the @samp{gfxterm} graphical terminal. @@ -1134,7 +1255,7 @@ Set to @samp{text} to force the Linux kernel to boot in normal text mode, @samp{keep} to preserve the graphics mode set using @samp{GRUB_GFXMODE}, @samp{@var{width}x@var{height}}[@samp{x@var{depth}}] to set a particular graphics mode, or a sequence of these separated by commas or semicolons to -try several modes in sequence. +try several modes in sequence. @xref{gfxpayload}. Depending on your kernel, your distribution, your graphics card, and the phase of the moon, note that using this option may cause GNU/Linux to suffer @@ -1157,6 +1278,11 @@ directly to @ref{play}. If this option is set, GRUB will issue a @ref{badram} command to filter out specified regions of RAM. +@item GRUB_PRELOAD_MODULES +This option may be set to a list of GRUB module names separated by spaces. +Each module will be loaded as early as possible, at the start of +@file{grub.cfg}. + @end table For more detailed customisation of @command{grub-mkconfig}'s output, you may @@ -1240,7 +1366,8 @@ protect the variable to be expanded from characters immediately following it which could be interpreted as part of the name. Normal variable names begin with an alphabetic character, followed by zero -or more alphanumeric characters. +or more alphanumeric characters. These names refer to entries in the GRUB +environment (@pxref{Environment}). Positional variable names consist of one or more digits. They represent parameters passed to function calls, with @samp{$1} representing the first @@ -1371,14 +1498,14 @@ reside anywhere on the file system, and may be removed after running @command{grub-mkimage}. After the embedded configuration file (if any) is executed, GRUB will load -the @samp{normal} module, which will then read the real configuration file -from @file{$prefix/grub.cfg}. By this point, the @code{root} variable will -also have been set to the root device name. For example, @code{prefix} -might be set to @samp{(hd0,1)/boot/grub}, and @code{root} might be set to -@samp{hd0,1}. Thus, in most cases, the embedded configuration file only -needs to set the @code{prefix} and @code{root} variables, and then drop -through to GRUB's normal processing. A typical example of this might look -like this: +the @samp{normal} module (@pxref{normal}), which will then read the real +configuration file from @file{$prefix/grub.cfg}. By this point, the +@code{root} variable will also have been set to the root device name. For +example, @code{prefix} might be set to @samp{(hd0,1)/boot/grub}, and +@code{root} might be set to @samp{hd0,1}. Thus, in most cases, the embedded +configuration file only needs to set the @code{prefix} and @code{root} +variables, and then drop through to GRUB's normal processing. A typical +example of this might look like this: @example @group @@ -1896,7 +2023,7 @@ The commands @command{terminal_input} (@pxref{terminal_input}) and @command{terminal_output} (@pxref{terminal_output}) choose which type of terminal you want to use. In the case above, the terminal will be a serial terminal, but you can also pass @code{console} to the command, -as @samp{terminal serial console}. In this case, a terminal in which +as @samp{terminal_input serial console}. In this case, a terminal in which you press any key will be selected as a GRUB terminal. In the example above, note that you need to put both commands on the same command line, as you will lose the ability to type commands on the console after the first @@ -1934,6 +2061,44 @@ model-specific. Values known to the GRUB team are: To take full advantage of this function, install GRUB into the MBR (@pxref{Installing GRUB using grub-install}). +If you have a laptop which has a similar feature and not in the above list +could you figure your address and contribute? +To discover the address do the following: +@itemize +@item boot normally +@item +@example +sudo modprobe nvram +sudo cat /dev/nvram | xxd > normal_button.txt +@end example +@item boot using vendor button +@item +@example +sudo modprobe nvram +sudo cat /dev/nvram | xxd > normal_vendor.txt +@end example +@end itemize + +Then compare these text files and find where a bit was toggled. E.g. in +case of Dell XPS it was: +@example +byte 0x47: 20 --> 28 +@end example +It's a bit number 3 as seen from following table: +@multitable @columnfractions .2 .2 +@item 0 @tab 01 +@item 1 @tab 02 +@item 2 @tab 04 +@item 3 @tab 08 +@item 4 @tab 10 +@item 5 @tab 20 +@item 6 @tab 40 +@item 7 @tab 80 +@end multitable + +0x47 is decimal 71. Linux nvram implementation cuts first 14 bytes of +CMOS. So the real byte address in CMOS is 71+14=85 +So complete address is 85:3 @node Images @chapter GRUB image files @@ -1992,28 +2157,8 @@ target operating systems, and so on) from the file system at run-time. The modular design allows the core image to be kept small, since the areas of disk where it must be installed are often as small as 32KB. -On PC systems using the traditional MBR partition table format, the core -image is usually installed in the "MBR gap" between the master boot record -and the first partition, or sometimes it is installed in a file system and -read directly from that. The latter is not recommended because GRUB needs -to encode the location of all the core image sectors in @file{diskboot.img}, -and if the file system ever moves the core image around (as it is entitled -to do) then GRUB must be reinstalled; it also means that GRUB will not be -able to reliably find the core image if it resides on a different disk than -the one to which @file{boot.img} was installed. - -On PC systems using the more recent GUID Partition Table (GPT) format, the -core image should be installed to a BIOS Boot Partition. This may be -created by GNU Parted using a command such as the following: - -@example -# @kbd{parted /dev/@var{disk} set @var{partition-number} bios_grub on} -@end example - -@strong{Caution:} Be very careful which partition you select! When GRUB -finds a BIOS Boot Partition during installation, it will automatically -overwrite part of it. Make sure that the partition does not contain any -other data. +@xref{BIOS installation}, for details on where the core image can be +installed on PC systems. @item *.mod Everything else in GRUB resides in dynamically loadable modules. These are @@ -2093,42 +2238,67 @@ you see the files in a device or use the command @command{search} The device syntax is like this: @example -@code{(@var{device}[,@var{part-num}][,@var{bsd-subpart-letter}])} +@code{(@var{device}[,@var{partmap-name1}@var{part-num1}[,@var{partmap-name2}@var{part-num2}[,...]]])} @end example -@samp{[]} means the parameter is optional. @var{device} should be -either @samp{fd} or @samp{hd} followed by a digit, like @samp{fd0}. -But you can also set @var{device} to a hexadecimal or a decimal number -which is a BIOS drive number, so the following are equivalent: +@samp{[]} means the parameter is optional. @var{device} depends on the disk +driver in use. BIOS and EFI disks use either @samp{fd} or @samp{hd} followed +by a digit, like @samp{fd0}, or @samp{cd}. +AHCI, PATA (ata), crypto, USB use the name of driver followed by a number. +Memdisk and host are limited to one disk and so it's refered just by driver +name. +RAID (md), ofdisk (ieee1275), LVM (lv) and arcdisk (arc) use intrinsic name +of disk prefixed by driver name. Conflicts are solved by suffixing a number +if necessarry. Commas need to be escaped. +Loopback uses whatever name specified to @command{loopback} command. +Hostdisk uses names specified in device.map or hostdisk/. +For crypto and RAID (md) additionally you can use the syntax +uuid/. @example +(fd0) (hd0) -(0x80) -(128) +(cd) +(ahci0) +(ata0) +(crypto0) +(usb0) +(cryptouuid/123456789abcdef0123456789abcdef0) +(mduuid/123456789abcdef0123456789abcdef0) +(lv/system-root) +(md/myraid) +(md/0) +(ieee1275/disk2) +(ieee1275//pci@@1f\,0/ide@@d/disk@@2) +(memdisk) +(host) +(myloop) +(hostdisk//dev/sda) @end example @var{part-num} represents the partition number of @var{device}, starting -from one for primary partitions and from five for extended partitions, -and @var{bsd-subpart-letter} represents the BSD disklabel subpartition, -such as @samp{a} or @samp{e}. - -A shortcut for specifying BSD subpartitions is -@code{(@var{device},@var{bsd-subpart-letter})}, in this case, GRUB -searches for the first PC partition containing a BSD disklabel, then -finds the subpartition @var{bsd-subpart-letter}. Here is an example: - -@example -(hd0,a) -@end example +from one. @var{partname} is optional but is recommended since disk may have +several top-level partmaps. Specifying third and later component you can access +to subpartitions. The syntax @samp{(hd0)} represents using the entire disk (or the MBR when installing GRUB), while the syntax @samp{(hd0,1)} represents using the first partition of the disk (or the boot sector of the partition when installing GRUB). -If you enabled the network support, the special drive @samp{(pxe)} is -also available. Before using the network drive, you must initialize the -network. @xref{Network}, for more information. +@example +(hd0,msdos1) +(hd0,msdos1,msdos5) +(hd0,msdos1,bsd3) +(hd0,netbsd1) +(hd0,gpt1) +(hd0,1,3) +@end example + +If you enabled the network support, the special drives @samp{(tftp)}, +@samp{(http)} and so on ars also available. +Before using the network drive, you must initialize the network. +@xref{Network}, for more information. If you boot GRUB from a CD-ROM, @samp{(cd)} is available. @xref{Making a GRUB bootable CD-ROM}, for details. @@ -2302,6 +2472,431 @@ Although GRUB unfortunately does not support @dfn{undo}, you can do almost the same thing by just returning to the main menu using @key{ESC}. +@node Environment +@chapter GRUB environment variables + +GRUB supports environment variables which are rather like those offered by +all Unix-like systems. Environment variables have a name, which is unique +and is usually a short identifier, and a value, which is an arbitrary string +of characters. They may be set (@pxref{set}), unset (@pxref{unset}), or +looked up (@pxref{Shell-like scripting}) by name. + +A number of environment variables have special meanings to various parts of +GRUB. Others may be used freely in GRUB configuration files. + + +@menu +* Special environment variables:: +* Environment block:: +@end menu + + +@node Special environment variables +@section Special environment variables + +These variables have special meaning to GRUB. + +@menu +* biosnum:: +* chosen:: +* color_highlight:: +* color_normal:: +* debug:: +* default:: +* fallback:: +* gfxmode:: +* gfxpayload:: +* gfxterm_font:: +* icondir:: +* lang:: +* locale_dir:: +* menu_color_highlight:: +* menu_color_normal:: +* net_pxe_boot_file:: +* net_pxe_dhcp_server_name:: +* net_pxe_domain:: +* net_pxe_extensionspath:: +* net_pxe_hostname:: +* net_pxe_ip:: +* net_pxe_mac:: +* net_pxe_rootpath:: +* pager:: +* prefix:: +* pxe_blksize:: +* pxe_default_gateway:: +* pxe_default_server:: +* root:: +* superusers:: +* theme:: +* timeout:: +@end menu + + +@node biosnum +@subsection biosnum + +When chain-loading another boot loader (@pxref{Chain-loading}), GRUB may +need to know what BIOS drive number corresponds to the root device +(@pxref{root}) so that it can set up registers properly. If the +@var{biosnum} variable is set, it overrides GRUB's own means of guessing +this. + +For an alternative approach which also changes BIOS drive mappings for the +chain-loaded system, @pxref{drivemap}. + + +@node chosen +@subsection chosen + +When executing a menu entry, GRUB sets the @var{chosen} variable to the +title of the entry being executed. + +If the menu entry is in one or more submenus, then @var{chosen} is set to +the titles of each of the submenus starting from the top level followed by +the title of the menu entry itself, separated by @samp{>}. + + +@node color_highlight +@subsection color_highlight + +This variable contains the ``highlight'' foreground and background terminal +colors, separated by a slash (@samp{/}). Setting this variable changes +those colors. For the available color names, @pxref{color_normal}. + +The default is @samp{black/white}. + + +@node color_normal +@subsection color_normal + +This variable contains the ``normal'' foreground and background terminal +colors, separated by a slash (@samp{/}). Setting this variable changes +those colors. Each color must be a name from the following list: + +@itemize @bullet +@item black +@item blue +@item green +@item cyan +@item red +@item magenta +@item brown +@item light-gray +@item dark-gray +@item light-blue +@item light-green +@item light-cyan +@item light-red +@item light-magenta +@item yellow +@item white +@end itemize + +The default is @samp{white/black}. + + +@node debug +@subsection debug + +This variable may be set to enable debugging output from various components +of GRUB. The value is a list of debug facility names separated by +whitespace or @samp{,}, or @samp{all} to enable all available debugging +output. + + +@node default +@subsection default + +If this variable is set, it identifies a menu entry that should be selected +by default, possibly after a timeout (@pxref{timeout}). The entry may be +identified by number or by title. + +If the entry is in a submenu, then it must be identified using the titles of +each of the submenus starting from the top level followed by the number or +title of the menu entry itself, separated by @samp{>}. For example, take +the following menu structure: + +@example +Submenu 1 + Menu Entry 1 + Menu Entry 2 +Submenu 2 + Submenu 3 + Menu Entry 3 + Menu Entry 4 + Menu Entry 5 +@end example + +``Menu Entry 3'' would then be identified as +@samp{Submenu 2>Submenu 3>Menu Entry 3}. + +This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple +configuration}), @command{grub-set-default}, or @command{grub-reboot}. + + +@node fallback +@subsection fallback + +If this variable is set, it identifies a menu entry that should be selected +if the default menu entry fails to boot. Entries are identified in the same +way as for @samp{default} (@pxref{default}). + + +@node gfxmode +@subsection gfxmode + +If this variable is set, it sets the resolution used on the @samp{gfxterm} +graphical terminal. Note that you can only use modes which your graphics +card supports via VESA BIOS Extensions (VBE), so for example native LCD +panel resolutions may not be available. The default is @samp{auto}, which +selects a platform-specific default that should look reasonable. + +The resolution may be specified as a sequence of one or more modes, +separated by commas (@samp{,}) or semicolons (@samp{;}); each will be tried +in turn until one is found. Each mode should be either @samp{auto}, +@samp{@var{width}x@var{height}}, or +@samp{@var{width}x@var{height}x@var{depth}}. + + +@node gfxpayload +@subsection gfxpayload + +If this variable is set, it controls the video mode in which the Linux +kernel starts up, replacing the @samp{vga=} boot option (@pxref{linux}). It +may be set to @samp{text} to force the Linux kernel to boot in normal text +mode, @samp{keep} to preserve the graphics mode set using @samp{gfxmode}, or +any of the permitted values for @samp{gfxmode} to set a particular graphics +mode (@pxref{gfxmode}). + +Depending on your kernel, your distribution, your graphics card, and the +phase of the moon, note that using this option may cause GNU/Linux to suffer +from various display problems, particularly during the early part of the +boot sequence. If you have problems, set this variable to @samp{text} and +GRUB will tell Linux to boot in normal text mode. + +The default is platform-specific. On platforms with a native text mode +(such as PC BIOS platforms), the default is @samp{text}. Otherwise the +default may be @samp{auto} or a specific video mode. + +This variable is often set by @samp{GRUB_GFXPAYLOAD_LINUX} (@pxref{Simple +configuration}). + + +@node gfxterm_font +@subsection gfxterm_font + +If this variable is set, it names a font to use for text on the +@samp{gfxterm} graphical terminal. Otherwise, @samp{gfxterm} may use any +available font. + + +@node icondir +@subsection icondir + +If this variable is set, it names a directory in which the GRUB graphical +menu should look for icons after looking in the theme's @samp{icons} +directory. @xref{Theme file format}. + + +@node lang +@subsection lang + +If this variable is set, it names the language code that the +@command{gettext} command (@pxref{gettext}) uses to translate strings. For +example, French would be named as @samp{fr}, and Simplified Chinese as +@samp{zh_CN}. + +@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a +reasonable default for this variable based on the system locale. + + +@node locale_dir +@subsection locale_dir + +If this variable is set, it names the directory where translation files may +be found (@pxref{gettext}), usually @file{/boot/grub/locale}. Otherwise, +internationalization is disabled. + +@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable +default for this variable if internationalization is needed and any +translation files are available. + + +@node menu_color_highlight +@subsection menu_color_highlight + +This variable contains the foreground and background colors to be used for +the highlighted menu entry, separated by a slash (@samp{/}). Setting this +variable changes those colors. For the available color names, +@pxref{color_normal}. + +The default is the value of @samp{color_highlight} +(@pxref{color_highlight}). + + +@node menu_color_normal +@subsection menu_color_normal + +This variable contains the foreground and background colors to be used for +non-highlighted menu entries, separated by a slash (@samp{/}). Setting this +variable changes those colors. For the available color names, +@pxref{color_normal}. + +The default is the value of @samp{color_normal} (@pxref{color_normal}). + + +@node net_pxe_boot_file +@subsection net_pxe_boot_file + +@xref{Network}. + + +@node net_pxe_dhcp_server_name +@subsection net_pxe_dhcp_server_name + +@xref{Network}. + + +@node net_pxe_domain +@subsection net_pxe_domain + +@xref{Network}. + + +@node net_pxe_extensionspath +@subsection net_pxe_extensionspath + +@xref{Network}. + + +@node net_pxe_hostname +@subsection net_pxe_hostname + +@xref{Network}. + + +@node net_pxe_ip +@subsection net_pxe_ip + +@xref{Network}. + + +@node net_pxe_mac +@subsection net_pxe_mac + +@xref{Network}. + + +@node net_pxe_rootpath +@subsection net_pxe_rootpath + +@xref{Network}. + + +@node pager +@subsection pager + +If set to @samp{1}, pause output after each screenful and wait for keyboard +input. The default is not to pause output. + + +@node prefix +@subsection prefix + +The location of the @samp{/boot/grub} directory as an absolute file name +(@pxref{File name syntax}). This is normally set by GRUB at startup based +on information provided by @command{grub-install}. GRUB modules are +dynamically loaded from this directory, so it must be set correctly in order +for many parts of GRUB to work. + + +@node pxe_blksize +@subsection pxe_blksize + +@xref{Network}. + + +@node pxe_default_gateway +@subsection pxe_default_gateway + +@xref{Network}. + + +@node pxe_default_server +@subsection pxe_default_server + +@xref{Network}. + + +@node root +@subsection root + +The root device name (@pxref{Device syntax}). Any file names that do not +specify an explicit device name are read from this device. The default is +normally set by GRUB at startup based on the value of @samp{prefix} +(@pxref{prefix}). + +For example, if GRUB was installed to the first partition of the first hard +disk, then @samp{prefix} might be set to @samp{(hd0,msdos1)/boot/grub} and +@samp{root} to @samp{hd0,msdos1}. + + +@node superusers +@subsection superusers + +This variable may be set to a list of superuser names to enable +authentication support. @xref{Security}. + + +@node theme +@subsection theme + +This variable may be set to a directory containing a GRUB graphical menu +theme. @xref{Theme file format}. + +This variable is often set by @samp{GRUB_THEME} (@pxref{Simple +configuration}). + + +@node timeout +@subsection timeout + +If this variable is set, it specifies the time in seconds to wait for +keyboard input before booting the default menu entry. A timeout of @samp{0} +means to boot the default entry immediately without displaying the menu; a +timeout of @samp{-1} (or unset) means to wait indefinitely. + +This variable is often set by @samp{GRUB_TIMEOUT} or +@samp{GRUB_HIDDEN_TIMEOUT} (@pxref{Simple configuration}). + + +@node Environment block +@section The GRUB environment block + +It is often useful to be able to remember a small amount of information from +one boot to the next. For example, you might want to set the default menu +entry based on what was selected the last time. GRUB deliberately does not +implement support for writing files in order to minimise the possibility of +the boot loader being responsible for file system corruption, so a GRUB +configuration file cannot just create a file in the ordinary way. However, +GRUB provides an ``environment block'' which can be used to save a small +amount of state. + +The environment block is a preallocated 1024-byte file, which normally lives +in @file{/boot/grub/grubenv} (although you should not assume this). At boot +time, the @command{load_env} command (@pxref{load_env}) loads environment +variables from it, and the @command{save_env} (@pxref{save_env}) command +saves environment variables to it. From a running system, the +@command{grub-editenv} utility can be used to edit the environment block. + +For safety reasons, this storage is only available when installed on a plain +disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and +using BIOS or EFI functions (no ATA, USB or IEEE1275). + +@command{grub-mkconfig} uses this facility to implement +@samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}). + + @node Commands @chapter The list of available commands @@ -2314,7 +2909,9 @@ anywhere in the menu or specifically in the menu entries. In rescue mode, only the @command{insmod} (@pxref{insmod}), @command{ls} (@pxref{ls}), @command{set} (@pxref{set}), and @command{unset} -(@pxref{unset}) commands are normally available. +(@pxref{unset}) commands are normally available. If you end up in rescue +mode and do not know what to do, then @pxref{GRUB only offers a rescue +shell}. @menu * Menu-specific commands:: @@ -2329,9 +2926,6 @@ In rescue mode, only the @command{insmod} (@pxref{insmod}), @command{ls} The semantics used in parsing the configuration file are the following: @itemize @bullet -@item -The menu-specific commands have to be used before any others. - @item The files @emph{must} be in plain-text format. @@ -2345,20 +2939,13 @@ Options are separated by spaces. @item All numbers can be either decimal or hexadecimal. A hexadecimal number must be preceded by @samp{0x}, and is case-insensitive. - -@item -Extra options or text at the end of the line are ignored unless otherwise -specified. - -@item -Unrecognized commands are added to the current entry, except before entries -start, where they are ignored. @end itemize These commands can only be used in the menu: @menu * menuentry:: Start a menu entry +* submenu:: Group menu entries @end menu @@ -2388,6 +2975,22 @@ The @option{--hotkey} option associates a hotkey with a menu entry. @end deffn +@node submenu +@subsection submenu + +@deffn Command submenu @var{title} @ + [@option{--class=class} @dots{}] [@option{--users=users}] @ + [@option{--hotkey=key}] @ + @{ @var{menu entries} @dots{} @} +This defines a submenu. An entry called @var{title} will be added to the +menu; when that entry is selected, a new menu will be displayed showing all +the entries within this submenu. + +All options are the same as in the @command{menuentry} command +(@pxref{menuentry}). +@end deffn + + @node General commands @section The list of general commands @@ -2508,6 +3111,7 @@ you forget a command, you can run the command @command{help} * drivemap:: Map a drive to another * echo:: Display a line of text * export:: Export an environment variable +* false:: Do nothing, unsuccessfully * gettext:: Translate a string * gptsync:: Fill an MBR based on GPT entries * halt:: Shut down your computer @@ -2518,16 +3122,24 @@ you forget a command, you can run the command @command{help} * keystatus:: Check key modifier status * linux:: Load a Linux kernel * linux16:: Load a Linux kernel (16-bit mode) +* list_env:: List variables in environment block +* load_env:: Load variables from environment block +* loopback:: Make a device from a filesystem image * ls:: List devices or files +* normal:: Enter normal mode +* normal_exit:: Exit from normal mode * parttool:: Modify partition table entries * password:: Set a clear-text password * password_pbkdf2:: Set a hashed password * play:: Play a tune * pxe_unload:: Unload the PXE environment +* read:: Read user input * reboot:: Reboot your computer +* save_env:: Save variables to environment block * search:: Search devices by file, label, or UUID * sendkey:: Emulate keystrokes * set:: Set an environment variable +* true:: Do nothing, successfully * unset:: Unset an environment variable * uppermem:: Set the upper memory size @end menu @@ -2770,6 +3382,15 @@ to subsidiary configuration files loaded using @command{configfile}. @end deffn +@node false +@subsection false + +@deffn Command false +Do nothing, unsuccessfully. This is mainly useful in control constructs +such as @code{if} and @code{while} (@pxref{Shell-like scripting}). +@end deffn + + @node gettext @subsection gettext @@ -2777,8 +3398,8 @@ to subsidiary configuration files loaded using @command{configfile}. Translate @var{string} into the current language. The current language code is stored in the @samp{lang} variable in GRUB's -environment. Translation files in MO format are read from -@samp{locale_dir}, usually @file{/boot/grub/locale}. +environment (@pxref{lang}). Translation files in MO format are read from +@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}. @end deffn @@ -2907,6 +3528,46 @@ This command is only available on x86 systems. @end deffn +@node list_env +@subsection list_env + +@deffn Command list_env [@option{-f} file] +List all variables in the environment block file. @xref{Environment block}. + +The @option{-f} option overrides the default location of the environment +block. +@end deffn + + +@node load_env +@subsection load_env + +@deffn Command load_env [@option{-f} file] +Load all variables from the environment block file into the environment. +@xref{Environment block}. + +The @option{-f} option overrides the default location of the environment +block. +@end deffn + + +@node loopback +@subsection loopback + +@deffn Command loopback [@option{-d}] device file +Make the device named @var{device} correspond to the contents of the +filesystem image in @var{file}. For example: + +@example +loopback loop0 /path/to/image +ls (loop0)/ +@end example + +With the @option{-d} option, delete a device previously created using this +command. +@end deffn + + @node ls @subsection ls @@ -2923,6 +3584,34 @@ name syntax}), then list the contents of that directory. @end deffn +@node normal +@subsection normal + +@deffn Command normal [file] +Enter normal mode and display the GRUB menu. + +In normal mode, commands, filesystem modules, and cryptography modules are +automatically loaded, and the full GRUB script parser is available. Other +modules may be explicitly loaded using @command{insmod} (@pxref{insmod}). + +If a @var{file} is given, then commands will be read from that file. +Otherwise, they will be read from @file{$prefix/grub.cfg} if it exists. + +@command{normal} may be called from within normal mode, creating a nested +environment. It is more usual to use @command{configfile} +(@pxref{configfile}) for this. +@end deffn + + +@node normal_exit +@subsection normal_exit + +@deffn Command normal_exit +Exit normal mode (@pxref{normal}). If this instance of normal mode was not +nested within another one, then return to rescue mode. +@end deffn + + @node parttool @subsection parttool @@ -3006,6 +3695,16 @@ This command is only available on PC BIOS systems. @end deffn +@node read +@subsection read + +@deffn Command read [var] +Read a line of input from the user. If an environment variable @var{var} is +given, set that environment variable to the line of input that was read, +with no terminating newline. +@end deffn + + @node reboot @subsection reboot @@ -3014,6 +3713,18 @@ Reboot the computer. @end deffn +@node save_env +@subsection save_env + +@deffn Command save_env [@option{-f} file] var @dots{} +Save the named variables from the environment to the environment block file. +@xref{Environment block}. + +The @option{-f} option overrides the default location of the environment +block. +@end deffn + + @node search @subsection search @@ -3194,6 +3905,15 @@ arguments, print all environment variables with their values. @end deffn +@node true +@subsection true + +@deffn Command true +Do nothing, successfully. This is mainly useful in control constructs such +as @code{if} and @code{while} (@pxref{Shell-like scripting}). +@end deffn + + @node unset @subsection unset @@ -3207,6 +3927,93 @@ Unset the environment variable @var{envvar}. This command is not yet implemented for GRUB 2, although it is planned. +@node Internationalisation +@chapter Charset +GRUB uses UTF-8 internally other than in rendering where some GRUB-specific +appropriate representation is used. All text files (including config) are +assumed to be encoded in UTF-8. + +@chapter Filesystems +NTFS, JFS, UDF, HFS+, exFAT, long filenames in FAT, Joliet part of +ISO9660 are treated as UTF-16 as per specification. AFS and BFS are read +as UTF-8, again according to specification. BtrFS, cpio, tar, squash4, minix, +minix2, minix3, ROMFS, ReiserFS, XFS, ext2, ext3, ext4, FAT (short names), +ISO9660 (plain and RockRidge), nilfs2, UFS1, UFS2 and ZFS are assumed +to be UTF-8. This might be false on systems configured with legacy charset +but as long as the charset used is superset of ASCII you should be able to +access ASCII-named files. And it's recommended to configure your system to use +UTF-8 to access the filesystem, convmv may help with migration. AFFS, SFS +and HFS never use unicode and GRUB assumes them to be in Latin1, Latin1 +and MacRoman respectively. GRUB handles filesystem case-insensitivity however +no attempt is performed at case conversion of international characters +so e.g. a file named lowercase greek alpha is treated as different from +the one named as uppercase alpha. The filesystems in questions are +NTFS (except POSIX namespace), HFS+ (by default), FAT, exFAT and +ZFS (configurable on per-subvolume basis by property ``casesensitivity'', +default sensitive). On ZFS subvolumes marked as case insensitive files +containing lowercase international characters are inaccessible. +Also like all supported filesystems except HFS+ and ZFS (configurable on +per-subvolume basis by property ``normalization'', default none) GRUB makes +no attempt at check of canonical equivalence so a file name u-diaresis is +treated as distinct from u+combining diaresis. This however means that in +order to access file on HFS+ its name must be specified in normalisation form D. +On normalized ZFS subvolumes filenames out of normalisation are inaccessible. + +@chapter Output terminal +Firmware output console ``console'' on ARC and IEEE1275 are limited to ASCII. +BIOS firmware console and VGA text are limited to ASCII and some pseudographics. +None of above mentioned is appropriate for displaying international and any +unsupported character is replaced with question mark except pseudographics +which we attempt to approximate with ASCII. EFI console on the other hand +nominally supports UTF-16 but actual language coverage depends on firmware and +may be very limited. The encoding used on serial can be chosen with +@command{terminfo} as either ASCII, UTF-8 or ``visual UTF-8''. Last one is +against the specification but results in correct rendering of right-to-left +on some readers which don't have own bidi implementation. When using gfxterm +or gfxmenu GRUB itself is responsible for rendering the text. In this case +GRUB is limited by loaded fonts. If fonts contain all required characters +then bidirectional text, cursive variants and combining marks other than +enclosing, half (e.g. left half tilde or combining overline) and double ones. +Ligatures aren't supported though. This should cover European, Middle Eastern +(if you don't mind lack of lam-alif ligature in Arabic) and East Asian scripts. +Notable unsupported scripts are Brahmic family and derived as well as +Mongolian, Tifinagh, Korean Jamo (precomposed characters have no problem) +and tonal writing (2e5-2e9). GRUB also ignores deprecated (as specified +in Unicode) characters (e.g. tags). GRUB also doesn't handle so called +``annotation characters'' If you can complete either of +two lists or, better, propose a patch to improve rendering, please contact +developper team. + +@chapter Input terminal +Firmware console on BIOS, IEEE1275 and ARC doesn't allow you to enter non-ASCII +characters. EFI specification allows for such but author is unaware of any +actual implementations. Serial input is currently limited for latin1 (unlikely +to change). Own keyboard implementations (at_keyboard and usb_keyboard) can +support any characters but work on one-char-per-keystroke. So no dead keys or +advanced input method. Also there is no keymap change hotkey. In practice it +makes difficult to enter any text using non-Latin alphabet. + +@chapter Gettext +GRUB supports being translated. For this you need to have language *.mo files in $prefix/locale, load gettext module and set ``lang'' variable. + +@chapter Regexp +Regexps work on unicode characters, however no attempt at checking cannonical +equivalence has been made. Moreover the classes like [:alpha:] match only +ASCII subset. + +@chapter Other +IEEE1275 aliases are matched case-insensitively except non-ASCII which is +matched as binary. Similar behaviour is for matching OSBundleRequired. +Since IEEE1275 aliases and OSBundleRequired don't contain any non-ASCII it +should never be a problem in practice. +Case-sensitive identifiers are matched as raw strings, no canonical +equivalence check is performed. Case-insenstive identifiers are matched +as RAW but additionally [a-z] is equivalent to [A-Z]. GRUB-defined +identifiers use only ASCII and so should user-defined ones. +Identifiers containing non-ASCII may work but aren't supported. +Only the ASCII space characters (space U+0020, tab U+000b, CR U+000d and +LF U+000a) are recognised. Other unicode space characters aren't a valid +field separator. @node Security @chapter Authentication and authorisation @@ -3275,14 +4082,177 @@ adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} commands. +@node Platform limitations +@chapter Platform limitations + +GRUB2 is designed to be portable and is actually ported across platforms. We +try to keep all platforms at the level. Unfortunately some platforms are better +supported than others. This is detailed in current and 2 following sections. + +ARC platform is unable to change datetime (firmware doesn't seem to provide a +function for it). +EMU has similar limitation. + +Console charset refers only to firmware-assisted console. gfxterm is always +Unicode (see Internationalisation section for its limitations). Serial is +configurable to UTF-8 or ASCII (see Internationalisation). In case of qemu +and coreboot ports the refered console is vga_text. Loongson always uses +gfxterm. + +Most limited one is ASCII. CP437 provides additionally pseudographics. +GRUB2 doesn't use any language characters from CP437 as often CP437 is replaced +by national encoding compatible only in pseudographics. +Unicode is the most versatile charset which supports many languages. However +the actual console may be much more limited depending on firmware + +On BIOS network is supported only if the image is loaded through network. +On sparc64 GRUB is unable to determine which server it was booted from. + +On platforms not having direct serial support (as indicated in the line serial) +you can still redirect firmware console to serial if it allows so. + +Direct ATA/AHCI support allows to circumvent various firmware limitations but +isn't needed for normal operation except on baremetal ports. + +AT keyboard support allows keyboard layout remapping and support for keys not +available through firmware. It isn't needed for normal operation except +baremetal ports. + +USB support provides benefits similar to ATA (for USB disks) or AT (for USB +keyboards). In addition it allows USBserial. + +Chainloading refers to the ability to load another bootloader through the same protocol + +Hints allow faster disk discovery by already knowing in advance which is the disk in +question. On some platforms hints are correct unless you move the disk between boots. +On other platforms it's just an educated guess. +Note that hint failure results in just reduced performance, not a failure + +BadRAM is the ability to mark some of the RAM as ``bad''. Note: due to protocol +limitations mips-loongson (with Linux protocol) +and mips-qemu_mips can use only memory up to first hole. + +@multitable @columnfractions .20 .20 .20 .20 .20 +@item @tab BIOS @tab Coreboot @tab Multiboot @tab Qemu +@item video @tab yes @tab yes @tab yes @tab yes +@item console charset @tab CP437 @tab CP437 @tab CP437 @tab CP437 +@item network @tab yes (*) @tab no @tab no @tab no +@item serial @tab yes @tab yes @tab yes @tab yes +@item ATA/AHCI @tab yes @tab yes @tab yes @tab yes +@item AT keyboard @tab yes @tab yes @tab yes @tab yes +@item USB @tab yes @tab yes @tab yes @tab yes +@item chainloader @tab local @tab yes @tab yes @tab no +@item cpuid @tab partial @tab partial @tab partial @tab partial +@item hints @tab guess @tab guess @tab guess @tab guess +@item PCI @tab yes @tab yes @tab yes @tab yes +@item badram @tab yes @tab yes @tab yes @tab yes +@item compression @tab always @tab pointless @tab no @tab no +@item exit @tab yes @tab no @tab no @tab no +@end multitable + +@multitable @columnfractions .20 .20 .20 .20 .20 +@item @tab ia32 EFI @tab amd64 EFI @tab ia32 IEEE1275 @tab Itanium +@item video @tab yes @tab yes @tab no @tab no +@item console charset @tab Unicode @tab Unicode @tab ASCII @tab Unicode +@item network @tab yes @tab yes @tab yes @tab yes +@item serial @tab yes @tab yes @tab yes @tab no +@item ATA/AHCI @tab yes @tab yes @tab yes @tab no +@item AT keyboard @tab yes @tab yes @tab yes @tab no +@item USB @tab yes @tab yes @tab yes @tab no +@item chainloader @tab local @tab local @tab no @tab local +@item cpuid @tab partial @tab partial @tab partial @tab no +@item hints @tab guess @tab guess @tab good @tab guess +@item PCI @tab yes @tab yes @tab yes @tab no +@item badram @tab yes @tab yes @tab no @tab yes +@item compression @tab no @tab no @tab no @tab no +@item exit @tab yes @tab yes @tab yes @tab yes +@end multitable + +@multitable @columnfractions .20 .20 .20 .20 .20 +@item @tab Loongson @tab sparc64 @tab Powerpc @tab ARC +@item video @tab yes @tab no @tab yes @tab no +@item console charset @tab N/A @tab ASCII @tab ASCII @tab ASCII +@item network @tab no @tab yes (*) @tab yes @tab no +@item serial @tab yes @tab no @tab no @tab no +@item ATA/AHCI @tab yes @tab no @tab no @tab no +@item AT keyboard @tab yes @tab no @tab no @tab no +@item USB @tab yes @tab no @tab no @tab no +@item chainloader @tab yes @tab no @tab no @tab no +@item cpuid @tab no @tab no @tab no @tab no +@item hints @tab good @tab good @tab good @tab no +@item PCI @tab yes @tab no @tab no @tab no +@item badram @tab yes (*) @tab no @tab no @tab no +@item compression @tab configurable @tab no @tab no @tab configurable +@item exit @tab no @tab yes @tab yes @tab yes +@end multitable + +@multitable @columnfractions .20 .20 .20 .20 .20 +@item @tab MIPS qemu @tab emu +@item video @tab no @tab no +@item console charset @tab CP437 @tab ASCII +@item network @tab no @tab yes +@item serial @tab yes @tab no +@item ATA/AHCI @tab yes @tab no +@item AT keyboard @tab yes @tab no +@item USB @tab N/A @tab yes +@item chainloader @tab yes @tab no +@item cpuid @tab no @tab no +@item hints @tab guess @tab no +@item PCI @tab no @tab no +@item badram @tab yes (*) @tab no +@item compression @tab configurable @tab no +@item exit @tab no @tab yes +@end multitable + +@node Platform-specific operations +@chapter Outline + +Some platforms have features which allows to implement +some commands useless or not implementable on others. + +Quick summary: + +Information retrieval: + +@itemize +@item mipsel-loongson: lsspd +@item mips-arc: lsdev +@item efi: lsefisystab, lssal, lsefimmap +@item i386-pc: lsapm +@item acpi-enabled (i386-pc, i386-coreboot, i386-multiboot, *-efi): lsacpi +@end itemize + +Workarounds for platform-specific issues: +@itemize +@item i386-efi/x86_64-efi: loadbios, fixvideo +@item acpi-enabled (i386-pc, i386-coreboot, i386-multiboot, *-efi): + acpi (override ACPI tables) +@item i386-pc: drivemap +@item i386-pc: sendkey +@end itemize + +Advanced operations for power users: +@itemize +@item x86: iorw (direct access to I/O ports) +@end itemize + +Miscelaneous: +@itemize +@item cmos (x86-*, ieee1275, mips-qemu_mips, mips-loongson): cmostest + (used on some laptops to check for special power-on key) +@item i386-pc: play +@end itemize + @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. +X86 support is summarised in the following table. ``Yes'' means that the kernel works on the given platform, ``crashes'' means an early kernel crash which we hope will be fixed by concerned kernel developers. ``no'' means GRUB doesn't load the 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 Plan9 @tab yes @tab no (1) +@item Freedos @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) @@ -3307,6 +4277,8 @@ X86 support is summarised in following table. ``Yes'' means that kernel works on @item @tab Multiboot @tab Qemu @item BIOS chainloading @tab no (1) @tab no (1) @item NTLDR @tab no (1) @tab no (1) +@item Plan9 @tab no (1) @tab no (1) +@item FreeDOS @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) @@ -3328,9 +4300,11 @@ X86 support is summarised in following table. ``Yes'' means that kernel works on @end multitable @multitable @columnfractions .50 .22 .22 -@item @tab 32-bit EFI @tab 64-bit EFI +@item @tab ia32 EFI @tab amd64 EFI @item BIOS chainloading @tab no (1) @tab no (1) @item NTLDR @tab no (1) @tab no (1) +@item Plan9 @tab no (1) @tab no (1) +@item FreeDOS @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 @@ -3352,9 +4326,11 @@ X86 support is summarised in following table. ``Yes'' means that kernel works on @end multitable @multitable @columnfractions .50 .22 .22 -@item @tab IEEE1275 +@item @tab ia32 IEEE1275 @item BIOS chainloading @tab no (1) @item NTLDR @tab no (1) +@item Plan9 @tab no (1) +@item FreeDOS @tab no (1) @item FreeBSD bootloader @tab crashes (1) @item 32-bit kFreeBSD @tab crashes (6) @item 64-bit kFreeBSD @tab crashes (6) @@ -3384,7 +4360,8 @@ X86 support is summarised in following table. ``Yes'' means that kernel works on @item Requires ACPI @end enumerate -PowerPC and Sparc ports support only Linux. MIPS port supports Linux and multiboot2. +PowerPC, IA64 and Sparc64 ports support only Linux. MIPS port supports Linux +and multiboot2. @chapter Boot tests @@ -3429,7 +4406,7 @@ GRUB's normal start-up procedure involves setting the @samp{prefix} environment variable to a value set in the core image by @command{grub-install}, setting the @samp{root} variable to match, loading the @samp{normal} module from the prefix, and running the @samp{normal} -command. This command is responsible for reading +command (@pxref{normal}). This command is responsible for reading @file{/boot/grub/grub.cfg}, running the menu, and doing all the useful things GRUB is supposed to do. @@ -3444,6 +4421,8 @@ device), then you can correct this and enter normal mode manually: @group # Inspect the current prefix (and other preset variables): set +# Find out which devices are available: +ls # Set to the correct value, which might be something like this: set prefix=(hd0,1)/grub set root=(hd0,1) @@ -3510,15 +4489,28 @@ Print a summary of the command-line options and exit. @item --version Print the version number of GRUB and exit. -@item --root-directory=@var{dir} -Install GRUB images under the directory @var{dir} instead of the root -directory. This option is useful when you want to install GRUB into a -separate partition or a removable disk. Here is an example in which -you have a separate @dfn{boot} partition which is mounted on -@file{/boot}: +@item --boot-directory=@var{dir} +Install GRUB images under the directory @file{@var{dir}/grub/} +This option is useful when you want to install GRUB into a +separate partition or a removable disk. +If this option is not specified then it defaults to @file{/boot}, so @example -@kbd{grub-install --root-directory=/boot hd0} +@kbd{grub-install /dev/sda} +@end example + +is equivalent to + +@example +@kbd{grub-install --boot-directory=/boot/ /dev/sda} +@end example + +Here is an example in which you have a separate @dfn{boot} partition which is +mounted on +@file{/mnt/boot}: + +@example +@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb} @end example @item --recheck @@ -3582,6 +4574,64 @@ Length of the salt. Defaults to 64. @end table +@node Invoking grub-mkrescue +@chapter Invoking grub-mkrescue + +The program @command{grub-mkrescue} generates a bootable GRUB rescue image +(@pxref{Making a GRUB bootable CD-ROM}). + +@example +grub-mkrescue -o grub.iso +@end example + +All arguments not explicitly listed as @command{grub-mkrescue} options are +passed on directly to @command{xorriso} in @command{mkisofs} emulation mode. +Options passed to @command{xorriso} will normally be interpreted as +@command{mkisofs} options; if the option @samp{--} is used, then anything +after that will be interpreted as native @command{xorriso} options. + +Non-option arguments specify additional source directories. This is +commonly used to add extra files to the image: + +@example +mkdir -p disk/boot/grub +@r{(add extra files to @file{disk/boot/grub})} +grub-mkrescue -o grub.iso disk +@end example + +@command{grub-mkrescue} accepts the following options: + +@table @option +@item --help +Print a summary of the command-line options and exit. + +@item --version +Print the version number of GRUB and exit. + +@item -o @var{file} +@itemx --output=@var{file} +Save output in @var{file}. This "option" is required. + +@item --modules=@var{modules} +Pre-load the named GRUB modules in the image. Multiple entries in +@var{modules} should be separated by whitespace (so you will probably need +to quote this for your shell). + +@item --rom-directory=@var{dir} +If generating images for the QEMU or Coreboot platforms, copy the resulting +@file{qemu.img} or @file{coreboot.elf} files respectively to the @var{dir} +directory as well as including them in the image. + +@item --xorriso=@var{file} +Use @var{file} as the @command{xorriso} program, rather than the built-in +default. + +@item --grub-mkimage=@var{file} +Use @var{file} as the @command{grub-mkimage} program, rather than the +built-in default. +@end table + + @node Obtaining and Building GRUB @appendix How to obtain and build GRUB @@ -3594,11 +4644,11 @@ how to get the latest version. @end quotation GRUB is available from the GNU alpha archive site -@uref{ftp://alpha.gnu.org/gnu/grub} or any of its mirrors. The file +@uref{ftp://ftp.gnu.org/gnu/grub} or any of its mirrors. The file will be named grub-version.tar.gz. The current version is @value{VERSION}, so the file you should grab is: -@uref{ftp://alpha.gnu.org/gnu/grub/grub-@value{VERSION}.tar.gz} +@uref{ftp://ftp.gnu.org/gnu/grub/grub-@value{VERSION}.tar.gz} To unbundle GRUB use the instruction: @@ -3673,7 +4723,7 @@ for. @item Write down anything that you think might be related. Please understand -that we often need to reproduce the same problem you encounterred in our +that we often need to reproduce the same problem you encountered in our environment. So your information should be sufficient for us to do the same thing---Don't forget that we cannot see your computer directly. If you are not sure whether to state a fact or leave it out, state it! @@ -3693,119 +4743,13 @@ Once we get your report, we will try to fix the bugs. @node Future @appendix Where GRUB will go -We started the next generation of GRUB, GRUB 2. GRUB 2 includes -internationalization, dynamic module loading, real memory management, -multiple architecture support, a scripting language, and many other -nice features. If you are interested in the development of GRUB 2, take -a look at @uref{http://www.gnu.org/software/grub/grub.html, the -homepage}. +GRUB 2 is now quite stable and used in many production systems. We are +currently working towards a 2.0 release. + +If you are interested in the development of GRUB 2, take a look at +@uref{http://www.gnu.org/software/grub/grub.html, the homepage}. -@node Internals -@appendix Hacking GRUB - -@menu -* Getting the source code:: -* Finding your way around:: -@end menu - - -@node Getting the source code -@section Getting the source code - -GRUB is maintained using the @uref{http://bazaar-vcs.org/, Bazaar revision -control system}. To fetch the primary development branch: - -@example -bzr get http://bzr.savannah.gnu.org/r/grub/trunk/grub -@end example - -The GRUB developers maintain several other branches with work in progress. -Of these, the most interesting is the experimental branch, which is a -staging area for new code which we expect to eventually merge into trunk but -which is not yet ready: - -@example -bzr get http://bzr.savannah.gnu.org/r/grub/branches/experimental -@end example - -Once you have used @kbd{bzr get} to fetch an initial copy of a branch, you -can use @kbd{bzr pull} to keep it up to date. If you have modified your -local version, you may need to resolve conflicts when pulling. - - -@node Finding your way around -@section Finding your way around - -Here is a brief map of the GRUB code base. - -GRUB uses Autoconf, but not (yet) Automake. The top-level build rules are -in @file{configure.ac}, @file{Makefile.in}, and @file{conf/*.rmk}. Each -@file{conf/*.rmk} file represents a particular target configuration, and is -processed into GNU Make rules by @file{genmk.rb} (which you only need to -look at if you are extending the build system). If you are adding a new -module which follows an existing pattern, such as a new command or a new -filesystem implementation, it is usually easiest to grep @file{conf/*.rmk} -for an existing example of that pattern to find out where it should be -added. - -Low-level boot code, such as the MBR implementation on PC BIOS systems, is -in the @file{boot/} directory. - -The GRUB kernel is in @file{kern/}. This contains core facilities such as -the device, disk, and file frameworks, environment variable handling, list -processing, and so on. The kernel should contain enough to get up to a -rescue prompt. Header files for kernel facilities, among others, are in -@file{include/}. - -Terminal implementations are in @file{term/}. - -Disk access code is spread across @file{disk/} (for accessing the disk -devices themselves), @file{partmap/} (for interpreting partition table -data), and @file{fs/} (for accessing filesystems). Note that, with the odd -specialised exception, GRUB only contains code to @emph{read} from -filesystems and tries to avoid containing any code to @emph{write} to -filesystems; this lets us confidently assure users that GRUB cannot be -responsible for filesystem corruption. - -PCI and USB bus handling is in @file{bus/}. - -Video handling code is in @file{video/}. The graphical menu system uses -this heavily, but is in a separate directory, @file{gfxmenu/}. - -Most commands are implemented by files in @file{commands/}, with the -following exceptions: - -@itemize -@item -A few core commands live in @file{kern/corecmd.c}. - -@item -Commands related to normal mode live under @file{normal/}. - -@item -Commands that load and boot kernels live under @file{loader/}. - -@item -The @samp{loopback} command is really a disk device, and so lives in -@file{disk/loopback.c}. - -@item -The @samp{gettext} command lives under @file{gettext/}. - -@item -The @samp{loadfont} and @samp{lsfonts} commands live under @file{font/}. - -@item -The @samp{serial}, @samp{terminfo}, and @samp{background_image} commands -live under @file{term/}. - -@item -The @samp{efiemu_*} commands live under @file{efiemu/}. -@end itemize - -There are a few other special-purpose exceptions; grep for them if they -matter to you. diff --git a/docs/man/grub-bin2h.h2m b/docs/man/grub-bin2h.h2m deleted file mode 100644 index ef463f3d1..000000000 --- a/docs/man/grub-bin2h.h2m +++ /dev/null @@ -1,2 +0,0 @@ -[NAME] -grub-bin2h \- convert a binary file to a C header diff --git a/docs/man/grub-editenv.h2m b/docs/man/grub-editenv.h2m index efbd79070..3859d3d4c 100644 --- a/docs/man/grub-editenv.h2m +++ b/docs/man/grub-editenv.h2m @@ -1,2 +1,5 @@ [NAME] grub-editenv \- edit GRUB environment block +[SEE ALSO] +.BR grub-reboot (8), +.BR grub-set-default (8) diff --git a/docs/man/grub-emu.h2m b/docs/man/grub-emu.h2m index 09a1f88c1..ef1c00065 100644 --- a/docs/man/grub-emu.h2m +++ b/docs/man/grub-emu.h2m @@ -1,2 +1,6 @@ [NAME] grub-emu \- GRUB emulator +[SEE ALSO] +If you are trying to install GRUB, then you should use +.BR grub-install (8) +rather than this program. diff --git a/docs/man/grub-fstest.h2m b/docs/man/grub-fstest.h2m index be39429b5..9676b159a 100644 --- a/docs/man/grub-fstest.h2m +++ b/docs/man/grub-fstest.h2m @@ -1,2 +1,4 @@ [NAME] grub-fstest \- debug tool for GRUB filesystem drivers +[SEE ALSO] +.BR grub-probe (8) diff --git a/docs/man/grub-install.h2m b/docs/man/grub-install.h2m index 65252155c..2de371a3f 100644 --- a/docs/man/grub-install.h2m +++ b/docs/man/grub-install.h2m @@ -1,2 +1,7 @@ [NAME] grub-install \- install GRUB to a device +[SEE ALSO] +.BR grub-mkconfig (8), +.BR grub-mkimage (1), +.BR grub-setup (8), +.BR grub-mkrescue (1) diff --git a/docs/man/grub-macho2img.h2m b/docs/man/grub-macho2img.h2m index 412bf926a..d79aaeed8 100644 --- a/docs/man/grub-macho2img.h2m +++ b/docs/man/grub-macho2img.h2m @@ -1,2 +1,4 @@ [NAME] grub-macho2img \- convert Mach-O to raw image +[SEE ALSO] +.BR grub-mkimage (1) diff --git a/docs/man/grub-menulst2cfg.h2m b/docs/man/grub-menulst2cfg.h2m index 0c0570f27..c2e0055ed 100644 --- a/docs/man/grub-menulst2cfg.h2m +++ b/docs/man/grub-menulst2cfg.h2m @@ -1,3 +1,4 @@ [NAME] grub-menulst2cfg \- transform legacy menu.lst into grub.cfg - +[SEE ALSO] +.BR grub-mkconfig (8) diff --git a/docs/man/grub-mkconfig.h2m b/docs/man/grub-mkconfig.h2m index b0d33ec61..9b42f8130 100644 --- a/docs/man/grub-mkconfig.h2m +++ b/docs/man/grub-mkconfig.h2m @@ -1,2 +1,4 @@ [NAME] grub-mkconfig \- generate a GRUB configuration file +[SEE ALSO] +.BR grub-install (8) diff --git a/docs/man/grub-mkdevicemap.h2m b/docs/man/grub-mkdevicemap.h2m index 8ab34ac86..3ef8e9712 100644 --- a/docs/man/grub-mkdevicemap.h2m +++ b/docs/man/grub-mkdevicemap.h2m @@ -1,2 +1,4 @@ [NAME] grub-mkdevicemap \- generate a GRUB device map file automatically +[SEE ALSO] +.BR grub-install (8) diff --git a/docs/man/grub-mkfont.h2m b/docs/man/grub-mkfont.h2m index d8580186f..d46fe600e 100644 --- a/docs/man/grub-mkfont.h2m +++ b/docs/man/grub-mkfont.h2m @@ -1,2 +1,4 @@ [NAME] grub-mkfont \- make GRUB font files +[SEE ALSO] +.BR grub-mkconfig (8) diff --git a/docs/man/grub-mkimage.h2m b/docs/man/grub-mkimage.h2m index 71f270940..ca08b0c5c 100644 --- a/docs/man/grub-mkimage.h2m +++ b/docs/man/grub-mkimage.h2m @@ -1,2 +1,7 @@ [NAME] grub-mkimage \- make a bootable image of GRUB +[SEE ALSO] +.BR grub-install (8), +.BR grub-setup (8), +.BR grub-mkrescue (1), +.BR grub-mknetdir (8) diff --git a/docs/man/grub-mklayout.h2m b/docs/man/grub-mklayout.h2m index e0ae9dedb..1e43409c0 100644 --- a/docs/man/grub-mklayout.h2m +++ b/docs/man/grub-mklayout.h2m @@ -1,2 +1,10 @@ [NAME] grub-mklayout \- generate a GRUB keyboard layout file +[DESCRIPTION] +grub-mklayout processes a keyboard layout description in +.BR keymaps (5) +format into a format that can be used by GRUB's +.B keymap +command. +[SEE ALSO] +.BR grub-mkconfig (8) diff --git a/docs/man/grub-mknetdir.h2m b/docs/man/grub-mknetdir.h2m index 26defe876..a2ef13ec1 100644 --- a/docs/man/grub-mknetdir.h2m +++ b/docs/man/grub-mknetdir.h2m @@ -1,2 +1,4 @@ [NAME] grub-mknetdir \- prepare a GRUB netboot directory. +[SEE ALSO] +.BR grub-mkimage (1) diff --git a/docs/man/grub-mkpasswd-pbkdf2.h2m b/docs/man/grub-mkpasswd-pbkdf2.h2m index 5b2b2ef7f..4d202f3da 100644 --- a/docs/man/grub-mkpasswd-pbkdf2.h2m +++ b/docs/man/grub-mkpasswd-pbkdf2.h2m @@ -1,2 +1,4 @@ [NAME] grub-mkpasswd-pbkdf2 \- generate hashed password for GRUB +[SEE ALSO] +.BR grub-mkconfig (8) diff --git a/docs/man/grub-mkrelpath.h2m b/docs/man/grub-mkrelpath.h2m index ccc0880fa..d01f3961e 100644 --- a/docs/man/grub-mkrelpath.h2m +++ b/docs/man/grub-mkrelpath.h2m @@ -1,2 +1,4 @@ [NAME] grub-mkrelpath \- make a system path relative to its root +[SEE ALSO] +.BR grub-probe (8) diff --git a/docs/man/grub-mkrescue.h2m b/docs/man/grub-mkrescue.h2m index 5e92e0d99..a427f02e3 100644 --- a/docs/man/grub-mkrescue.h2m +++ b/docs/man/grub-mkrescue.h2m @@ -1,2 +1,4 @@ [NAME] grub-mkrescue \- make a GRUB rescue image +[SEE ALSO] +.BR grub-mkimage (1) diff --git a/docs/man/grub-mkstandalone.h2m b/docs/man/grub-mkstandalone.h2m new file mode 100644 index 000000000..c77313978 --- /dev/null +++ b/docs/man/grub-mkstandalone.h2m @@ -0,0 +1,4 @@ +[NAME] +grub-mkstandalone \- make a memdisk-based GRUB image +[SEE ALSO] +.BR grub-mkimage (1) diff --git a/docs/man/grub-mount.h2m b/docs/man/grub-mount.h2m new file mode 100644 index 000000000..8d168982d --- /dev/null +++ b/docs/man/grub-mount.h2m @@ -0,0 +1,2 @@ +[NAME] +grub-mount \- export GRUB filesystem with FUSE diff --git a/docs/man/grub-ofpathname.h2m b/docs/man/grub-ofpathname.h2m index f07158cb3..74b43eea0 100644 --- a/docs/man/grub-ofpathname.h2m +++ b/docs/man/grub-ofpathname.h2m @@ -1,2 +1,4 @@ [NAME] grub-ofpathname \- find OpenBOOT path for a device +[SEE ALSO] +.BR grub-probe (8) diff --git a/docs/man/grub-pe2elf.h2m b/docs/man/grub-pe2elf.h2m index 3fdb88b43..7ca29bd70 100644 --- a/docs/man/grub-pe2elf.h2m +++ b/docs/man/grub-pe2elf.h2m @@ -1,2 +1,4 @@ [NAME] grub-pe2elf \- convert PE image to ELF +[SEE ALSO] +.BR grub-mkimage (1) diff --git a/docs/man/grub-probe.h2m b/docs/man/grub-probe.h2m index 817ba8ef6..6e1ffdcf9 100644 --- a/docs/man/grub-probe.h2m +++ b/docs/man/grub-probe.h2m @@ -1,2 +1,4 @@ [NAME] grub-probe \- probe device information for GRUB +[SEE ALSO] +.BR grub-fstest (1) diff --git a/docs/man/grub-reboot.h2m b/docs/man/grub-reboot.h2m index 957e4b797..e4acace65 100644 --- a/docs/man/grub-reboot.h2m +++ b/docs/man/grub-reboot.h2m @@ -1,2 +1,5 @@ [NAME] grub-reboot \- set the default boot entry for GRUB, for the next boot only +[SEE ALSO] +.BR grub-set-default (8), +.BR grub-editenv (1) diff --git a/docs/man/grub-script-check.h2m b/docs/man/grub-script-check.h2m index 39c0a3ef6..365368267 100644 --- a/docs/man/grub-script-check.h2m +++ b/docs/man/grub-script-check.h2m @@ -1,2 +1,4 @@ [NAME] grub-script-check \- check grub.cfg for syntax errors +[SEE ALSO] +.BR grub-mkconfig (8) diff --git a/docs/man/grub-set-default.h2m b/docs/man/grub-set-default.h2m index 3ac13d7ed..7945001c1 100644 --- a/docs/man/grub-set-default.h2m +++ b/docs/man/grub-set-default.h2m @@ -1,2 +1,5 @@ [NAME] -grub-set-default \- set the default boot entry for GRUB +grub-set-default \- set the saved default boot entry for GRUB +[SEE ALSO] +.BR grub-reboot (8), +.BR grub-editenv (1) diff --git a/docs/man/grub-setup.h2m b/docs/man/grub-setup.h2m index e70e465a4..eebe3ef38 100644 --- a/docs/man/grub-setup.h2m +++ b/docs/man/grub-setup.h2m @@ -1,2 +1,6 @@ [NAME] grub-setup \- set up a device to boot using GRUB +[SEE ALSO] +.BR grub-install (8), +.BR grub-mkimage (1), +.BR grub-mkrescue (1) diff --git a/gentpl.py b/gentpl.py index a42a60667..3008b8018 100644 --- a/gentpl.py +++ b/gentpl.py @@ -6,8 +6,9 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "i386_multiboot", "i386_ieee1275", "x86_64_efi", - "mips_yeeloong", "sparc64_ieee1275", - "powerpc_ieee1275" ] + "mips_loongson", "sparc64_ieee1275", + "powerpc_ieee1275", "mips_arc", "ia64_efi", + "mips_qemu_mips" ] GROUPS = {} @@ -17,34 +18,35 @@ GROUPS["common"] = GRUB_PLATFORMS[:] 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["mips"] = [ "mips_yeeloong" ] +GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ] GROUPS["sparc64"] = [ "sparc64_ieee1275" ] GROUPS["powerpc"] = [ "powerpc_ieee1275" ] # Groups based on firmware -GROUPS["x86_efi"] = [ "i386_efi", "x86_64_efi" ] +GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi" ] GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] # emu is a special case so many core functionality isn't needed on this platform GROUPS["noemu"] = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu") # 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["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips", + "sparc64_ieee1275", "powerpc_ieee1275"] +GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi") +GROUPS["pci"] = GROUPS["x86"] + ["mips_loongson"] GROUPS["usb"] = GROUPS["pci"] # If gfxterm is main output console integrate it into kernel -GROUPS["videoinkernel"] = ["mips_yeeloong"] +GROUPS["videoinkernel"] = ["mips_loongson", "mips_qemu_mips"] GROUPS["videomodules"] = GRUB_PLATFORMS[:]; for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i) # Similar for terminfo -GROUPS["terminfoinkernel"] = ["mips_yeeloong"] + GROUPS["ieee1275"]; +GROUPS["terminfoinkernel"] = ["mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"]; GROUPS["terminfomodule"] = GRUB_PLATFORMS[:]; for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].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") @@ -180,6 +182,17 @@ def foreach_platform_specific_value(platform, suffix, nonetag, closure): r += "[+ ELSE +][+ FOR " + nonetag + " +]" + closure("[+ ." + nonetag + " +]") + "[+ ENDFOR +][+ ENDIF +]" return r +# +# Returns autogen code that defines an autogen macro using the +# definition given in the 'snippet'. +# +def define_autogen_macro(name, snippet): + r = "" + r += "[+ DEFINE " + name + " +]" + r += snippet + r += "[+ ENDDEF +]\n" + return r + # # Template for handling values from sum of all groups for a platform, # for example: @@ -238,14 +251,22 @@ def foreach_enabled_platform(closure): # noemu = bus/usb/usbhub.c; # enable = emu; # enable = i386; -# enable = mips_yeeloong; +# enable = mips_loongson; # emu_condition = COND_GRUB_EMU_USB; # }; # +def define_macro_for_platform_conditionals_if_statement(p): + return define_autogen_macro( + "if_" + p + "_conditionals", + foreach_platform_specific_value(platform, "_condition", "condition", lambda cond: "if " + cond + "\n")) +def define_macro_for_platform_conditionals_endif_statement(p): + return define_autogen_macro( + "endif_" + p + "_conditionals", + foreach_platform_specific_value(platform, "_condition", "condition", lambda cond: "endif " + cond + "\n")) def under_platform_specific_conditionals(platform, snippet): - r = foreach_platform_specific_value(platform, "_condition", "condition", lambda cond: "if " + cond + "\n") + r = "[+ if_" + platform + "_conditionals +]" r += snippet - r += foreach_platform_specific_value(platform, "_condition", "condition", lambda cond: "endif " + cond + "\n") + r += "[+ endif_" + platform + "_conditionals +]" return r def platform_specific_values(platform, suffix, nonetag): @@ -258,18 +279,69 @@ def platform_values(platform, suffix): def extra_dist(): return foreach_value("extra_dist", lambda value: value + " ") -def platform_sources(p): return platform_values(p, "") -def platform_nodist_sources(p): return platform_values(p, "_nodist") -def platform_dependencies(p): return platform_values(p, "dependencies", "_dependencies") +def define_macro_for_platform_sources(p): + return define_autogen_macro( + "get_" + p + "_sources", + platform_values(p, "")) +def define_macro_for_platform_nodist_sources(p): + return define_autogen_macro( + "get_" + p + "_nodist_sources", + platform_values(p, "_nodist")) +def define_macro_for_platform_dependencies(p): + return define_autogen_macro( + "get_" + p + "_dependencies", + platform_values(p, "dependencies", "_dependencies")) +def platform_sources(p): return "[+ get_" + p + "_sources +]" +def platform_nodist_sources(p): return "[+ get_" + p + "_nodist_sources +]" +def platform_dependencies(p): return "[+ get_" + p + "_dependencies +]" -def platform_startup(p): return platform_specific_values(p, "_startup", "startup") -def platform_ldadd(p): return platform_specific_values(p, "_ldadd", "ldadd") -def platform_cflags(p): return platform_specific_values(p, "_cflags", "cflags") -def platform_ldflags(p): return platform_specific_values(p, "_ldflags", "ldflags") -def platform_cppflags(p): return platform_specific_values(p, "_cppflags", "cppflags") -def platform_ccasflags(p): return platform_specific_values(p, "_ccasflags", "ccasflags") -def platform_stripflags(p): return platform_specific_values(p, "_stripflags", "stripflags") -def platform_objcopyflags(p): return platform_specific_values(p, "_objcopyflags", "objcopyflags") +# +# Returns Autogen code which defines the autogen macros that collect +# platform specific values for cflags, ldflags, etc. tags. +# +def define_macro_for_platform_startup(p): + return define_autogen_macro( + "get_" + p + "_startup", + platform_specific_values(p, "_startup", "startup")) +def define_macro_for_platform_cflags(p): + return define_autogen_macro( + "get_" + p + "_cflags", + platform_specific_values(p, "_cflags", "cflags")) +def define_macro_for_platform_ldadd(p): + return define_autogen_macro( + "get_" + p + "_ldadd", + platform_specific_values(p, "_ldadd", "ldadd")) +def define_macro_for_platform_ldflags(p): + return define_autogen_macro( + "get_" + p + "_ldflags", + platform_specific_values(p, "_ldflags", "ldflags")) +def define_macro_for_platform_cppflags(p): + return define_autogen_macro( + "get_" + p + "_cppflags", + platform_specific_values(p, "_cppflags", "cppflags")) +def define_macro_for_platform_ccasflags(p): + return define_autogen_macro( + "get_" + p + "_ccasflags", + platform_specific_values(p, "_ccasflags", "ccasflags")) +def define_macro_for_platform_stripflags(p): + return define_autogen_macro( + "get_" + p + "_stripflags", + platform_specific_values(p, "_stripflags", "stripflags")) +def define_macro_for_platform_objcopyflags(p): + return define_autogen_macro( + "get_" + p + "_objcopyflags", + platform_specific_values(p, "_objcopyflags", "objcopyflags")) +# +# Autogen calls to invoke the above macros. +# +def platform_startup(p): return "[+ get_" + p + "_startup +]" +def platform_ldadd(p): return "[+ get_" + p + "_ldadd +]" +def platform_cflags(p): return "[+ get_" + p + "_cflags +]" +def platform_ldflags(p): return "[+ get_" + p + "_ldflags +]" +def platform_cppflags(p): return "[+ get_" + p + "_cppflags +]" +def platform_ccasflags(p): return "[+ get_" + p + "_ccasflags +]" +def platform_stripflags(p): return "[+ get_" + p + "_stripflags +]" +def platform_objcopyflags(p): return "[+ get_" + p + "_objcopyflags +]" # # Emit snippet only the first time through for the current name. @@ -486,7 +558,6 @@ def script_rules(): def data_rules(): return rules("data", data) -print "[+ AutoGen5 template +]\n" a = module_rules() b = kernel_rules() c = image_rules() @@ -496,11 +567,28 @@ f = script_rules() g = data_rules() z = global_variable_initializers() +print ("[+ AutoGen5 template +]\n") +for p in GRUB_PLATFORMS: + print (define_macro_for_platform_sources(p)) + print (define_macro_for_platform_nodist_sources(p)) + # print define_macro_for_platform_dependencies(p) + + print (define_macro_for_platform_startup(p)) + print (define_macro_for_platform_cflags(p)) + print (define_macro_for_platform_ldadd(p)) + print (define_macro_for_platform_ldflags(p)) + print (define_macro_for_platform_cppflags(p)) + print (define_macro_for_platform_ccasflags(p)) + print (define_macro_for_platform_stripflags(p)) + print (define_macro_for_platform_objcopyflags(p)) + + print (define_macro_for_platform_conditionals_if_statement(p)) + print (define_macro_for_platform_conditionals_endif_statement(p)) # print z # initializer for all vars -print a -print b -print c -print d -print e -print f -print g +print (a) +print (b) +print (c) +print (d) +print (e) +print (f) +print (g) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 9792dd974..4a46e1d9c 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -1,4 +1,4 @@ -AUTOMAKE_OPTIONS = subdir-objects +AUTOMAKE_OPTIONS = subdir-objects -Wno-portability DEPDIR=.deps-core @@ -30,7 +30,7 @@ CCASFLAGS_LIBRARY += $(CCASFLAGS_PLATFORM) # gentrigtables gentrigtables: gentrigtables.c - $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(CPPFLAGS) -lm $< + $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(CPPFLAGS) $< -lm CLEANFILES += gentrigtables # trigtables.c @@ -50,7 +50,7 @@ grub_script.yy.h: script/yylex.l grub_script.yy.c: grub_script.yy.h rs_decoder.S: $(srcdir)/lib/reed_solomon.c - $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 -mregparm=3 + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Os -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 -mregparm=3 kern/i386/pc/startup.S: $(builddir)/rs_decoder.S @@ -78,12 +78,11 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.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/mm_private.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h if COND_i386_pc -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.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 @@ -99,10 +98,12 @@ endif if COND_i386_coreboot KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/i386/pc/int.h endif if COND_i386_multiboot KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/i386/pc/int.h endif if COND_i386_qemu @@ -125,7 +126,39 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif -if COND_mips_yeeloong +if COND_ia64_efi +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 +endif + +if COND_mips +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/kernel.h +endif + +if COND_mips_arc +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arc/arc.h +endif + +if COND_mips_qemu_mips +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bitmap.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bitmap_scale.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/serial.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +endif + +if COND_mips_loongson KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h @@ -145,6 +178,11 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h endif +if COND_mips_qemu_mips +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +endif + if COND_powerpc_ieee1275 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h @@ -163,6 +201,7 @@ endif if COND_emu KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/export.h if COND_GRUB_EMU_SDL KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h endif @@ -237,9 +276,9 @@ command.lst: $(MARKER_FILES) (for pp in $^; do \ b=`basename $$pp .marker`; \ sed -n \ - -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" \ -e "/EXTCOMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ - -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" $$pp; \ + -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ + -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ done) | sort -u > $@ platform_DATA += command.lst CLEANFILES += command.lst @@ -303,8 +342,9 @@ platform_DATA += moddep.lst CLEANFILES += config.log syminfo.lst moddep.lst $(MOD_FILES): %.mod : genmod.sh moddep.lst %.module$(EXEEXT) - sh $^ $@ + TARGET_OBJ2ELF=@TARGET_OBJ2ELF@ sh $^ $@ platform_DATA += $(MOD_FILES) +platform_DATA += modinfo.sh CLEANFILES += $(MOD_FILES) if COND_ENABLE_EFIEMU diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 8845c26ea..80054b3da 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -12,37 +12,61 @@ script = { common = genmod.sh.in; }; +script = { + installdir = noinst; + name = modinfo.sh; + common = modinfo.sh.in; +}; + +script = { + installdir = noinst; + name = gmodule.pl; + common = gmodule.pl.in; +}; + +script = { + installdir = noinst; + name = gdb_grub; + common = gdb_grub.in; +}; + kernel = { name = kernel; nostrip = emu; emu_ldflags = '-Wl,-r,-d'; - x86_efi_ldflags = '-Wl,-r,-d'; - x86_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment'; + i386_efi_ldflags = '-Wl,-r,-d'; + i386_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment'; + x86_64_efi_ldflags = '-Wl,-r,-d'; + x86_64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment'; + + ia64_efi_cflags = '-fno-builtin -fpic -minline-int-divide-max-throughput'; + ia64_efi_ldflags = '-Wl,-r,-d'; + ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment'; i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; - i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000'; i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)'; i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200'; + ldadd = '$(LDADD_KERNEL)'; + i386_coreboot_ldflags = '-Wl,-Ttext=0x8200'; i386_multiboot_ldflags = '-Wl,-Ttext=0x8200'; i386_ieee1275_ldflags = '-Wl,-Ttext=0x10000'; - mips_yeeloong_ldflags = '-Wl,-Ttext,0x80200000'; + mips_loongson_ldflags = '-Wl,-Ttext,0x80200000'; powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; + mips_arc_ldflags = '-Wl,-Ttext,0x8bd00000'; + mips_qemu_mips_ldflags = '-Wl,-Ttext,0x80200000'; - mips_yeeloong_cppflags = '-DUSE_ASCII_FAILBACK'; + mips_loongson_cppflags = '-DUSE_ASCII_FAILBACK'; i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)'; emu_cflags = '$(CFLAGS_GNULIB)'; emu_cppflags = '$(CPPFLAGS_GNULIB)'; - mips_ldadd = '-lgcc'; - powerpc_ldadd = '-lgcc'; - sparc64_ldadd = '-lgcc'; - i386_pc_startup = kern/i386/pc/startup.S; i386_efi_startup = kern/i386/efi/startup.S; x86_64_efi_startup = kern/x86_64/efi/startup.S; @@ -50,7 +74,7 @@ kernel = { i386_ieee1275_startup = kern/i386/ieee1275/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; + mips_startup = kern/mips/startup.S; sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S; powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S; @@ -79,18 +103,18 @@ kernel = { noemu_nodist = symlist.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; + mips = kern/generic/rtc_get_time_ms.c; ieee1275 = disk/ieee1275/ofdisk.c; ieee1275 = kern/ieee1275/cmain.c; ieee1275 = kern/ieee1275/ieee1275.c; ieee1275 = kern/ieee1275/mmap.c; ieee1275 = kern/ieee1275/openfw.c; - ieee1275 = term/ieee1275/ofconsole.c; + ieee1275 = term/ieee1275/console.c; + ieee1275 = kern/ieee1275/init.c; terminfoinkernel = term/terminfo.c; terminfoinkernel = term/tparm.c; @@ -107,18 +131,24 @@ kernel = { x86 = kern/i386/pit.c; - x86_efi = disk/efi/efidisk.c; - x86_efi = kern/efi/efi.c; - x86_efi = kern/efi/init.c; - x86_efi = kern/efi/mm.c; - x86_efi = kern/i386/efi/init.c; - x86_efi = term/efi/console.c; + efi = disk/efi/efidisk.c; + efi = kern/efi/efi.c; + efi = kern/efi/init.c; + efi = kern/efi/mm.c; + efi = term/efi/console.c; i386_efi = kern/i386/tsc.c; + i386_efi = kern/i386/efi/init.c; x86_64_efi = kern/i386/tsc.c; x86_64_efi = kern/x86_64/dl.c; x86_64_efi = kern/x86_64/efi/callwrap.S; + x86_64_efi = kern/i386/efi/init.c; + + ia64_efi = kern/ia64/efi/startup.S; + ia64_efi = kern/ia64/efi/init.c; + ia64_efi = kern/ia64/dl.c; + ia64_efi = kern/ia64/dl_helper.c; i386_pc = kern/i386/pc/init.c; i386_pc = kern/i386/pc/mmap.c; @@ -126,7 +156,7 @@ kernel = { i386_pc = term/i386/pc/console.c; i386_qemu = bus/pci.c; - i386_qemu = kern/i386/qemu/init.c; + i386_qemu = kern/vga_init.c; i386_qemu = kern/i386/qemu/mmap.c; i386_qemu = kern/i386/tsc.c; @@ -136,42 +166,55 @@ kernel = { i386_multiboot = kern/i386/multiboot_mmap.c; i386_multiboot = kern/i386/tsc.c; - i386_ieee1275 = kern/ieee1275/init.c; + mips = kern/mips/cache.S; + mips = kern/mips/dl.c; + mips = kern/mips/init.c; - mips_yeeloong = term/ns8250.c; - mips_yeeloong = bus/bonito.c; - mips_yeeloong = bus/cs5536.c; - mips_yeeloong = bus/pci.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 = term/at_keyboard.c; - mips_yeeloong = term/serial.c; - mips_yeeloong = video/sm712.c; + mips_qemu_mips = kern/mips/qemu_mips/init.c; + mips_qemu_mips = term/ns8250.c; + mips_qemu_mips = term/serial.c; + mips_qemu_mips = term/at_keyboard.c; + mips_qemu_mips = commands/keylayouts.c; + mips_qemu_mips = term/i386/pc/vga_text.c; + mips_qemu_mips = term/i386/vga_common.c; + mips_qemu_mips = kern/vga_init.c; + + mips_arc = kern/mips/arc/init.c; + mips_arc = term/arc/console.c; + mips_arc = disk/arc/arcdisk.c; + + mips_loongson = term/ns8250.c; + mips_loongson = bus/bonito.c; + mips_loongson = bus/cs5536.c; + mips_loongson = bus/pci.c; + mips_loongson = kern/mips/loongson/init.c; + mips_loongson = term/at_keyboard.c; + mips_loongson = term/serial.c; + mips_loongson = video/sm712.c; + mips_loongson = video/sis315pro.c; + mips_loongson = video/radeon_fuloong2e.c; extra_dist = video/sm712_init.c; - mips_yeeloong = commands/keylayouts.c; + mips_loongson = commands/keylayouts.c; - powerpc_ieee1275 = kern/ieee1275/init.c; powerpc_ieee1275 = kern/powerpc/cache.S; powerpc_ieee1275 = kern/powerpc/dl.c; sparc64_ieee1275 = kern/sparc64/cache.S; sparc64_ieee1275 = kern/sparc64/dl.c; sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c; - sparc64_ieee1275 = kern/sparc64/ieee1275/init.c; emu = disk/host.c; emu = gnulib/progname.c; emu = gnulib/error.c; + emu = kern/emu/cache_s.S; emu = kern/emu/console.c; - emu = kern/emu/getroot.c; emu = kern/emu/hostdisk.c; emu = kern/emu/hostfs.c; emu = kern/emu/main.c; emu = kern/emu/misc.c; emu = kern/emu/mm.c; emu = kern/emu/time.c; + emu = kern/emu/cache.c; videoinkernel = term/gfxterm.c; videoinkernel = font/font.c; @@ -179,6 +222,7 @@ kernel = { videoinkernel = io/bufio.c; videoinkernel = video/bitmap.c; videoinkernel = video/bitmap_scale.c; + videoinkernel = video/colors.c; videoinkernel = video/fb/fbblit.c; videoinkernel = video/fb/fbfill.c; videoinkernel = video/fb/fbutil.c; @@ -187,6 +231,7 @@ kernel = { videoinkernel = commands/boot.c; + extra_dist = kern/i386/int.S; extra_dist = kern/i386/realmode.S; extra_dist = kern/i386/pc/lzma_decode.S; extra_dist = kern/mips/cache_flush.S; @@ -201,7 +246,7 @@ program = { ldadd = 'kernel.img$(EXEEXT)'; ldadd = '$(MODULE_FILES)'; - ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; enable = emu; }; @@ -210,11 +255,10 @@ program = { name = grub-emu-lite; emu = kern/emu/lite.c; - emu = kern/emu/cache.S; emu_nodist = symlist.c; ldadd = 'kernel.img$(EXEEXT)'; - ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; + ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; enable = emu; }; @@ -297,12 +341,13 @@ image = { common = lib/xzembed/xz_dec_lzma2.c; common = lib/xzembed/xz_dec_stream.c; - cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed'; - - mips_cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -DGRUB_EMBED_DECOMPRESSOR=1'; objcopyflags = '-O binary'; - ldflags = '-lgcc -static-libgcc -Wl,-Ttext,0x80100000'; + mips_loongson_ldflags = '-static-libgcc -Wl,-Ttext,0x80100000'; + mips_qemu_mips_ldflags = '-static-libgcc -Wl,-Ttext,0x80100000'; + mips_arc_ldflags = '-static-libgcc -Wl,-Ttext,0x8bc00000'; + ldadd = '-lgcc'; cflags = '-static-libgcc'; enable = mips; }; @@ -312,19 +357,40 @@ image = { mips = boot/mips/startup_raw.S; common = boot/decompressor/none.c; - mips_cppflags = '-DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000'; + cppflags = '-DGRUB_EMBED_DECOMPRESSOR=1'; objcopyflags = '-O binary'; - ldflags = '-lgcc -static-libgcc -Wl,-Ttext,0x80100000'; + mips_loongson_ldflags = '-static-libgcc -Wl,-Ttext,0x80100000'; + mips_qemu_mips_ldflags = '-static-libgcc -Wl,-Ttext,0x80100000'; + mips_arc_ldflags = '-static-libgcc -Wl,-Ttext,0x8bc00000'; + ldadd = '-lgcc'; cflags = '-static-libgcc'; enable = mips; }; image = { - name = fwstart; - mips_yeeloong = boot/mips/yeeloong/fwstart.S; + name = lzma_decompress; + i386_pc = boot/i386/pc/startup_raw.S; + objcopyflags = '-O binary'; - enable = mips_yeeloong; + ldflags = '$(TARGET_IMG_LDFLAGS) -Wl,-Ttext,0x8200'; + enable = i386_pc; +}; + +image = { + name = fwstart; + mips_loongson = boot/mips/loongson/fwstart.S; + objcopyflags = '-O binary'; + ldflags = '-static-libgcc -lgcc -Wl,-N,-S,-Ttext,0xbfc00000,-Bstatic'; + enable = mips_loongson; +}; + +image = { + name = fwstart_fuloong2f; + mips_loongson = boot/mips/loongson/fuloong2f.S; + objcopyflags = '-O binary'; + ldflags = '-static-libgcc -lgcc -Wl,-N,-S,-Ttext,0xbfc00000,-Bstatic'; + enable = mips_loongson; }; module = { @@ -348,18 +414,22 @@ module = { module = { name = lsspd; - mips_yeeloong = commands/mips/yeeloong/lsspd.c; - enable = mips_yeeloong; + mips_loongson = commands/mips/loongson/lsspd.c; + enable = mips_loongson; }; module = { name = usb; common = bus/usb/usb.c; - noemu = bus/usb/usbtrans.c; - noemu = bus/usb/usbhub.c; - enable = emu; + common = bus/usb/usbtrans.c; + common = bus/usb/usbhub.c; enable = usb; - emu_condition = COND_GRUB_EMU_USB; +}; + +module = { + name = emuusb; + common = bus/usb/usb.c; + condition = COND_GRUB_EMU_USB; }; module = { @@ -393,18 +463,36 @@ module = { }; module = { - name = pci; - noemu = bus/pci.c; - emu = bus/emu/pci.c; - emu = commands/lspci.c; + name = ehci; + common = bus/usb/ehci.c; + enable = pci; +}; + +module = { + name = pci; + common = bus/pci.c; - enable = emu; enable = i386_pc; - enable = x86_efi; + enable = i386_efi; + enable = x86_64_efi; enable = i386_ieee1275; enable = i386_coreboot; enable = i386_multiboot; - emu_condition = COND_GRUB_EMU_PCI; +}; + +module = { + name = emupci; + common = bus/emu/pci.c; + common = commands/lspci.c; + + condition = COND_GRUB_EMU_PCI; +}; + +module = { + name = lsdev; + common = commands/arc/lsdev.c; + + enable = mips_arc; }; library = { @@ -439,12 +527,12 @@ module = { name = acpi; common = commands/acpi.c; - x86_efi = commands/efi/acpi.c; + 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 = efi; enable = i386_pc; enable = i386_coreboot; enable = i386_multiboot; @@ -455,7 +543,7 @@ module = { common = commands/lsacpi.c; - enable = x86_efi; + enable = efi; enable = i386_pc; enable = i386_coreboot; enable = i386_multiboot; @@ -466,7 +554,7 @@ module = { common = commands/efi/lsefisystab.c; - enable = x86_efi; + enable = efi; }; module = { @@ -474,7 +562,7 @@ module = { common = commands/efi/lssal.c; - enable = x86_efi; + enable = efi; }; module = { @@ -482,7 +570,7 @@ module = { common = commands/efi/lsefimmap.c; - enable = x86_efi; + enable = efi; }; module = { @@ -545,8 +633,9 @@ module = { module = { name = fixvideo; - x86_efi = commands/efi/fixvideo.c; - enable = x86_efi; + common = commands/efi/fixvideo.c; + enable = i386_efi; + enable = x86_64_efi; }; module = { @@ -561,15 +650,30 @@ module = { i386_pc = commands/acpihalt.c; i386_coreboot = commands/acpihalt.c; i386_multiboot = commands/acpihalt.c; - x86_efi = commands/acpihalt.c; + i386_efi = commands/acpihalt.c; + x86_64_efi = commands/acpihalt.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; + efi = lib/efi/halt.c; ieee1275 = lib/ieee1275/halt.c; emu = lib/emu/halt.c; }; +module = { + name = reboot; + i386 = lib/i386/reboot.c; + i386 = lib/i386/reboot_trampoline.S; + ia64_efi = lib/efi/reboot.c; + x86_64_efi = lib/efi/reboot.c; + powerpc_ieee1275 = lib/ieee1275/reboot.c; + sparc64_ieee1275 = lib/ieee1275/reboot.c; + mips_arc = lib/mips/arc/reboot.c; + mips_loongson = lib/mips/loongson/reboot.c; + mips_qemu_mips = lib/mips/qemu_mips/reboot.c; + common = commands/reboot.c; +}; + module = { name = hashsum; common = commands/hashsum.c; @@ -580,6 +684,7 @@ module = { common = commands/hdparm.c; common = lib/hexdump.c; enable = pci; + enable = mips_qemu_mips; }; module = { @@ -600,8 +705,9 @@ module = { module = { name = loadbios; - x86_efi = commands/efi/loadbios.c; - enable = x86_efi; + common = commands/efi/loadbios.c; + enable = i386_efi; + enable = x86_64_efi; }; module = { @@ -663,22 +769,11 @@ module = { common = commands/probe.c; }; -module = { - name = pxecmd; - i386_pc = commands/i386/pc/pxecmd.c; - enable = i386_pc; -}; - module = { name = read; common = commands/read.c; }; -module = { - name = reboot; - common = commands/reboot.c; -}; - module = { name = search; common = commands/search_wrap.c; @@ -703,7 +798,7 @@ module = { module = { name = setpci; common = commands/setpci.c; - enable = x86; + enable = pci; }; module = { @@ -737,8 +832,6 @@ module = { name = usbtest; common = commands/usbtest.c; enable = usb; - enable = emu; - emu_condition = COND_GRUB_EMU_USB; }; module = { @@ -766,11 +859,32 @@ module = { common = disk/loopback.c; }; +module = { + name = cryptodisk; + common = disk/cryptodisk.c; +}; + +module = { + name = luks; + common = disk/luks.c; + common = disk/AFSplitter.c; +}; + +module = { + name = geli; + common = disk/geli.c; +}; + module = { name = lvm; common = disk/lvm.c; }; +module = { + name = ldm; + common = disk/ldm.c; +}; + module = { name = mdraid09; common = disk/mdraid_linux.c; @@ -782,8 +896,8 @@ module = { }; module = { - name = raid; - common = disk/raid.c; + name = diskfilter; + common = disk/diskfilter.c; }; module = { @@ -810,14 +924,22 @@ module = { name = ata; common = disk/ata.c; enable = pci; + enable = mips_qemu_mips; }; module = { - name = ata_pthru; - common = disk/ata_pthru.c; + name = ahci; + common = disk/ahci.c; enable = pci; }; +module = { + name = pata; + common = disk/pata.c; + enable = pci; + enable = mips_qemu_mips; +}; + module = { name = biosdisk; i386_pc = disk/i386/pc/biosdisk.c; @@ -828,8 +950,6 @@ module = { name = usbms; common = disk/usbms.c; enable = usb; - enable = emu; - emu_condition = COND_GRUB_EMU_USB; }; module = { @@ -888,23 +1008,16 @@ module = { }; module = { - name = afs_be; - common = fs/afs_be.c; -}; - -module = { - name = befs; - common = fs/befs.c; -}; - -module = { - name = befs_be; - common = fs/befs_be.c; + name = bfs; + common = fs/bfs.c; }; module = { name = btrfs; common = fs/btrfs.c; + common = lib/crc.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; }; module = { @@ -912,6 +1025,21 @@ module = { common = fs/cpio.c; }; +module = { + name = cpio_be; + common = fs/cpio_be.c; +}; + +module = { + name = newc; + common = fs/newc.c; +}; + +module = { + name = odc; + common = fs/odc.c; +}; + module = { name = ext2; common = fs/ext2.c; @@ -922,6 +1050,11 @@ module = { common = fs/fat.c; }; +module = { + name = exfat; + common = fs/exfat.c; +}; + module = { name = fshelp; common = fs/fshelp.c; @@ -957,6 +1090,11 @@ module = { common = fs/minix2.c; }; +module = { + name = minix3; + common = fs/minix3.c; +}; + module = { name = nilfs2; common = fs/nilfs2.c; @@ -977,11 +1115,23 @@ module = { common = fs/reiserfs.c; }; +module = { + name = romfs; + common = fs/romfs.c; +}; + module = { name = sfs; common = fs/sfs.c; }; +module = { + name = squash4; + common = fs/squash4.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; +}; + module = { name = tar; common = fs/tar.c; @@ -1007,9 +1157,27 @@ module = { common = fs/xfs.c; }; +module = { + name = zfs; + common = fs/zfs/zfs.c; + common = fs/zfs/zfs_lzjb.c; + common = fs/zfs/zfs_sha256.c; + common = fs/zfs/zfs_fletcher.c; +}; + +module = { + name = zfscrypt; + common = fs/zfs/zfscrypt.c; +}; + +module = { + name = zfsinfo; + common = fs/zfs/zfsinfo.c; +}; + module = { name = pxe; - i386_pc = fs/i386/pc/pxe.c; + i386_pc = net/drivers/i386/pc/pxe.c; enable = i386_pc; }; @@ -1036,7 +1204,6 @@ module = { common = gfxmenu/gui_progress_bar.c; common = gfxmenu/gui_util.c; common = gfxmenu/gui_string_util.c; - common = gfxmenu/named_colors.c; }; module = { @@ -1082,7 +1249,7 @@ module = { x86_64 = lib/x86_64/relocator_asm.S; x86 = lib/i386/relocator.c; ieee1275 = lib/ieee1275/relocator.c; - x86_efi = lib/efi/relocator.c; + efi = lib/efi/relocator.c; mips = lib/mips/relocator_asm.S; mips = lib/mips/relocator.c; powerpc = lib/powerpc/relocator_asm.S; @@ -1099,9 +1266,13 @@ module = { module = { name = datetime; cmos = lib/cmos_datetime.c; - x86_efi = lib/efi/datetime.c; + efi = lib/efi/datetime.c; sparc64_ieee1275 = lib/ieee1275/datetime.c; powerpc_ieee1275 = lib/ieee1275/datetime.c; + sparc64_ieee1275 = lib/ieee1275/cmos.c; + powerpc_ieee1275 = lib/ieee1275/cmos.c; + + mips_arc = lib/arc/datetime.c; enable = noemu; }; @@ -1113,6 +1284,7 @@ module = { extra_dist = lib/x86_64/setjmp.S; extra_dist = lib/sparc64/setjmp.S; extra_dist = lib/powerpc/setjmp.S; + extra_dist = lib/ia64/setjmp.S; }; module = { @@ -1133,9 +1305,17 @@ module = { enable = x86; }; +module = { + name = plan9; + i386_pc = loader/i386/pc/plan9.c; + enable = i386_pc; +}; + + module = { name = linux16; i386_pc = loader/i386/pc/linux.c; + i386_pc = lib/cmdline.c; enable = i386_pc; }; @@ -1145,6 +1325,12 @@ module = { enable = i386_pc; }; +module = { + name = freedos; + i386_pc = loader/i386/pc/freedos.c; + enable = i386_pc; +}; + module = { name = multiboot2; cppflags = "-DGRUB_USE_MULTIBOOT2"; @@ -1170,6 +1356,8 @@ module = { mips = loader/mips/linux.c; powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; + ia64_efi = loader/ia64/efi/linux.c; + common = lib/cmdline.c; enable = noemu; }; @@ -1188,16 +1376,19 @@ module = { module = { name = appleldr; - x86_efi = loader/efi/appleloader.c; - enable = x86_efi; + common = loader/efi/appleloader.c; + enable = i386_efi; + enable = x86_64_efi; }; module = { name = chain; - x86_efi = loader/efi/chainloader.c; + efi = loader/efi/chainloader.c; i386_pc = loader/i386/pc/chainloader.c; + i386_coreboot = loader/i386/coreboot/chainloader.c; enable = i386_pc; - enable = x86_efi; + enable = i386_coreboot; + enable = efi; }; module = { @@ -1209,12 +1400,13 @@ module = { i386_pc = mmap/i386/pc/mmap.c; i386_pc = mmap/i386/pc/mmap_helper.S; - x86_efi = mmap/efi/mmap.c; + efi = mmap/efi/mmap.c; - mips_yeeloong = mmap/mips/yeeloong/uppermem.c; + mips = mmap/mips/uppermem.c; enable = x86; - enable = mips_yeeloong; + enable = ia64_efi; + enable = mips; }; module = { @@ -1254,7 +1446,7 @@ module = { extra_dist = script/yylex.l; extra_dist = script/parser.y; - cflags = '$(CFLAGS_POSIX) -Wno-error'; + cflags = '$(CFLAGS_POSIX)'; cppflags = '$(CPPFLAGS_POSIX)'; }; @@ -1288,6 +1480,16 @@ module = { common = partmap/sun.c; }; +module = { + name = part_plan; + common = partmap/plan.c; +}; + +module = { + name = part_dvh; + common = partmap/dvh.c; +}; + module = { name = part_bsd; common = partmap/bsdlabel.c; @@ -1320,10 +1522,7 @@ module = { common = term/serial.c; x86 = term/ns8250.c; - enable = emu; - enable = i386; - enable = x86_64_efi; - emu_condition = COND_GRUB_EMU_USB; + enable = x86; }; module = { @@ -1347,8 +1546,10 @@ module = { module = { name = vga; - i386_pc = video/i386/pc/vga.c; + common = video/i386/pc/vga.c; enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; }; module = { @@ -1398,14 +1599,15 @@ module = { module = { name = efi_gop; - x86_efi = video/efi_gop.c; - enable = x86_efi; + efi = video/efi_gop.c; + enable = efi; }; module = { name = efi_uga; - x86_efi = video/efi_uga.c; - enable = x86_efi; + efi = video/efi_uga.c; + enable = i386_efi; + enable = x86_64_efi; }; module = { @@ -1425,8 +1627,10 @@ module = { module = { name = vbe; - i386_pc = video/i386/pc/vbe.c; + common = video/i386/pc/vbe.c; enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; }; module = { @@ -1441,14 +1645,14 @@ module = { module = { name = video; common = video/video.c; + common = video/colors.c; enable = videomodules; }; module = { name = ieee1275_fb; ieee1275 = video/ieee1275.c; - enable = powerpc; - enable = sparc64; + enable = powerpc_ieee1275; }; module = { @@ -1463,6 +1667,49 @@ module = { common = hook/datehook.c; }; +module = { + name = net; + common = net/net.c; + common = net/dns.c; + common = net/bootp.c; + common = net/ip.c; + common = net/udp.c; + common = net/tcp.c; + common = net/icmp.c; + common = net/icmp6.c; + common = net/ethernet.c; + common = net/arp.c; + common = net/netbuff.c; +}; + +module = { + name = tftp; + common = net/tftp.c; +}; + +module = { + name = http; + common = net/http.c; +}; + +module = { + name = ofnet; + common = net/drivers/ieee1275/ofnet.c; + enable = ieee1275; +}; + +module = { + name = efinet; + common = net/drivers/efi/efinet.c; + enable = efi; +}; + +module = { + name = emunet; + emu = net/drivers/emu/emunet.c; + enable = emu; +}; + module = { name = legacycfg; common = commands/legacycfg.c; @@ -1486,6 +1733,14 @@ module = { cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed'; }; +module = { + name = lzopio; + common = io/lzopio.c; + common = lib/minilzo/minilzo.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; +}; + module = { name = testload; common = commands/testload.c; @@ -1502,3 +1757,29 @@ module = { common = commands/keylayouts.c; enable = videomodules; }; + +module = { + name = priority_queue; + common = lib/priority_queue.c; +}; + +module = { + name = time; + common = commands/time.c; +}; + +module = { + name = cacheinfo; + common = commands/cacheinfo.c; + condition = COND_ENABLE_CACHE_STATS; +}; + +module = { + name = adler32; + common = lib/adler32.c; +}; + +module = { + name = crc64; + common = lib/crc64.c; +}; diff --git a/grub-core/boot/decompressor/none.c b/grub-core/boot/decompressor/none.c index 44f56ce90..911e861e3 100644 --- a/grub-core/boot/decompressor/none.c +++ b/grub-core/boot/decompressor/none.c @@ -25,6 +25,9 @@ grub_decompress_core (void *src, void *dest, unsigned long n, char *d = (char *) dest; const char *s = (const char *) src; + if (d == s) + return; + if (d < s) while (n--) *d++ = *s++; diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S index 320918566..314f14016 100644 --- a/grub-core/boot/i386/pc/boot.S +++ b/grub-core/boot/i386/pc/boot.S @@ -18,7 +18,6 @@ */ #include -#include #include /* @@ -459,6 +458,8 @@ fd_probe_error_string: .asciz "Floppy" 1: /* perform read */ movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + movw %bx, %es + xorw %bx, %bx movw $0x201, %ax movb $0, %ch movb $0, %dh diff --git a/grub-core/boot/i386/pc/cdboot.S b/grub-core/boot/i386/pc/cdboot.S index 33569ce9d..d939835a9 100644 --- a/grub-core/boot/i386/pc/cdboot.S +++ b/grub-core/boot/i386/pc/cdboot.S @@ -18,7 +18,6 @@ */ #include -#include #include #include #include diff --git a/grub-core/boot/i386/pc/lnxboot.S b/grub-core/boot/i386/pc/lnxboot.S index 9a599c261..e4bc8b425 100644 --- a/grub-core/boot/i386/pc/lnxboot.S +++ b/grub-core/boot/i386/pc/lnxboot.S @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -178,15 +177,21 @@ real_code_2: pushw %es popw %ds - movl $0x200, %ecx - addl %ecx, %esi + movl $0x1000, %ecx + addl $0x200, %esi movl $DATA_ADDR, %edi call LOCAL(move_memory) /* Check for multiboot signature. */ - cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART) + movl $DATA_ADDR, %edi +3: + movl %ss:(%edi), %eax + cmpl $MULTIBOOT_HEADER_MAGIC, %eax jz 1f + addl $4, %edi + cmpl $(DATA_ADDR + 0x1000), %edi + jne 3b movl (ramdisk_image - start), %esi movl (ramdisk_size - start), %ecx @@ -195,17 +200,13 @@ real_code_2: 1: - movl %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE), %ecx - addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - 0x200), %ecx + movl $(DATA_ADDR + 0x1000), %edi + movl %ss:(DATA_ADDR + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE), %ecx + addl $GRUB_DECOMPRESSOR_I386_PC_MAX_DECOMPRESSOR_SIZE, %ecx 2: call LOCAL(move_memory) - movsbl %dh, %eax - movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART) - movsbl (reg_edx + 2 - start), %eax - movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART) - movb $0xFF, %dh ljmp $(DATA_ADDR >> 4), $0 diff --git a/grub-core/kern/i386/pc/lzma_decode.S b/grub-core/boot/i386/pc/lzma_decode.S similarity index 100% rename from grub-core/kern/i386/pc/lzma_decode.S rename to grub-core/boot/i386/pc/lzma_decode.S diff --git a/grub-core/boot/i386/pc/startup_raw.S b/grub-core/boot/i386/pc/startup_raw.S new file mode 100644 index 000000000..fdd408702 --- /dev/null +++ b/grub-core/boot/i386/pc/startup_raw.S @@ -0,0 +1,354 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009,2011 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 ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) + + .file "startup_raw.S" + + .text + + /* Tell GAS to generate 16-bit instructions so that this code works + in real mode. */ + .code16 + + .globl start, _start +start: +_start: +LOCAL (base): + /* + * Guarantee that "main" is loaded at 0x0:0x8200. + */ +#ifdef __APPLE__ + ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000) +#else + ljmp $0, $ABS(LOCAL (codestart)) +#endif + + /* + * This is a special data area. + */ + + . = _start + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE +LOCAL(compressed_size): + .long 0 + . = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE +LOCAL(uncompressed_size): + .long 0 + + . = _start + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY +reed_solomon_redundancy: + .long 0 + . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH + .short (LOCAL(reed_solomon_part) - _start) + +/* + * This is the area for all of the special variables. + */ + . = _start + GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE +LOCAL(boot_dev): + .byte 0xFF, 0xFF, 0xFF +LOCAL(boot_drive): + .byte 0x00 + +/* the real mode code continues... */ +LOCAL (codestart): + cli /* we're not safe here! */ + + /* set up %ds, %ss, and %es */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* set up the real mode/BIOS stack */ + movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp + movl %ebp, %esp + + sti /* we're safe again */ + + /* save the boot drive */ + ADDR32 movb %dl, LOCAL(boot_drive) + + /* reset disk system (%ah = 0) */ + int $0x13 + + /* transition to protected mode */ + DATA32 call real_to_prot + + /* The ".code32" directive takes GAS out of 16-bit mode. */ + .code32 + + incl %eax + cld + call grub_gate_a20 + + movl LOCAL(compressed_size), %edx + addl $(LOCAL(decompressor_end) - LOCAL(reed_solomon_part)), %edx + movl reed_solomon_redundancy, %ecx + leal LOCAL(reed_solomon_part), %eax + cld + call EXT_C (grub_reed_solomon_recover) + jmp post_reed_solomon + +#include "../../../kern/i386/realmode.S" + +#include + + .text + +/* + * grub_gate_a20(int on) + * + * Gate address-line 20 for high memory. + * + * This routine is probably overconservative in what it does, but so what? + * + * It also eats any keystrokes in the keyboard buffer. :-( + */ + +grub_gate_a20: + movl %eax, %edx + +gate_a20_test_current_state: + /* first of all, test if already in a good state */ + call gate_a20_check_state + cmpb %al, %dl + jnz gate_a20_try_bios + ret + +gate_a20_try_bios: + /* second, try a BIOS call */ + pushl %ebp + call prot_to_real + + .code16 + movw $0x2400, %ax + testb %dl, %dl + jz 1f + incw %ax +1: int $0x15 + + DATA32 call real_to_prot + .code32 + + popl %ebp + call gate_a20_check_state + cmpb %al, %dl + jnz gate_a20_try_system_control_port_a + ret + +gate_a20_try_system_control_port_a: + /* + * In macbook, the keyboard test would hang the machine, so we move + * this forward. + */ + /* fourth, try the system control port A */ + inb $0x92 + andb $(~0x03), %al + testb %dl, %dl + jz 6f + orb $0x02, %al +6: outb $0x92 + + /* When turning off Gate A20, do not check the state strictly, + because a failure is not fatal usually, and Gate A20 is always + on some modern machines. */ + testb %dl, %dl + jz 7f + call gate_a20_check_state + cmpb %al, %dl + jnz gate_a20_try_keyboard_controller +7: ret + +gate_a20_flush_keyboard_buffer: + inb $0x64 + andb $0x02, %al + jnz gate_a20_flush_keyboard_buffer +2: + inb $0x64 + andb $0x01, %al + jz 3f + inb $0x60 + jmp 2b +3: + ret + +gate_a20_try_keyboard_controller: + /* third, try the keyboard controller */ + call gate_a20_flush_keyboard_buffer + + movb $0xd1, %al + outb $0x64 +4: + inb $0x64 + andb $0x02, %al + jnz 4b + + movb $0xdd, %al + testb %dl, %dl + jz 5f + orb $0x02, %al +5: outb $0x60 + call gate_a20_flush_keyboard_buffer + + /* output a dummy command (USB keyboard hack) */ + movb $0xff, %al + outb $0x64 + call gate_a20_flush_keyboard_buffer + + call gate_a20_check_state + cmpb %al, %dl + /* everything failed, so restart from the beginning */ + jnz gate_a20_try_bios + ret + +gate_a20_check_state: + /* iterate the checking for a while */ + movl $100, %ecx +1: + call 3f + cmpb %al, %dl + jz 2f + loop 1b +2: + ret +3: + pushl %ebx + pushl %ecx + xorl %eax, %eax + /* compare the byte at 0x8000 with that at 0x108000 */ + movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx + pushl %ebx + /* save the original byte in CL */ + movb (%ebx), %cl + /* store the value at 0x108000 in AL */ + addl $0x100000, %ebx + movb (%ebx), %al + /* try to set one less value at 0x8000 */ + popl %ebx + movb %al, %ch + decb %ch + movb %ch, (%ebx) + /* serialize */ + outb %al, $0x80 + outb %al, $0x80 + /* obtain the value at 0x108000 in CH */ + pushl %ebx + addl $0x100000, %ebx + movb (%ebx), %ch + /* this result is 1 if A20 is on or 0 if it is off */ + subb %ch, %al + xorb $1, %al + /* restore the original */ + popl %ebx + movb %cl, (%ebx) + popl %ecx + popl %ebx + ret + +LOCAL(reed_solomon_part): + +/* + * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). + * This uses the a.out kludge to load raw binary to the area starting at 1MB, + * and relocates itself after loaded. + */ + .p2align 2 /* force 4-byte alignment */ +multiboot_header: + /* magic */ + .long 0x1BADB002 + /* flags */ + .long (1 << 16) + /* checksum */ + .long -0x1BADB002 - (1 << 16) + /* header addr */ + .long multiboot_header - _start + 0x100000 + 0x200 + /* load addr */ + .long 0x100000 + /* load end addr */ + .long 0 + /* bss end addr */ + .long 0 + /* entry addr */ + .long multiboot_entry - _start + 0x100000 + 0x200 + +multiboot_entry: + .code32 + /* obtain the boot device */ + movl 12(%ebx), %edx + + movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp + movl %ebp, %esp + + /* relocate the code */ + movl $(LOCAL(decompressor_end) + 0x200), %ecx + addl LOCAL(compressed_size) - _start + 0x100000 + 0x200, %ecx + movl $0x100000, %esi + movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi + cld + rep + movsb + /* jump to the real address */ + movl $multiboot_trampoline, %eax + jmp *%eax + +multiboot_trampoline: + /* fill the boot information */ + movl %edx, LOCAL(boot_dev) + shrl $24, %edx + /* enter the usual booting */ + call prot_to_real + .code16 + jmp LOCAL (codestart) + .code32 + +post_reed_solomon: + +#ifdef ENABLE_LZMA + movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi + movl $LOCAL(decompressor_end), %esi + pushl %edi + movl LOCAL (uncompressed_size), %ecx + leal (%edi, %ecx), %ebx + /* Don't remove this push: it's an argument. */ + push %ecx + call _LzmaDecodeA + pop %ecx + /* _LzmaDecodeA clears DF, so no need to run cld */ + popl %esi +#endif + + movl LOCAL(boot_dev), %edx + movl $prot_to_real, %edi + movl $real_to_prot, %ecx + jmp *%esi + +#ifdef ENABLE_LZMA +#include "lzma_decode.S" +#endif + + .p2align 4 + +LOCAL(decompressor_end): diff --git a/grub-core/boot/mips/loongson/fuloong2f.S b/grub-core/boot/mips/loongson/fuloong2f.S new file mode 100644 index 000000000..a88c81efe --- /dev/null +++ b/grub-core/boot/mips/loongson/fuloong2f.S @@ -0,0 +1,2 @@ +#define FULOONG2F 1 +#include "fwstart.S" diff --git a/grub-core/boot/mips/yeeloong/fwstart.S b/grub-core/boot/mips/loongson/fwstart.S similarity index 80% rename from grub-core/boot/mips/yeeloong/fwstart.S rename to grub-core/boot/mips/loongson/fwstart.S index 425458401..7ed5d30ae 100644 --- a/grub-core/boot/mips/yeeloong/fwstart.S +++ b/grub-core/boot/mips/loongson/fwstart.S @@ -16,51 +16,73 @@ * along with GRUB. If not, see . */ -#include -#include +#include +#include #include #include #include +#include #include #include #include +#ifdef FULOONG2F +#define GRUB_MACHINE_SERIAL_PORT GRUB_MACHINE_SERIAL_PORT2 +#define GRUB_MACHINE_SERIAL_DIVISOR_115200 GRUB_MACHINE_SERIAL_PORT2_DIVISOR_115200 +#else +#define GRUB_MACHINE_SERIAL_PORT GRUB_MACHINE_SERIAL_PORT0 +#define GRUB_MACHINE_SERIAL_DIVISOR_115200 GRUB_MACHINE_SERIAL_PORT0_DIVISOR_115200 +#endif + .set noreorder .set noat .set nomacro + .set mips3 .global start,_start,__start start: _start: __start: + /* Put serial init as soon as possible. But on Fuloong2f serial is past + Geode, so on Fuloong2f we need Geode first. + */ +#ifndef FULOONG2F bal serial_hw_init nop +#endif + /* Find CS5536 controller. */ /* $t4 chooses device in priority encoding. */ /* Resulting value is kept in GRUB_MACHINE_PCI_CONF_CTRL_REG. This way we don't need to sacrifice a register for it. */ +retry_cs5536: /* We have only one bus (0). Function is 0. */ lui $t0, %hi(GRUB_MACHINE_PCI_CONF_CTRL_REG_ADDR) lui $t1, %hi(GRUB_MACHINE_PCI_CONFSPACE) lui $t3, %hi(GRUB_CS5536_PCIID) addiu $t3, $t3, %lo(GRUB_CS5536_PCIID) ori $t4, $zero, 1 - lui $a0, %hi(no_cs5536) 1: andi $t4, $t4, ((1 << GRUB_PCI_NUM_DEVICES) - 1) - beql $t4, $zero, fatal - addiu $a0, $a0, %lo(no_cs5536) + /* In case of failure try again. CS5536 may be slow to come up. */ + beql $t4, $zero, retry_cs5536 + nop sw $t4, %lo(GRUB_MACHINE_PCI_CONF_CTRL_REG_ADDR) ($t0) lw $t2, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_PCI_REG_PCI_ID) ($t1) bnel $t2, $t3, 1b sll $t4, $t4, 1 +#ifndef FULOONG2F bal message addiu $a0, $a0, %lo(cs5536_found) bal printhex move $a0, $t4 +#endif - /* Initialise SMBus controller. */ + lui $t0, %hi(GRUB_MACHINE_PCI_CONFSPACE) + li $t1, GRUB_CS5536_MSR_MAILBOX_CONFIG_ENABLED + sw $t1, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_CONFIG) ($t0) + /* Set GPIO LBAR. */ lui $a0, %hi(GRUB_CS5536_MSR_GPIO_BAR) addiu $a0, $a0, %lo(GRUB_CS5536_MSR_GPIO_BAR) @@ -70,6 +92,15 @@ __start: ori $a2, $zero, ((GRUB_CS5536_LBAR_MASK_MASK \ | GRUB_CS5536_LBAR_ENABLE) >> 32) + bal gpio_init + nop + +#ifdef FULOONG2F + bal serial_hw_init + nop +#endif + + /* Initialise SMBus controller. */ /* Set SMBUS LBAR. */ lui $a0, %hi(GRUB_CS5536_MSR_SMB_BAR) addiu $a0, $a0, %lo(GRUB_CS5536_MSR_SMB_BAR) @@ -83,14 +114,6 @@ __start: bal message addiu $a0, $a0, %lo(smbus_enabled) - /* Enable SMBus controller pins. */ - lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO) - ori $t1, $zero, GRUB_GPIO_SMBUS_PINS - sw $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_OUT_EN) ($t0) - sw $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_OUT_AUX1) ($t0) - sw $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_IN_EN) ($t0) - sw $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_IN_AUX1) ($t0) - lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS) /* Disable SMB. */ @@ -107,7 +130,7 @@ __start: sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL3) ($t0) sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0) - /* Yeeloong has only one memory slot. */ + /* Yeeloong and Fuloong2f have only one memory slot. */ /* Output first byte on serial for debugging. */ ori $a1, $zero, GRUB_SMB_RAM_START_ADDR bal read_spd @@ -120,7 +143,7 @@ __start: ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2 lui $a0, %hi(unimplemented_memory_type) bne $t0, $v0, fatal - addiu $a0, $a0, %hi(unimplemented_memory_type) + addiu $a0, $a0, %lo(unimplemented_memory_type) /* And here is our goal: DDR2 controller initialisation. */ lui $t0, %hi(GRUB_CPU_LOONGSON_CORECFG) @@ -206,10 +229,54 @@ other_exception: b fatal addiu $a0, $a0, %lo(unhandled_exception) +gpio_init: + lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO) + addiu $t0, $t0, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO) + lui $t1, %hi (gpio_dump) + addiu $t1, $t1, %lo (gpio_dump) + +1: + lw $t2, 0($t1) + sw $t2, 0($t0) + addiu $t0, $t0, 4 + addiu $t1, $t1, 4 + lui $t2, %hi (gpio_dump_end) + addiu $t2, $t2, %lo (gpio_dump_end) + bne $t1, $t2, 1b + nop + jr $ra + nop + /* Same as similarly named C function but in asm since we need it early. */ - /* In: none. Out: none. Clobbered: $t0, $t1, $a0. */ + /* In: none. Out: none. Clobbered: $t0, $t1, $t2, $a0, $a1, $a2. */ serial_hw_init: + move $t2, $ra +#ifdef FULOONG2F + lui $a0, %hi(GRUB_CS5536_MSR_DIVIL_LEG_IO) + addiu $a0, $a0, %lo(GRUB_CS5536_MSR_DIVIL_LEG_IO) + lui $a1, %hi (GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3 \ + | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP \ + | GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86 \ + | GRUB_CS5536_MSR_DIVIL_LEG_IO_UART1_COM1) + ori $a1, $a1, (GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0 \ + | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1) + bal wrmsr + move $a2, $zero + + lui $a0, %hi(GRUB_CS5536_MSR_DIVIL_UART1_CONF) + addiu $a0, $a0, %lo(GRUB_CS5536_MSR_DIVIL_UART1_CONF) + li $a1, 2 + bal wrmsr + move $a2, $zero + + lui $a0, %hi(GRUB_CS5536_MSR_DIVIL_UART2_CONF) + addiu $a0, $a0, %lo(GRUB_CS5536_MSR_DIVIL_UART2_CONF) + li $a1, 2 + bal wrmsr + move $a2, $zero +#endif + lui $t0, %hi (GRUB_MACHINE_SERIAL_PORT) /* Turn off the interrupt. */ @@ -239,6 +306,7 @@ serial_hw_init: /* Let message return to original caller. */ lui $a0, %hi(notification_string) addiu $a0, $a0, %lo(notification_string) + move $ra, $t2 /* Print message on serial console. */ /* In: $a0 = asciiz message. Out: none. Clobbered: $t0, $t1, $a0. */ @@ -379,7 +447,6 @@ read_spd_fail: ori $v0, $v0, 0x100 notification_string: .asciz "GRUB " -no_cs5536: .asciz "No CS5536 found.\n\r" cs5536_found: .asciz "CS5536 at " sm_failed: .asciz "SM transaction failed.\n\r" unhandled_tlb_refill: .asciz "Unhandled TLB refill.\n\r" @@ -404,14 +471,22 @@ regdump: .quad 0x0100020200010101 /* 4 */ .quad 0x0a04030603050203 /* 6 */ .quad 0x0f0e040000010a0b /* 7 */ +#ifdef FULOONG2F + .quad 0x0000000100000001 /* 8 */ +#else .quad 0x0000010200000102 /* 8 */ +#endif .quad 0x0000060c00000000 /* 9 */ .quad 0x2323233f3f1f0200 /* a */ .quad 0x5f7f232323232323 /* b */ .quad 0x002a3c0615000000 /* c */ .quad 0x002a002a002a002a /* d */ .quad 0x002a002a002a002a /* e */ +#ifdef FULOONG2F + .quad 0x00b40020005b0004 /* f */ +#else .quad 0x00b40020006d0004 /* f */ +#endif .quad 0x070007ff00000087 /* 10 */ .quad 0x000000000016101f /* 11 */ .quad 0x001c000000000000 /* 12 */ @@ -426,6 +501,45 @@ regdump: .quad 0 /* 1b */ .quad 0 /* 1c */ +/* Dump of GPIO connections. FIXME: Remove useless and macroify. */ +gpio_dump: +#ifdef FULOONG2F + .long 0xffff0000, 0x2eefd110, 0xffff0000, 0xffff0000 + .long 0x2eefd110, 0xffff0000, 0x1000efff, 0xefff1000 + .long 0x3df3c20c, 0xffff0000, 0xffff0000, 0xffff0000 + .long 0x7df3820c, 0x3df3c20c, 0xffff0000, 0x00000000 + .long 0xffff0000, 0xffff0000, 0x3de3c21c, 0x3d83c27c + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000 + .long 0xffff0000, 0xffff0000, 0x0000ffff, 0xffff0000 + .long 0xefff1000, 0xffff0000, 0xffff0000, 0xffff0000 + .long 0xefff1000, 0xefff1000, 0xffff0000, 0x00000000 + .long 0xffff0000, 0xffff0000, 0xefff1000, 0xefff1000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 +#else + .long 0xffff0000, 0x2ffdd002, 0xffff0000, 0xffff0000 + .long 0x2fffd000, 0xffff0000, 0x1000efff, 0xefff1000 + .long 0x3ffbc004, 0xffff0000, 0xffff0000, 0xffff0000 + .long 0x3ffbc004, 0x3ffbc004, 0xffff0000, 0x00000000 + .long 0xffff0000, 0xffff0000, 0x3ffbc004, 0x3f9bc064 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000 + .long 0xffff0000, 0xffff0000, 0x0000ffff, 0xffff0000 + .long 0xefff1000, 0xffff0000, 0xffff0000, 0xffff0000 + .long 0xefff1000, 0xefff1000, 0xffff0000, 0x00000000 + .long 0xffff0000, 0xffff0000, 0xefff1000, 0xffff0000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x00000000, 0x00000000, 0x00000000 + .long 0x00000000, 0x50000000, 0x00000000, 0x00000000 +#endif +gpio_dump_end: + .p2align write_dumpreg: @@ -626,6 +740,10 @@ continue: lui $t0, %hi(cached_continue - 0x20000000) addiu $t0, $t0, %lo(cached_continue - 0x20000000) jr $t0 - addiu $a2, $zero, -1 +#ifdef FULOONG2F + addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_FULOONG2F) +#else + addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_YEELOONG) +#endif -cached_continue: \ No newline at end of file +cached_continue: diff --git a/grub-core/boot/mips/startup_raw.S b/grub-core/boot/mips/startup_raw.S index c41ce8257..bbbc1dbec 100644 --- a/grub-core/boot/mips/startup_raw.S +++ b/grub-core/boot/mips/startup_raw.S @@ -20,6 +20,7 @@ #include #include #include +#include #include #define BASE_ADDR 8 @@ -37,27 +38,51 @@ start: bal codestart nop base: - . = _start + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE + . = _start + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE compressed_size: .long 0 - . = _start + GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE + . = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE uncompressed_size: .long 0 + . = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR +uncompressed_addr: + .long 0 codestart: /* Save our base. */ move $s0, $ra /* Parse arguments. Has to be done before relocation. So need to do it in asm. */ -#ifdef GRUB_MACHINE_MIPS_YEELOONG +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + lui $t0, %hi (((16 << 20) - 264 + 4) | 0x80000000) + lw $t1, %lo (((16 << 20) - 264 + 4) | 0x80000000) ($t0) + + lui $t2, 0x1234 + ori $t2, 0x5678 + + bne $t1, $t2, 1f + nop + + lui $t0, %hi (((16 << 20) - 264) | 0x80000000) + b 2f + lw $s4, %lo (((16 << 20) - 264) | 0x80000000) ($t0) + +1: + li $s4, 0 +2: +#endif + +#ifdef GRUB_MACHINE_MIPS_LOONGSON move $s2, $zero move $s3, $zero move $s4, $zero move $s5, $zero + move $s7, $zero /* $a2 has the environment. */ - addiu $t0, $a2, 1 - beq $t0, $zero, argdone + addiu $t0, $zero, -0x10 + and $t1, $a2, $t0 + beq $t0, $t1, argfw nop move $t0, $a2 argcont: @@ -72,11 +97,19 @@ argcont: nop ;\ b 2f;\ move reg, $v0; \ -1: +1: +#define DO_CHECKT1(str, val) \ + move $t6, $t1 ;\ + addiu $t7, $s0, (str - base);\ + bal do_check ;\ + li $t2, val + DO_PARSE (busclockstr, $s2) DO_PARSE (cpuclockstr, $s3) DO_PARSE (memsizestr, $s4) DO_PARSE (highmemsizestr, $s5) + DO_CHECKT1 (pmon_yeeloong_verstr, GRUB_ARCH_MACHINE_YEELOONG) + DO_CHECKT1 (pmon_fuloong2f_verstr, GRUB_ARCH_MACHINE_FULOONG2F) 2: b argcont addiu $t0, $t0, 4 @@ -120,8 +153,49 @@ busclockstr: .asciiz "busclock=" cpuclockstr: .asciiz "cpuclock=" memsizestr: .asciiz "memsize=" highmemsizestr: .asciiz "highmemsize=" +machtype_yeeloong_str1: .asciiz "machtype=8.9" +machtype_yeeloong_str2: .asciiz "machtype=lemote-yeeloong-" +machtype_fuloong2f_str: .asciiz "machtype=lemote-fuloong-2f" +machtype_fuloong2e_str: .asciiz "machtype=lemote-fuloong-2e" +pmon_yeeloong_str: .asciiz "PMON_VER=LM8" +pmon_fuloong2f_str: .asciiz "PMON_VER=LM6" +pmon_yeeloong_verstr: .asciiz "Version=LM8" +pmon_fuloong2f_verstr: .asciiz "Version=LM6" .p2align 2 + argdone: + beq $a0, $zero, cmdlinedone + nop +#define DO_CHECKA1(str, val) \ + lw $t6, 0($a1) ;\ + addiu $t7, $s0, (str - base);\ + bal do_check ;\ + li $t2, val + DO_CHECKA1 (machtype_yeeloong_str1, GRUB_ARCH_MACHINE_YEELOONG) + DO_CHECKA1 (machtype_yeeloong_str2, GRUB_ARCH_MACHINE_YEELOONG) + DO_CHECKA1 (pmon_yeeloong_str, GRUB_ARCH_MACHINE_YEELOONG) + DO_CHECKA1 (machtype_fuloong2f_str, GRUB_ARCH_MACHINE_FULOONG2F) + DO_CHECKA1 (machtype_fuloong2e_str, GRUB_ARCH_MACHINE_FULOONG2E) + DO_CHECKA1 (pmon_fuloong2f_str, GRUB_ARCH_MACHINE_FULOONG2F) + addiu $a0, $a0, -1 + b argdone + addiu $a1, $a1, 4 +do_check: + lb $t4, 0($t7) + beq $t4, $zero, 1f + lb $t3, 0($t6) + bne $t3, $t4, 2f + addiu $t6, $t6, 1 + b do_check + addiu $t7, $t7, 1 +1: + move $s7, $t2 +2: + jr $ra + nop +argfw: + not $s7, $a2 +cmdlinedone: #endif /* Copy the decompressor. */ lui $t1, %hi(base) @@ -150,6 +224,13 @@ argdone: b 1b addiu $t1, $t1, 1 2: + lui $a0, %hi(base) + addiu $a0, $a0, %lo(base) + lui $a1, %hi(_end) + addiu $a1, %lo(_end) + subu $a1,$a1,$a0 + +#include "../../kern/mips/cache_flush.S" /* Decompress the payload. */ lui $a0, %hi(__bss_start) @@ -159,10 +240,9 @@ argdone: subu $a0, $a0, $t0 addu $a0, $a0, $s0 - lui $a1, %hi(GRUB_MACHINE_LINK_ADDR) - addiu $a1, %lo(GRUB_MACHINE_LINK_ADDR) - lw $a2, (GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0) - lw $a3, (GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE - BASE_ADDR)($s0) + lw $a1, (GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR - BASE_ADDR)($s0) + lw $a2, (GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0) + lw $a3, (GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE - BASE_ADDR)($s0) move $s1, $a1 /* $a0 contains source compressed address, $a1 is destination, @@ -170,9 +250,11 @@ argdone: */ move $s6, $a3 - lui $sp, %hi(_start - 256) + lui $t0, %hi(EXT_C(grub_decompress_core)) + addiu $t0, $t0, %lo(EXT_C(grub_decompress_core)) - bal EXT_C(grub_decompress_core) + lui $sp, %hi(_start - 256) + jalr $t0 addiu $sp, $sp, %lo(_start - 256) move $a0, $s1 diff --git a/grub-core/boot/sparc64/ieee1275/boot.S b/grub-core/boot/sparc64/ieee1275/boot.S index f08258f47..f79699502 100644 --- a/grub-core/boot/sparc64/ieee1275/boot.S +++ b/grub-core/boot/sparc64/ieee1275/boot.S @@ -17,7 +17,6 @@ * along with GRUB. If not, see . */ -#include #include .text @@ -29,9 +28,6 @@ pic_base: call boot_continue mov %o4, CIF_REG - . = _start + GRUB_BOOT_MACHINE_VER_MAJ -boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR - /* The offsets to these locations are defined by the * GRUB_BOOT_MACHINE_foo macros in include/grub/sparc/ieee1275/boot.h, * and grub-setup uses this to patch these next three values as needed. @@ -44,6 +40,7 @@ boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR * After loading in that block we will execute it by jumping to the * load address plus the size of the prepended A.OUT header (32 bytes). */ + . = _start + GRUB_BOOT_MACHINE_BOOT_DEVPATH boot_path: . = _start + GRUB_BOOT_MACHINE_KERNEL_BYTE boot_path_end: diff --git a/grub-core/boot/sparc64/ieee1275/diskboot.S b/grub-core/boot/sparc64/ieee1275/diskboot.S index 83dfee098..e020f6221 100644 --- a/grub-core/boot/sparc64/ieee1275/diskboot.S +++ b/grub-core/boot/sparc64/ieee1275/diskboot.S @@ -17,7 +17,6 @@ * along with GRUB. If not, see . */ -#include #include #include diff --git a/grub-core/bus/bonito.c b/grub-core/bus/bonito.c index 3f794c45a..c2e0cd6ff 100644 --- a/grub-core/bus/bonito.c +++ b/grub-core/bus/bonito.c @@ -38,7 +38,7 @@ write_bases (void) for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) reg |= (((base_win[i] >> GRUB_MACHINE_PCI_WIN_SHIFT) & GRUB_MACHINE_PCI_WIN_MASK) - >> (i * GRUB_MACHINE_PCI_WIN_MASK_SIZE)); + << (i * GRUB_MACHINE_PCI_WIN_MASK_SIZE)); GRUB_MACHINE_PCI_IO_CTRL_REG = reg; } diff --git a/grub-core/bus/cs5536.c b/grub-core/bus/cs5536.c index 088f4dfc1..9e7796ea1 100644 --- a/grub-core/bus/cs5536.c +++ b/grub-core/bus/cs5536.c @@ -21,6 +21,13 @@ #include #include #include +#ifdef GRUB_MACHINE_MIPS_LOONGSON +#include +#endif + +#include + +GRUB_MOD_LICENSE ("GPLv3+"); int grub_cs5536_find (grub_pci_device_t *devp) @@ -90,8 +97,6 @@ grub_cs5536_smbus_wait (grub_port_t smbbase) if (grub_get_time_ms () > start + 40) return grub_error (GRUB_ERR_IO, "SM stalled"); } - - return GRUB_ERR_NONE; } grub_err_t @@ -213,26 +218,6 @@ grub_cs5536_read_spd (grub_port_t smbbase, grub_uint8_t dev, return GRUB_ERR_NONE; } -/* Dump of GPIO connections. FIXME: Remove useless and macroify. */ -static grub_uint32_t gpiodump[] = { - 0xffff0000, 0x2ffdd002, 0xffff0000, 0xffff0000, - 0x2fffd000, 0xffff0000, 0x1000efff, 0xefff1000, - 0x3ffbc004, 0xffff0000, 0xffff0000, 0xffff0000, - 0x3ffbc004, 0x3ffbc004, 0xffff0000, 0x00000000, - 0xffff0000, 0xffff0000, 0x3ffbc004, 0x3f9bc064, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, - 0xffff0000, 0xffff0000, 0x0000ffff, 0xffff0000, - 0xefff1000, 0xffff0000, 0xffff0000, 0xffff0000, - 0xefff1000, 0xefff1000, 0xffff0000, 0x00000000, - 0xffff0000, 0xffff0000, 0xefff1000, 0xffff0000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x50000000, 0x00000000, 0x00000000, -}; - static inline void set_io_space (grub_pci_device_t dev, int num, grub_uint16_t start, grub_uint16_t len) @@ -273,17 +258,6 @@ set_p2d (grub_pci_device_t dev, int num, int dest, grub_uint32_t start) void grub_cs5536_init_geode (grub_pci_device_t dev) { - int i; - - /* Make sure GPIO is where we expect it to be. */ - grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GPIO_BAR, - GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_GPIO); - - /* Setup GPIO. */ - for (i = 0; i < (int) ARRAY_SIZE (gpiodump); i++) - ((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_IO_BASE - + GRUB_CS5536_LBAR_GPIO)) [i] = gpiodump[i]; - /* Enable more BARs. */ grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IRQ_MAP_BAR, GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_IRQ_MAP); @@ -295,11 +269,27 @@ grub_cs5536_init_geode (grub_pci_device_t dev) GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_PM); /* Setup DIVIL. */ - grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LEG_IO, - GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86 - | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP - | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0 - | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1); +#ifdef GRUB_MACHINE_MIPS_LOONGSON + switch (grub_arch_machine) + { + case GRUB_ARCH_MACHINE_YEELOONG: + grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LEG_IO, + GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86 + | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP + | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0 + | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1); + break; + case GRUB_ARCH_MACHINE_FULOONG2F: + grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LEG_IO, + GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3 + | GRUB_CS5536_MSR_DIVIL_LEG_IO_UART1_COM1 + | GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86 + | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP + | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0 + | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1); + break; + } +#endif grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_PRIMARY_MASK, (~GRUB_CS5536_DIVIL_LPC_INTERRUPTS) & 0xffff); grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_LPC_MASK, diff --git a/grub-core/bus/pci.c b/grub-core/bus/pci.c index bf14a8653..f007ec33a 100644 --- a/grub-core/bus/pci.c +++ b/grub-core/bus/pci.c @@ -20,23 +20,39 @@ #include #include #include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* FIXME: correctly support 64-bit architectures. */ /* #if GRUB_TARGET_SIZEOF_VOID_P == 4 */ struct grub_pci_dma_chunk * grub_memalign_dma32 (grub_size_t align, grub_size_t size) { - return grub_memalign (align, size); + void *ret; + if (align < 64) + align = 64; + size = ALIGN_UP (size, align); + ret = grub_memalign (align, size); + if (!ret) + return 0; + grub_arch_sync_dma_caches (ret, size); + return ret; } +/* FIXME: evil. */ void grub_dma_free (struct grub_pci_dma_chunk *ch) { + grub_size_t size = (((struct grub_mm_header *) ch) - 1)->size * GRUB_MM_ALIGN; + grub_arch_sync_dma_caches (ch, size); grub_free (ch); } /* #endif */ -#ifdef GRUB_MACHINE_MIPS_YEELOONG +#ifdef GRUB_MACHINE_MIPS_LOONGSON volatile void * grub_dma_get_virt (struct grub_pci_dma_chunk *ch) { @@ -90,17 +106,14 @@ grub_pci_iterate (grub_pci_iteratefunc_t hook) /* Check if there is a device present. */ if (id >> 16 == 0xFFFF) - continue; - -#ifdef GRUB_MACHINE_MIPS_YEELOONG - /* Skip ghosts. */ - if (id == GRUB_YEELOONG_OHCI_PCIID - && dev.function == GRUB_YEELOONG_OHCI_GHOST_FUNCTION) - continue; - if (id == GRUB_YEELOONG_EHCI_PCIID - && dev.function == GRUB_YEELOONG_EHCI_GHOST_FUNCTION) - continue; -#endif + { + if (dev.function == 0) + /* Devices are required to implement function 0, so if + it's missing then there is no device here. */ + break; + else + continue; + } if (hook (dev, id)) return; diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c new file mode 100644 index 000000000..357f7578f --- /dev/null +++ b/grub-core/bus/usb/ehci.c @@ -0,0 +1,1846 @@ +/* ehci.c - EHCI Support. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* This simple GRUB implementation of EHCI driver: + * - assumes no IRQ + * - is not supporting isochronous transfers (iTD, siTD) + * - is not supporting interrupt transfers + */ + +#define GRUB_EHCI_PCI_SBRN_REG 0x60 + +/* Capability registers offsets */ +enum +{ + GRUB_EHCI_EHCC_CAPLEN = 0x00, /* byte */ + GRUB_EHCI_EHCC_VERSION = 0x02, /* word */ + GRUB_EHCI_EHCC_SPARAMS = 0x04, /* dword */ + GRUB_EHCI_EHCC_CPARAMS = 0x08, /* dword */ + GRUB_EHCI_EHCC_PROUTE = 0x0c, /* 60 bits */ +}; + +#define GRUB_EHCI_EECP_MASK (0xff << 8) +#define GRUB_EHCI_EECP_SHIFT 8 + +#define GRUB_EHCI_ADDR_MEM_MASK (~0xff) +#define GRUB_EHCI_POINTER_MASK (~0x1f) + +/* Capability register SPARAMS bits */ +enum +{ + GRUB_EHCI_SPARAMS_N_PORTS = (0xf << 0), + GRUB_EHCI_SPARAMS_PPC = (1 << 4), /* Power port control */ + GRUB_EHCI_SPARAMS_PRR = (1 << 7), /* Port routing rules */ + GRUB_EHCI_SPARAMS_N_PCC = (0xf << 8), /* No of ports per comp. */ + GRUB_EHCI_SPARAMS_NCC = (0xf << 12), /* No of com. controllers */ + GRUB_EHCI_SPARAMS_P_IND = (1 << 16), /* Port indicators present */ + GRUB_EHCI_SPARAMS_DEBUG_P = (0xf << 20) /* Debug port */ +}; + +#define GRUB_EHCI_MAX_N_PORTS 15 /* Max. number of ports */ + +/* Capability register CPARAMS bits */ +enum +{ + GRUB_EHCI_CPARAMS_64BIT = (1 << 0), + GRUB_EHCI_CPARAMS_PROG_FRAMELIST = (1 << 1), + GRUB_EHCI_CPARAMS_PARK_CAP = (1 << 2) +}; + +#define GRUB_EHCI_N_FRAMELIST 1024 +#define GRUB_EHCI_N_QH 256 +#define GRUB_EHCI_N_TD 640 + +#define GRUB_EHCI_QH_EMPTY 1 + +/* USBLEGSUP bits and related OS OWNED byte offset */ +enum +{ + GRUB_EHCI_BIOS_OWNED = (1 << 16), + GRUB_EHCI_OS_OWNED = (1 << 24) +}; + +/* Operational registers offsets */ +enum +{ + GRUB_EHCI_COMMAND = 0x00, + GRUB_EHCI_STATUS = 0x04, + GRUB_EHCI_INTERRUPT = 0x08, + GRUB_EHCI_FRAME_INDEX = 0x0c, + GRUB_EHCI_64BIT_SEL = 0x10, + GRUB_EHCI_FL_BASE = 0x14, + GRUB_EHCI_CUR_AL_ADDR = 0x18, + GRUB_EHCI_CONFIG_FLAG = 0x40, + GRUB_EHCI_PORT_STAT_CMD = 0x44 +}; + +/* Operational register COMMAND bits */ +enum +{ + GRUB_EHCI_CMD_RUNSTOP = (1 << 0), + GRUB_EHCI_CMD_HC_RESET = (1 << 1), + GRUB_EHCI_CMD_FL_SIZE = (3 << 2), + GRUB_EHCI_CMD_PS_ENABL = (1 << 4), + GRUB_EHCI_CMD_AS_ENABL = (1 << 5), + GRUB_EHCI_CMD_AS_ADV_D = (1 << 6), + GRUB_EHCI_CMD_L_HC_RES = (1 << 7), + GRUB_EHCI_CMD_AS_PARKM = (3 << 8), + GRUB_EHCI_CMD_AS_PARKE = (1 << 11), + GRUB_EHCI_CMD_INT_THRS = (0xff << 16) +}; + +/* Operational register STATUS bits */ +enum +{ + GRUB_EHCI_ST_INTERRUPT = (1 << 0), + GRUB_EHCI_ST_ERROR_INT = (1 << 1), + GRUB_EHCI_ST_PORT_CHG = (1 << 2), + GRUB_EHCI_ST_FL_ROLLOVR = (1 << 3), + GRUB_EHCI_ST_HS_ERROR = (1 << 4), + GRUB_EHCI_ST_AS_ADVANCE = (1 << 5), + GRUB_EHCI_ST_HC_HALTED = (1 << 12), + GRUB_EHCI_ST_RECLAM = (1 << 13), + GRUB_EHCI_ST_PS_STATUS = (1 << 14), + GRUB_EHCI_ST_AS_STATUS = (1 << 15) +}; + +/* Operational register PORT_STAT_CMD bits */ +enum +{ + GRUB_EHCI_PORT_CONNECT = (1 << 0), + GRUB_EHCI_PORT_CONNECT_CH = (1 << 1), + GRUB_EHCI_PORT_ENABLED = (1 << 2), + GRUB_EHCI_PORT_ENABLED_CH = (1 << 3), + GRUB_EHCI_PORT_OVERCUR = (1 << 4), + GRUB_EHCI_PORT_OVERCUR_CH = (1 << 5), + GRUB_EHCI_PORT_RESUME = (1 << 6), + GRUB_EHCI_PORT_SUSPEND = (1 << 7), + GRUB_EHCI_PORT_RESET = (1 << 8), + GRUB_EHCI_PORT_LINE_STAT = (3 << 10), + GRUB_EHCI_PORT_POWER = (1 << 12), + GRUB_EHCI_PORT_OWNER = (1 << 13), + GRUB_EHCI_PORT_INDICATOR = (3 << 14), + GRUB_EHCI_PORT_TEST = (0xf << 16), + GRUB_EHCI_PORT_WON_CONN_E = (1 << 20), + GRUB_EHCI_PORT_WON_DISC_E = (1 << 21), + GRUB_EHCI_PORT_WON_OVER_E = (1 << 22), + + GRUB_EHCI_PORT_LINE_SE0 = (0 << 10), + GRUB_EHCI_PORT_LINE_K = (1 << 10), + GRUB_EHCI_PORT_LINE_J = (2 << 10), + GRUB_EHCI_PORT_LINE_UNDEF = (3 << 10), + GRUB_EHCI_PORT_LINE_LOWSP = GRUB_EHCI_PORT_LINE_K, /* K state means low speed */ + GRUB_EHCI_PORT_WMASK = ~(GRUB_EHCI_PORT_CONNECT_CH + | GRUB_EHCI_PORT_ENABLED_CH + | GRUB_EHCI_PORT_OVERCUR_CH) +}; + +/* Operational register CONFIGFLAGS bits */ +enum +{ + GRUB_EHCI_CF_EHCI_OWNER = (1 << 0) +}; + +/* Queue Head & Transfer Descriptor constants */ +#define GRUB_EHCI_HPTR_OFF 5 /* Horiz. pointer bit offset */ +enum +{ + GRUB_EHCI_HPTR_TYPE_MASK = (3 << 1), + GRUB_EHCI_HPTR_TYPE_ITD = (0 << 1), + GRUB_EHCI_HPTR_TYPE_QH = (1 << 1), + GRUB_EHCI_HPTR_TYPE_SITD = (2 << 1), + GRUB_EHCI_HPTR_TYPE_FSTN = (3 << 1) +}; + +enum +{ + GRUB_EHCI_C = (1 << 27), + GRUB_EHCI_MAXPLEN_MASK = (0x7ff << 16), + GRUB_EHCI_H = (1 << 15), + GRUB_EHCI_DTC = (1 << 14), + GRUB_EHCI_SPEED_MASK = (3 << 12), + GRUB_EHCI_SPEED_FULL = (0 << 12), + GRUB_EHCI_SPEED_LOW = (1 << 12), + GRUB_EHCI_SPEED_HIGH = (2 << 12), + GRUB_EHCI_SPEED_RESERVED = (3 << 12), + GRUB_EHCI_EP_NUM_MASK = (0xf << 8), + GRUB_EHCI_DEVADDR_MASK = 0x7f, + GRUB_EHCI_TARGET_MASK = (GRUB_EHCI_EP_NUM_MASK | GRUB_EHCI_DEVADDR_MASK) +}; + +enum +{ + GRUB_EHCI_MAXPLEN_OFF = 16, + GRUB_EHCI_SPEED_OFF = 12, + GRUB_EHCI_EP_NUM_OFF = 8 +}; + +enum +{ + GRUB_EHCI_MULT_MASK = (3 << 30), + GRUB_EHCI_MULT_RESERVED = (0 << 30), + GRUB_EHCI_MULT_ONE = (0 << 30), + GRUB_EHCI_MULT_TWO = (0 << 30), + GRUB_EHCI_MULT_THREE = (0 << 30), + GRUB_EHCI_DEVPORT_MASK = (0x7f << 23), + GRUB_EHCI_HUBADDR_MASK = (0x7f << 16) +}; + +enum +{ + GRUB_EHCI_MULT_OFF = 30, + GRUB_EHCI_DEVPORT_OFF = 23, + GRUB_EHCI_HUBADDR_OFF = 16 +}; + +#define GRUB_EHCI_TERMINATE (1<<0) + +#define GRUB_EHCI_TOGGLE (1<<31) + +enum +{ + GRUB_EHCI_TOTAL_MASK = (0x7fff << 16), + GRUB_EHCI_CERR_MASK = (3 << 10), + GRUB_EHCI_CERR_0 = (0 << 10), + GRUB_EHCI_CERR_1 = (1 << 10), + GRUB_EHCI_CERR_2 = (2 << 10), + GRUB_EHCI_CERR_3 = (3 << 10), + GRUB_EHCI_PIDCODE_OUT = (0 << 8), + GRUB_EHCI_PIDCODE_IN = (1 << 8), + GRUB_EHCI_PIDCODE_SETUP = (2 << 8), + GRUB_EHCI_STATUS_MASK = 0xff, + GRUB_EHCI_STATUS_ACTIVE = (1 << 7), + GRUB_EHCI_STATUS_HALTED = (1 << 6), + GRUB_EHCI_STATUS_BUFERR = (1 << 5), + GRUB_EHCI_STATUS_BABBLE = (1 << 4), + GRUB_EHCI_STATUS_TRANERR = (1 << 3), + GRUB_EHCI_STATUS_MISSDMF = (1 << 2), + GRUB_EHCI_STATUS_SPLITST = (1 << 1), + GRUB_EHCI_STATUS_PINGERR = (1 << 0) +}; + +enum +{ + GRUB_EHCI_TOTAL_OFF = 16, + GRUB_EHCI_CERR_OFF = 10 +}; + +#define GRUB_EHCI_BUFPTR_MASK (0xfffff<<12) +#define GRUB_EHCI_QHTDPTR_MASK 0xffffffe0 + +#define GRUB_EHCI_TD_BUF_PAGES 5 + +#define GRUB_EHCI_BUFPAGELEN 0x1000 +#define GRUB_EHCI_MAXBUFLEN 0x5000 + +struct grub_ehci_td; +struct grub_ehci_qh; +typedef volatile struct grub_ehci_td *grub_ehci_td_t; +typedef volatile struct grub_ehci_qh *grub_ehci_qh_t; + +/* EHCI Isochronous Transfer Descriptor */ +/* Currently not supported */ + +/* EHCI Split Transaction Isochronous Transfer Descriptor */ +/* Currently not supported */ + +/* EHCI Queue Element Transfer Descriptor (qTD) */ +/* Align to 32-byte boundaries */ +struct grub_ehci_td +{ + /* EHCI HW part */ + grub_uint32_t next_td; /* Pointer to next qTD */ + grub_uint32_t alt_next_td; /* Pointer to alternate next qTD */ + grub_uint32_t token; /* Toggle, Len, Interrupt, Page, Error, PID, Status */ + grub_uint32_t buffer_page[GRUB_EHCI_TD_BUF_PAGES]; /* Buffer pointer (+ cur. offset in page 0 */ + /* 64-bits part */ + grub_uint32_t buffer_page_high[GRUB_EHCI_TD_BUF_PAGES]; + /* EHCI driver part */ + grub_uint32_t link_td; /* pointer to next free/chained TD */ + grub_uint32_t size; + grub_uint32_t pad[1]; /* padding to some multiple of 32 bytes */ +}; + +/* EHCI Queue Head */ +/* Align to 32-byte boundaries */ +/* QH allocation is made in the similar/same way as in OHCI driver, + * because unlninking QH from the Asynchronous list is not so + * trivial as on UHCI (at least it is time consuming) */ +struct grub_ehci_qh +{ + /* EHCI HW part */ + grub_uint32_t qh_hptr; /* Horiz. pointer & Terminate */ + grub_uint32_t ep_char; /* EP characteristics */ + grub_uint32_t ep_cap; /* EP capabilities */ + grub_uint32_t td_current; /* current TD link pointer */ + struct grub_ehci_td td_overlay; /* TD overlay area = 64 bytes */ + /* EHCI driver part */ + grub_uint32_t pad[4]; /* padding to some multiple of 32 bytes */ +}; + +/* EHCI Periodic Frame Span Traversal Node */ +/* Currently not supported */ + +struct grub_ehci +{ + volatile grub_uint32_t *iobase_ehcc; /* Capability registers */ + volatile grub_uint32_t *iobase; /* Operational registers */ + struct grub_pci_dma_chunk *framelist_chunk; /* Currently not used */ + volatile grub_uint32_t *framelist_virt; + grub_uint32_t framelist_phys; + struct grub_pci_dma_chunk *qh_chunk; /* GRUB_EHCI_N_QH Queue Heads */ + grub_ehci_qh_t qh_virt; + grub_uint32_t qh_phys; + struct grub_pci_dma_chunk *td_chunk; /* GRUB_EHCI_N_TD Transfer Descriptors */ + grub_ehci_td_t td_virt; + grub_uint32_t td_phys; + grub_ehci_td_t tdfree_virt; /* Free Transfer Descriptors */ + int flag64; + grub_uint32_t reset; /* bits 1-15 are flags if port was reset from connected time or not */ + struct grub_ehci *next; +}; + +static struct grub_ehci *ehci; + +/* EHCC registers access functions */ +static inline grub_uint32_t +grub_ehci_ehcc_read32 (struct grub_ehci *e, grub_uint32_t addr) +{ + return + grub_le_to_cpu32 (* + ((volatile grub_uint32_t *) ((char *) e->iobase_ehcc + + addr))); +} + +static inline grub_uint16_t +grub_ehci_ehcc_read16 (struct grub_ehci *e, grub_uint32_t addr) +{ + return + grub_le_to_cpu16 (* + ((volatile grub_uint16_t *) ((char *) e->iobase_ehcc + + addr))); +} + +static inline grub_uint8_t +grub_ehci_ehcc_read8 (struct grub_ehci *e, grub_uint32_t addr) +{ + return *((volatile grub_uint8_t *) ((char *) e->iobase_ehcc + addr)); +} + +/* Operational registers access functions */ +static inline grub_uint32_t +grub_ehci_oper_read32 (struct grub_ehci *e, grub_uint32_t addr) +{ + return + grub_le_to_cpu32 (* + ((volatile grub_uint32_t *) ((char *) e->iobase + + addr))); +} + +static inline void +grub_ehci_oper_write32 (struct grub_ehci *e, grub_uint32_t addr, + grub_uint32_t value) +{ + *((volatile grub_uint32_t *) ((char *) e->iobase + addr)) = + grub_cpu_to_le32 (value); +} + +static inline grub_uint32_t +grub_ehci_port_read (struct grub_ehci *e, grub_uint32_t port) +{ + return grub_ehci_oper_read32 (e, GRUB_EHCI_PORT_STAT_CMD + port * 4); +} + +static inline void +grub_ehci_port_resbits (struct grub_ehci *e, grub_uint32_t port, + grub_uint32_t bits) +{ + grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + port * 4, + grub_ehci_port_read (e, + port) & GRUB_EHCI_PORT_WMASK & + ~(bits)); + grub_ehci_port_read (e, port); +} + +static inline void +grub_ehci_port_setbits (struct grub_ehci *e, grub_uint32_t port, + grub_uint32_t bits) +{ + grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + port * 4, + (grub_ehci_port_read (e, port) & + GRUB_EHCI_PORT_WMASK) | bits); + grub_ehci_port_read (e, port); +} + +/* Halt if EHCI HC not halted */ +static grub_usb_err_t +grub_ehci_halt (struct grub_ehci *e) +{ + grub_uint64_t maxtime; + + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) & GRUB_EHCI_ST_HC_HALTED) == 0) /* EHCI is not halted */ + { + /* Halt EHCI */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + ~GRUB_EHCI_CMD_RUNSTOP + & grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + /* Ensure command is written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND); + maxtime = grub_get_time_ms () + 1000; /* Fix: Should be 2ms ! */ + while (((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_HC_HALTED) == 0) + && (grub_get_time_ms () < maxtime)); + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_HC_HALTED) == 0) + return GRUB_USB_ERR_TIMEOUT; + } + + return GRUB_USB_ERR_NONE; +} + +/* EHCI HC reset */ +static grub_usb_err_t +grub_ehci_reset (struct grub_ehci *e) +{ + grub_uint64_t maxtime; + + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_HC_RESET + | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + /* Ensure command is written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND); + /* XXX: How long time could take reset of HC ? */ + maxtime = grub_get_time_ms () + 1000; + while (((grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND) + & GRUB_EHCI_CMD_HC_RESET) != 0) + && (grub_get_time_ms () < maxtime)); + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND) + & GRUB_EHCI_CMD_HC_RESET) != 0) + return GRUB_USB_ERR_TIMEOUT; + + return GRUB_USB_ERR_NONE; +} + +/* PCI iteration function... */ +static int NESTED_FUNC_ATTR +grub_ehci_pci_iter (grub_pci_device_t dev, + grub_pci_id_t pciid __attribute__ ((unused))) +{ + grub_uint8_t release; + grub_uint32_t class_code; + grub_uint32_t interf; + grub_uint32_t subclass; + grub_uint32_t class; + grub_uint32_t base, base_h; + struct grub_ehci *e; + grub_uint32_t eecp_offset; + grub_uint32_t fp; + int i; + grub_uint32_t usblegsup = 0; + grub_uint64_t maxtime; + grub_uint32_t n_ports; + grub_uint8_t caplen; + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: begin\n"); + + if (pciid == GRUB_CS5536_PCIID) + { + grub_uint64_t basereg; + + basereg = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE); + if (!(basereg & GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE)) + { + /* Shouldn't happen. */ + grub_dprintf ("ehci", "No EHCI address is assigned\n"); + return 0; + } + base = (basereg & GRUB_CS5536_MSR_USB_BASE_ADDR_MASK); + basereg |= GRUB_CS5536_MSR_USB_BASE_BUS_MASTER; + basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_ENABLED; + basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_STATUS; + basereg &= ~GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE; + grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE, basereg); + } + else + { + grub_pci_address_t addr; + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + class_code = grub_pci_read (addr) >> 8; + interf = class_code & 0xFF; + subclass = (class_code >> 8) & 0xFF; + class = class_code >> 16; + + /* If this is not an EHCI controller, just return. */ + if (class != 0x0c || subclass != 0x03 || interf != 0x20) + return 0; + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: class OK\n"); + + /* Check Serial Bus Release Number */ + addr = grub_pci_make_address (dev, GRUB_EHCI_PCI_SBRN_REG); + release = grub_pci_read_byte (addr); + if (release != 0x20) + { + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: Wrong SBRN: %0x\n", + release); + return 0; + } + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: bus rev. num. OK\n"); + + /* Determine EHCI EHCC registers base address. */ + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); + base = grub_pci_read (addr); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1); + base_h = grub_pci_read (addr); + /* Stop if registers are mapped above 4G - GRUB does not currently + * work with registers mapped above 4G */ + if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32) + && (base_h != 0)) + { + grub_dprintf ("ehci", + "EHCI grub_ehci_pci_iter: registers above 4G are not supported\n"); + return 0; + } + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: 32-bit EHCI OK\n"); + } + + /* Allocate memory for the controller and fill basic values. */ + e = grub_zalloc (sizeof (*e)); + if (!e) + return 1; + e->framelist_chunk = NULL; + e->td_chunk = NULL; + e->qh_chunk = NULL; + e->iobase_ehcc = grub_pci_device_map_range (dev, + (base & GRUB_EHCI_ADDR_MEM_MASK), + 0x100); + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: iobase of EHCC: %08x\n", + (base & GRUB_EHCI_ADDR_MEM_MASK)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CAPLEN: %02x\n", + grub_ehci_ehcc_read8 (e, GRUB_EHCI_EHCC_CAPLEN)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: VERSION: %04x\n", + grub_ehci_ehcc_read16 (e, GRUB_EHCI_EHCC_VERSION)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: SPARAMS: %08x\n", + grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CPARAMS: %08x\n", + grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS)); + + /* Determine base address of EHCI operational registers */ + caplen = grub_ehci_ehcc_read8 (e, GRUB_EHCI_EHCC_CAPLEN); + e->iobase = (volatile grub_uint32_t *) + ((grub_uint8_t *) e->iobase_ehcc + caplen); + + grub_dprintf ("ehci", + "EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n", + (base & GRUB_EHCI_ADDR_MEM_MASK) + caplen); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: INTERRUPT: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_INTERRUPT)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FRAME_INDEX: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_FRAME_INDEX)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FL_BASE: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_FL_BASE)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CUR_AL_ADDR: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_CUR_AL_ADDR)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG)); + + /* Is there EECP ? */ + eecp_offset = (grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS) + & GRUB_EHCI_EECP_MASK) >> GRUB_EHCI_EECP_SHIFT; + + /* Check format of data structures requested by EHCI */ + /* XXX: In fact it is not used at any place, it is prepared for future + * This implementation uses 32-bits pointers only */ + e->flag64 = ((grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS) + & GRUB_EHCI_CPARAMS_64BIT) != 0); + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: flag64=%d\n", e->flag64); + + /* Reserve a page for the frame list - it is accurate for max. + * possible size of framelist. But currently it is not used. */ + e->framelist_chunk = grub_memalign_dma32 (4096, 4096); + if (!e->framelist_chunk) + goto fail; + e->framelist_virt = grub_dma_get_virt (e->framelist_chunk); + e->framelist_phys = grub_dma_get_phys (e->framelist_chunk); + grub_memset ((void *) e->framelist_virt, 0, 4096); + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: framelist mem=0x%08x. OK\n", + (grub_uint32_t) e->framelist_virt); + + /* Allocate memory for the QHs and register it in "e". */ + e->qh_chunk = grub_memalign_dma32 (4096, + sizeof (struct grub_ehci_qh) * + GRUB_EHCI_N_QH); + if (!e->qh_chunk) + goto fail; + e->qh_virt = (grub_ehci_qh_t) grub_dma_get_virt (e->qh_chunk); + e->qh_phys = grub_dma_get_phys (e->qh_chunk); + grub_memset ((void *) e->qh_virt, 0, + sizeof (struct grub_ehci_qh) * GRUB_EHCI_N_QH); + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: QH mem=0x%08x. OK\n", + (grub_uint32_t) e->qh_virt); + + /* Allocate memory for the TDs and register it in "e". */ + e->td_chunk = grub_memalign_dma32 (4096, + sizeof (struct grub_ehci_td) * + GRUB_EHCI_N_TD); + if (!e->td_chunk) + goto fail; + e->td_virt = (grub_ehci_td_t) grub_dma_get_virt (e->td_chunk); + e->td_phys = grub_dma_get_phys (e->td_chunk); + grub_memset ((void *) e->td_virt, 0, + sizeof (struct grub_ehci_td) * GRUB_EHCI_N_TD); + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: TD mem=0x%08x. OK\n", + (grub_uint32_t) e->td_virt); + + /* Setup all frame list pointers. Since no isochronous transfers + are supported, they all point to the (same!) queue + head with index 0. */ + fp = grub_cpu_to_le32 ((e->qh_phys & GRUB_EHCI_POINTER_MASK) + | GRUB_EHCI_HPTR_TYPE_QH); + for (i = 0; i < GRUB_EHCI_N_FRAMELIST; i++) + e->framelist_virt[i] = fp; + /* Prepare chain of all TDs and set Terminate in all TDs */ + for (i = 0; i < (GRUB_EHCI_N_TD - 1); i++) + { + e->td_virt[i].link_td = e->td_phys + (i + 1) * sizeof (struct grub_ehci_td); + e->td_virt[i].next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + e->td_virt[i].alt_next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + } + e->td_virt[GRUB_EHCI_N_TD - 1].next_td = + grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + e->td_virt[GRUB_EHCI_N_TD - 1].alt_next_td = + grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + e->tdfree_virt = e->td_virt; + /* Set Terminate in first QH, which is used in framelist */ + e->qh_virt[0].qh_hptr = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + e->qh_virt[0].td_overlay.next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + e->qh_virt[0].td_overlay.alt_next_td = + grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + /* Also set Halted bit in token */ + e->qh_virt[0].td_overlay.token = grub_cpu_to_le32 (GRUB_EHCI_STATUS_HALTED); + /* Set the H bit in first QH used for AL */ + e->qh_virt[1].ep_char = grub_cpu_to_le32 (GRUB_EHCI_H); + /* Set Terminate into TD in rest of QHs and set horizontal link + * pointer to itself - these QHs will be used for asynchronous + * schedule and they should have valid value in horiz. link */ + for (i = 1; i < GRUB_EHCI_N_QH; i++) + { + e->qh_virt[i].qh_hptr = + grub_cpu_to_le32 ((grub_dma_virt2phys (&e->qh_virt[i], + e->qh_chunk) & + GRUB_EHCI_POINTER_MASK) | GRUB_EHCI_HPTR_TYPE_QH); + e->qh_virt[i].td_overlay.next_td = + grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + e->qh_virt[i].td_overlay.alt_next_td = + grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + /* Also set Halted bit in token */ + e->qh_virt[i].td_overlay.token = + grub_cpu_to_le32 (GRUB_EHCI_STATUS_HALTED); + } + + /* Note: QH 0 and QH 1 are reserved and must not be used anywhere. + * QH 0 is used as empty QH for framelist + * QH 1 is used as starting empty QH for asynchronous schedule + * QH 1 must exist at any time because at least one QH linked to + * itself must exist in asynchronous schedule + * QH 1 has the H flag set to one */ + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: QH/TD init. OK\n"); + + /* Determine and change ownership. */ + /* EECP offset valid in HCCPARAMS */ + /* Ownership can be changed via EECP only */ + if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40) + { + grub_pci_address_t pciaddr_eecp; + pciaddr_eecp = grub_pci_make_address (dev, eecp_offset); + + usblegsup = grub_pci_read (pciaddr_eecp); + if (usblegsup & GRUB_EHCI_BIOS_OWNED) + { + grub_dprintf ("ehci", + "EHCI grub_ehci_pci_iter: EHCI owned by: BIOS\n"); + /* Ownership change - set OS_OWNED bit */ + grub_pci_write (pciaddr_eecp, usblegsup | GRUB_EHCI_OS_OWNED); + /* Ensure PCI register is written */ + grub_pci_read (pciaddr_eecp); + + /* Wait for finish of ownership change, EHCI specification + * doesn't say how long it can take... */ + maxtime = grub_get_time_ms () + 1000; + while ((grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED) + && (grub_get_time_ms () < maxtime)); + if (grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED) + { + grub_dprintf ("ehci", + "EHCI grub_ehci_pci_iter: EHCI change ownership timeout"); + /* Change ownership in "hard way" - reset BIOS ownership */ + grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED); + /* Ensure PCI register is written */ + grub_pci_read (pciaddr_eecp); + /* Disable SMI. */ + pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4); + grub_pci_write (pciaddr_eecp, 0); + /* Ensure PCI register is written */ + grub_pci_read (pciaddr_eecp); + } + } + else if (usblegsup & GRUB_EHCI_OS_OWNED) + /* XXX: What to do in this case - nothing ? Can it happen ? */ + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: EHCI owned by: OS\n"); + else + { + grub_dprintf ("ehci", + "EHCI grub_ehci_pci_iter: EHCI owned by: NONE\n"); + /* XXX: What to do in this case ? Can it happen ? + * Is code below correct ? */ + /* Ownership change - set OS_OWNED bit */ + grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED); + /* Ensure PCI register is written */ + grub_pci_read (pciaddr_eecp); + /* Disable SMI, just to be sure. */ + pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4); + grub_pci_write (pciaddr_eecp, 0); + /* Ensure PCI register is written */ + grub_pci_read (pciaddr_eecp); + } + } + + grub_dprintf ("ehci", "inithw: EHCI grub_ehci_pci_iter: ownership OK\n"); + + /* Now we can setup EHCI (maybe...) */ + + /* Check if EHCI is halted and halt it if not */ + if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE) + { + grub_error (GRUB_ERR_TIMEOUT, + "EHCI grub_ehci_pci_iter: EHCI halt timeout"); + goto fail; + } + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: halted OK\n"); + + /* Reset EHCI */ + if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE) + { + grub_error (GRUB_ERR_TIMEOUT, + "EHCI grub_ehci_pci_iter: EHCI reset timeout"); + goto fail; + } + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: reset OK\n"); + + /* Setup list address registers */ + grub_ehci_oper_write32 (e, GRUB_EHCI_FL_BASE, e->framelist_phys); + grub_ehci_oper_write32 (e, GRUB_EHCI_CUR_AL_ADDR, + grub_dma_virt2phys (&e->qh_virt[1], + e->qh_chunk)); + + /* Set ownership of root hub ports to EHCI */ + grub_ehci_oper_write32 (e, GRUB_EHCI_CONFIG_FLAG, GRUB_EHCI_CF_EHCI_OWNER); + + /* Enable asynchronous list */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_AS_ENABL + | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + + /* Now should be possible to power-up and enumerate ports etc. */ + if ((grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS) + & GRUB_EHCI_SPARAMS_PPC) != 0) + { /* EHCI has port powering control */ + /* Power on all ports */ + n_ports = grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS) + & GRUB_EHCI_SPARAMS_N_PORTS; + for (i = 0; i < (int) n_ports; i++) + grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + i * 4, + GRUB_EHCI_PORT_POWER + | grub_ehci_oper_read32 (e, + GRUB_EHCI_PORT_STAT_CMD + + i * 4)); + } + + /* Ensure all commands are written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND); + + /* Enable EHCI */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_RUNSTOP + | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + + /* Ensure command is written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND); + + /* Link to ehci now that initialisation is successful. */ + e->next = ehci; + ehci = e; + + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: OK at all\n"); + + grub_dprintf ("ehci", + "EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n", + (base & GRUB_EHCI_ADDR_MEM_MASK)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: INTERRUPT: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_INTERRUPT)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FRAME_INDEX: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_FRAME_INDEX)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FL_BASE: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_FL_BASE)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CUR_AL_ADDR: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_CUR_AL_ADDR)); + grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG)); + + return 0; + +fail: + if (e) + { + if (e->td_chunk) + grub_dma_free ((void *) e->td_chunk); + if (e->qh_chunk) + grub_dma_free ((void *) e->qh_chunk); + if (e->framelist_chunk) + grub_dma_free (e->framelist_chunk); + } + grub_free (e); + + return 0; +} + +static int +grub_ehci_iterate (int (*hook) (grub_usb_controller_t dev)) +{ + struct grub_ehci *e; + struct grub_usb_controller dev; + + for (e = ehci; e; e = e->next) + { + dev.data = e; + if (hook (&dev)) + return 1; + } + + return 0; +} + +static void +grub_ehci_setup_qh (grub_ehci_qh_t qh, grub_usb_transfer_t transfer) +{ + grub_uint32_t ep_char = 0; + grub_uint32_t ep_cap = 0; + + /* Note: Another part of code is responsible to this QH is + * Halted ! But it can be linked in AL, so we cannot erase or + * change qh_hptr ! */ + /* We will not change any TD field because they should/must be + * in safe state from previous use. */ + + /* EP characteristic setup */ + /* Currently not used NAK counter (RL=0), + * C bit set if EP is not HIGH speed and is control, + * Max Packet Length is taken from transfer structure, + * H bit = 0 (because QH[1] has this bit set), + * DTC bit set to 1 because we are using our own toggle bit control, + * SPEED is selected according to value from transfer structure, + * EP number is taken from transfer structure + * "I" bit must not be set, + * Device Address is taken from transfer structure + * */ + if ((transfer->dev->speed != GRUB_USB_SPEED_HIGH) + && (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL)) + ep_char |= GRUB_EHCI_C; + ep_char |= (transfer->max << GRUB_EHCI_MAXPLEN_OFF) + & GRUB_EHCI_MAXPLEN_MASK; + ep_char |= GRUB_EHCI_DTC; + switch (transfer->dev->speed) + { + case GRUB_USB_SPEED_LOW: + ep_char |= GRUB_EHCI_SPEED_LOW; + break; + case GRUB_USB_SPEED_FULL: + ep_char |= GRUB_EHCI_SPEED_FULL; + break; + case GRUB_USB_SPEED_HIGH: + default: + ep_char |= GRUB_EHCI_SPEED_HIGH; + /* XXX: How we will handle unknown value of speed? */ + } + ep_char |= (transfer->endpoint << GRUB_EHCI_EP_NUM_OFF) + & GRUB_EHCI_EP_NUM_MASK; + ep_char |= transfer->devaddr & GRUB_EHCI_DEVADDR_MASK; + qh->ep_char = grub_cpu_to_le32 (ep_char); + /* EP capabilities setup */ + /* MULT field - we try to use max. number + * PortNumber - included now in device structure referenced + * inside transfer structure + * HubAddress - included now in device structure referenced + * inside transfer structure + * SplitCompletionMask - AFAIK it is ignored in asynchronous list, + * InterruptScheduleMask - AFAIK it should be zero in async. list */ + ep_cap |= GRUB_EHCI_MULT_THREE; + ep_cap |= (transfer->dev->port << GRUB_EHCI_DEVPORT_OFF) + & GRUB_EHCI_DEVPORT_MASK; + ep_cap |= (transfer->dev->hubaddr << GRUB_EHCI_HUBADDR_OFF) + & GRUB_EHCI_HUBADDR_MASK; + qh->ep_cap = grub_cpu_to_le32 (ep_cap); + + grub_dprintf ("ehci", "setup_qh: qh=%08x, not changed: qh_hptr=%08x\n", + (grub_uint32_t) qh, grub_le_to_cpu32 (qh->qh_hptr)); + grub_dprintf ("ehci", "setup_qh: ep_char=%08x, ep_cap=%08x\n", + ep_char, ep_cap); + grub_dprintf ("ehci", "setup_qh: end\n"); + grub_dprintf ("ehci", "setup_qh: not changed: td_current=%08x\n", + grub_le_to_cpu32 (qh->td_current)); + grub_dprintf ("ehci", "setup_qh: not changed: next_td=%08x\n", + grub_le_to_cpu32 (qh->td_overlay.next_td)); + grub_dprintf ("ehci", "setup_qh: not changed: alt_next_td=%08x\n", + grub_le_to_cpu32 (qh->td_overlay.alt_next_td)); + grub_dprintf ("ehci", "setup_qh: not changed: token=%08x\n", + grub_le_to_cpu32 (qh->td_overlay.token)); +} + +static grub_ehci_qh_t +grub_ehci_find_qh (struct grub_ehci *e, grub_usb_transfer_t transfer) +{ + grub_uint32_t target, mask; + int i; + grub_ehci_qh_t qh = e->qh_virt; + + /* Prepare part of EP Characteristic to find existing QH */ + target = ((transfer->endpoint << GRUB_EHCI_EP_NUM_OFF) | + transfer->devaddr) & GRUB_EHCI_TARGET_MASK; + target = grub_cpu_to_le32 (target); + mask = grub_cpu_to_le32 (GRUB_EHCI_TARGET_MASK); + + /* First try to find existing QH with proper target */ + for (i = 2; i < GRUB_EHCI_N_QH; i++) /* We ignore zero and first QH */ + { + if (!qh[i].ep_char) + break; /* Found first not-allocated QH, finish */ + if (target == (qh[i].ep_char & mask)) + { /* Found proper existing (and linked) QH, do setup of QH */ + grub_dprintf ("ehci", "find_qh: found, i=%d, QH=%08x\n", + i, (grub_uint32_t) & qh[i]); + grub_ehci_setup_qh (&qh[i], transfer); + return &qh[i]; + } + } + /* QH with target_addr does not exist, we have to add it */ + /* Have we any free QH in array ? */ + if (i >= GRUB_EHCI_N_QH) /* No. */ + { + grub_dprintf ("ehci", "find_qh: end - no free QH\n"); + return NULL; + } + grub_dprintf ("ehci", "find_qh: new, i=%d, QH=%08x\n", + i, (grub_uint32_t) & qh[i]); + /* Currently we simply take next (current) QH in array, no allocation + * function is used. It should be no problem until we will need to + * de-allocate QHs of unplugged devices. */ + /* We should preset new QH and link it into AL */ + grub_ehci_setup_qh (&qh[i], transfer); + /* Linking - this new (last) QH will point to first QH */ + qh[i].qh_hptr = grub_cpu_to_le32 (GRUB_EHCI_HPTR_TYPE_QH + | grub_dma_virt2phys (&qh[1], + e->qh_chunk)); + /* Linking - previous last QH will point to this new QH */ + qh[i - 1].qh_hptr = grub_cpu_to_le32 (GRUB_EHCI_HPTR_TYPE_QH + | grub_dma_virt2phys (&qh[i], + e->qh_chunk)); + + return &qh[i]; +} + +static grub_ehci_td_t +grub_ehci_alloc_td (struct grub_ehci *e) +{ + grub_ehci_td_t ret; + + /* Check if there is a Transfer Descriptor available. */ + if (!e->tdfree_virt) + { + grub_dprintf ("ehci", "alloc_td: end - no free TD\n"); + return NULL; + } + + ret = e->tdfree_virt; /* Take current free TD */ + /* Advance to next free TD in chain */ + if (ret->link_td) + e->tdfree_virt = grub_dma_phys2virt (ret->link_td, e->td_chunk); + else + e->tdfree_virt = NULL; + ret->link_td = 0; /* Reset link_td in allocated TD */ + return ret; +} + +static void +grub_ehci_free_td (struct grub_ehci *e, grub_ehci_td_t td) +{ + /* Chain new free TD & rest */ + if (e->tdfree_virt) + td->link_td = grub_dma_virt2phys (e->tdfree_virt, e->td_chunk); + else + td->link_td = 0; + e->tdfree_virt = td; /* Change address of first free TD */ +} + +static void +grub_ehci_free_tds (struct grub_ehci *e, grub_ehci_td_t td, + grub_usb_transfer_t transfer, grub_size_t * actual) +{ + int i; /* Index of TD in transfer */ + grub_uint32_t token, to_transfer; + + /* Note: Another part of code is responsible to this QH is + * INACTIVE ! */ + *actual = 0; + + /* Free the TDs in this queue and set last_trans. */ + for (i = 0; td; i++) + { + grub_ehci_td_t tdprev; + + token = grub_le_to_cpu32 (td->token); + to_transfer = (token & GRUB_EHCI_TOTAL_MASK) >> GRUB_EHCI_TOTAL_OFF; + + /* Check state of TD - if it did not transfered + * whole data then set last_trans - it should be last executed TD + * in case when something went wrong. */ + if (transfer && (td->size != to_transfer)) + transfer->last_trans = i; + + *actual += td->size - to_transfer; + + /* Unlink the TD */ + tdprev = td; + if (td->link_td) + td = grub_dma_phys2virt (td->link_td, e->td_chunk); + else + td = NULL; + + /* Free the TD. */ + grub_ehci_free_td (e, tdprev); + } + + /* Check if last_trans was set. If not and something was + * transferred (it should be all data in this case), set it + * to index of last TD, i.e. i-1 */ + if (transfer && (transfer->last_trans < 0) && (*actual != 0)) + transfer->last_trans = i - 1; + + /* XXX: Fix it: last_trans may be set to bad index. + * Probably we should test more error flags to distinguish + * if TD was at least partialy executed or not at all. + * Generaly, we still could have problem with toggling because + * EHCI can probably split transactions into smaller parts then + * we defined in transaction even if we did not exceed MaxFrame + * length - it probably could happen at the end of microframe (?) + * and if the buffer is crossing page boundary (?). */ +} + +static grub_ehci_td_t +grub_ehci_transaction (struct grub_ehci *e, + grub_transfer_type_t type, + unsigned int toggle, grub_size_t size, + grub_uint32_t data, grub_ehci_td_t td_alt) +{ + grub_ehci_td_t td; + grub_uint32_t token; + grub_uint32_t bufadr; + int i; + + /* Test of transfer size, it can be: + * <= GRUB_EHCI_MAXBUFLEN if data aligned to page boundary + * <= GRUB_EHCI_MAXBUFLEN - GRUB_EHCI_BUFPAGELEN if not aligned + * (worst case) + */ + if ((((data % GRUB_EHCI_BUFPAGELEN) == 0) + && (size > GRUB_EHCI_MAXBUFLEN)) + || + (((data % GRUB_EHCI_BUFPAGELEN) != 0) + && (size > (GRUB_EHCI_MAXBUFLEN - GRUB_EHCI_BUFPAGELEN)))) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, + "too long data buffer for EHCI transaction"); + return 0; + } + + /* Grab a free Transfer Descriptor and initialize it. */ + td = grub_ehci_alloc_td (e); + if (!td) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, + "no transfer descriptors available for EHCI transfer"); + return 0; + } + + grub_dprintf ("ehci", + "transaction: type=%d, toggle=%d, size=%lu data=0x%x td=%p\n", + type, toggle, (unsigned long) size, data, td); + + /* Fill whole TD by zeros */ + grub_memset ((void *) td, 0, sizeof (struct grub_ehci_td)); + + /* Don't point to any TD yet, just terminate. */ + td->next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + /* Set alternate pointer. When short packet occurs, alternate TD + * will not be really fetched because it is not active. But don't + * forget, EHCI will try to fetch alternate TD every scan of AL + * until QH is halted. */ + td->alt_next_td = grub_cpu_to_le32 (grub_dma_virt2phys (td_alt, + e->td_chunk)); + /* token: + * TOGGLE - according to toggle + * TOTAL SIZE = size + * Interrupt On Complete = FALSE, we don't need IRQ + * Current Page = 0 + * Error Counter = max. value = 3 + * PID Code - according to type + * STATUS: + * ACTIVE bit should be set to one + * SPLIT TRANS. STATE bit should be zero. It is ignored + * in HIGH speed transaction, and should be zero for LOW/FULL + * speed to indicate state Do Split Transaction */ + token = toggle ? GRUB_EHCI_TOGGLE : 0; + token |= (size << GRUB_EHCI_TOTAL_OFF) & GRUB_EHCI_TOTAL_MASK; + token |= GRUB_EHCI_CERR_3; + switch (type) + { + case GRUB_USB_TRANSFER_TYPE_IN: + token |= GRUB_EHCI_PIDCODE_IN; + break; + case GRUB_USB_TRANSFER_TYPE_OUT: + token |= GRUB_EHCI_PIDCODE_OUT; + break; + case GRUB_USB_TRANSFER_TYPE_SETUP: + token |= GRUB_EHCI_PIDCODE_SETUP; + break; + default: /* XXX: Should not happen, but what to do if it does ? */ + break; + } + token |= GRUB_EHCI_STATUS_ACTIVE; + td->token = grub_cpu_to_le32 (token); + + /* Fill buffer pointers according to size */ + bufadr = data; + td->buffer_page[0] = grub_cpu_to_le32 (bufadr); + bufadr = ((bufadr / GRUB_EHCI_BUFPAGELEN) + 1) * GRUB_EHCI_BUFPAGELEN; + for (i = 1; ((bufadr - data) < size) && (i < GRUB_EHCI_TD_BUF_PAGES); i++) + { + td->buffer_page[i] = grub_cpu_to_le32 (bufadr & GRUB_EHCI_BUFPTR_MASK); + bufadr = ((bufadr / GRUB_EHCI_BUFPAGELEN) + 1) * GRUB_EHCI_BUFPAGELEN; + } + + /* Remember data size for future use... */ + td->size = (grub_uint32_t) size; + + grub_dprintf ("ehci", "td=%08x\n", (grub_uint32_t) td); + grub_dprintf ("ehci", "HW: next_td=%08x, alt_next_td=%08x\n", + grub_le_to_cpu32 (td->next_td), + grub_le_to_cpu32 (td->alt_next_td)); + grub_dprintf ("ehci", "HW: token=%08x, buffer[0]=%08x\n", + grub_le_to_cpu32 (td->token), + grub_le_to_cpu32 (td->buffer_page[0])); + grub_dprintf ("ehci", "HW: buffer[1]=%08x, buffer[2]=%08x\n", + grub_le_to_cpu32 (td->buffer_page[1]), + grub_le_to_cpu32 (td->buffer_page[2])); + grub_dprintf ("ehci", "HW: buffer[3]=%08x, buffer[4]=%08x\n", + grub_le_to_cpu32 (td->buffer_page[3]), + grub_le_to_cpu32 (td->buffer_page[4])); + grub_dprintf ("ehci", "link_td=%08x, size=%08x\n", + td->link_td, td->size); + + return td; +} + +struct grub_ehci_transfer_controller_data +{ + grub_ehci_qh_t qh_virt; + grub_ehci_td_t td_first_virt; + grub_ehci_td_t td_alt_virt; + grub_ehci_td_t td_last_virt; +}; + +static grub_usb_err_t +grub_ehci_setup_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ehci *e = (struct grub_ehci *) dev->data; + grub_ehci_td_t td = NULL; + grub_ehci_td_t td_prev = NULL; + int i; + struct grub_ehci_transfer_controller_data *cdata; + + /* Check if EHCI is running and AL is enabled */ + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_HC_HALTED) != 0) + /* XXX: Fix it: Currently we don't do anything to restart EHCI */ + return GRUB_USB_ERR_INTERNAL; + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_AS_STATUS) == 0) + /* XXX: Fix it: Currently we don't do anything to restart EHCI */ + return GRUB_USB_ERR_INTERNAL; + + /* Check if transfer is not high speed and connected to root hub. + * It should not happened but... */ + if ((transfer->dev->speed != GRUB_USB_SPEED_HIGH) + && !transfer->dev->hubaddr) + { + grub_error (GRUB_USB_ERR_BADDEVICE, + "FULL/LOW speed device on EHCI port!?!"); + return GRUB_USB_ERR_BADDEVICE; + } + + /* Allocate memory for controller transfer data. */ + cdata = grub_malloc (sizeof (*cdata)); + if (!cdata) + return GRUB_USB_ERR_INTERNAL; + cdata->td_first_virt = NULL; + + /* Allocate a queue head for the transfer queue. */ + cdata->qh_virt = grub_ehci_find_qh (e, transfer); + if (!cdata->qh_virt) + { + grub_free (cdata); + return GRUB_USB_ERR_INTERNAL; + } + + /* To detect short packet we need some additional "alternate" TD, + * allocate it first. */ + cdata->td_alt_virt = grub_ehci_alloc_td (e); + if (!cdata->td_alt_virt) + { + grub_free (cdata); + return GRUB_USB_ERR_INTERNAL; + } + /* Fill whole alternate TD by zeros (= inactive) and set + * Terminate bits and Halt bit */ + grub_memset ((void *) cdata->td_alt_virt, 0, sizeof (struct grub_ehci_td)); + cdata->td_alt_virt->next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + cdata->td_alt_virt->alt_next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + cdata->td_alt_virt->token = grub_cpu_to_le32 (GRUB_EHCI_STATUS_HALTED); + + /* Allocate appropriate number of TDs and set */ + for (i = 0; i < transfer->transcnt; i++) + { + grub_usb_transaction_t tr = &transfer->transactions[i]; + + td = grub_ehci_transaction (e, tr->pid, tr->toggle, tr->size, + tr->data, cdata->td_alt_virt); + + if (!td) /* de-allocate and free all */ + { + grub_size_t actual = 0; + + if (cdata->td_first_virt) + grub_ehci_free_tds (e, cdata->td_first_virt, NULL, &actual); + + grub_free (cdata); + return GRUB_USB_ERR_INTERNAL; + } + + /* Register new TD in cdata or previous TD */ + if (!cdata->td_first_virt) + cdata->td_first_virt = td; + else + { + td_prev->link_td = grub_dma_virt2phys (td, e->td_chunk); + td_prev->next_td = + grub_cpu_to_le32 (grub_dma_virt2phys (td, e->td_chunk)); + } + td_prev = td; + } + + /* Remember last TD */ + cdata->td_last_virt = td; + /* Last TD should not have set alternate TD */ + cdata->td_last_virt->alt_next_td = grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + + grub_dprintf ("ehci", "setup_transfer: cdata=%08x, qh=%08x\n", + (grub_uint32_t) cdata, (grub_uint32_t) cdata->qh_virt); + grub_dprintf ("ehci", "setup_transfer: td_first=%08x, td_alt=%08x\n", + (grub_uint32_t) cdata->td_first_virt, + (grub_uint32_t) cdata->td_alt_virt); + grub_dprintf ("ehci", "setup_transfer: td_last=%08x\n", + (grub_uint32_t) cdata->td_last_virt); + + /* Start transfer: */ + /* Unlink possible alternate pointer in QH */ + cdata->qh_virt->td_overlay.alt_next_td = + grub_cpu_to_le32 (GRUB_EHCI_TERMINATE); + /* Link new TDs with QH via next_td */ + cdata->qh_virt->td_overlay.next_td = + grub_cpu_to_le32 (grub_dma_virt2phys + (cdata->td_first_virt, e->td_chunk)); + /* Reset Active and Halted bits in QH to activate Advance Queue, + * i.e. reset token */ + cdata->qh_virt->td_overlay.token = grub_cpu_to_le32 (0); + + /* Finito */ + transfer->controller_data = cdata; + + return GRUB_USB_ERR_NONE; +} + +/* This function expects QH is not active. + * Function set Halt bit in QH TD overlay and possibly prints + * necessary debug information. */ +static void +grub_ehci_pre_finish_transfer (grub_usb_transfer_t transfer) +{ + struct grub_ehci_transfer_controller_data *cdata = + transfer->controller_data; + + /* Collect debug data here if necessary */ + + /* Set Halt bit in not active QH. AL will not attempt to do + * Advance Queue on QH with Halt bit set, i.e., we can then + * safely manipulate with QH TD part. */ + cdata->qh_virt->td_overlay.token = (cdata->qh_virt->td_overlay.token + | + grub_cpu_to_le32 + (GRUB_EHCI_STATUS_HALTED)) & + grub_cpu_to_le32 (~GRUB_EHCI_STATUS_ACTIVE); + + /* Print debug data here if necessary */ + +} + +static grub_usb_err_t +grub_ehci_parse_notrun (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, grub_size_t * actual) +{ + struct grub_ehci *e = dev->data; + struct grub_ehci_transfer_controller_data *cdata = + transfer->controller_data; + + grub_dprintf ("ehci", "parse_notrun: info\n"); + + /* QH can be in any state in this case. */ + /* But EHCI or AL is not running, so QH is surely not active + * even if it has Active bit set... */ + grub_ehci_pre_finish_transfer (transfer); + grub_ehci_free_tds (e, cdata->td_first_virt, transfer, actual); + grub_ehci_free_td (e, cdata->td_alt_virt); + grub_free (cdata); + + /* Additionally, do something with EHCI to make it running (what?) */ + /* Try enable EHCI and AL */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_RUNSTOP | GRUB_EHCI_CMD_AS_ENABL + | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + /* Ensure command is written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND); + + return GRUB_USB_ERR_UNRECOVERABLE; +} + +static grub_usb_err_t +grub_ehci_parse_halt (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, grub_size_t * actual) +{ + struct grub_ehci *e = dev->data; + struct grub_ehci_transfer_controller_data *cdata = + transfer->controller_data; + grub_uint32_t token; + grub_usb_err_t err = GRUB_USB_ERR_NAK; + + /* QH should be halted and not active in this case. */ + + grub_dprintf ("ehci", "parse_halt: info\n"); + + /* Remember token before call pre-finish function */ + token = grub_le_to_cpu32 (cdata->qh_virt->td_overlay.token); + + /* Do things like in normal finish */ + grub_ehci_pre_finish_transfer (transfer); + grub_ehci_free_tds (e, cdata->td_first_virt, transfer, actual); + grub_ehci_free_td (e, cdata->td_alt_virt); + grub_free (cdata); + + /* Evaluation of error code - currently we don't have GRUB USB error + * codes for some EHCI states, GRUB_USB_ERR_DATA is used for them. + * Order of evaluation is critical, specially bubble/stall. */ + if ((token & GRUB_EHCI_STATUS_BABBLE) != 0) + err = GRUB_USB_ERR_BABBLE; + else if ((token & GRUB_EHCI_CERR_MASK) != 0) + err = GRUB_USB_ERR_STALL; + else if ((token & GRUB_EHCI_STATUS_TRANERR) != 0) + err = GRUB_USB_ERR_DATA; + else if ((token & GRUB_EHCI_STATUS_BUFERR) != 0) + err = GRUB_USB_ERR_DATA; + else if ((token & GRUB_EHCI_STATUS_MISSDMF) != 0) + err = GRUB_USB_ERR_DATA; + + return err; +} + +static grub_usb_err_t +grub_ehci_parse_success (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, grub_size_t * actual) +{ + struct grub_ehci *e = dev->data; + struct grub_ehci_transfer_controller_data *cdata = + transfer->controller_data; + + grub_dprintf ("ehci", "parse_success: info\n"); + + /* QH should be not active in this case, but it is not halted. */ + grub_ehci_pre_finish_transfer (transfer); + grub_ehci_free_tds (e, cdata->td_first_virt, transfer, actual); + grub_ehci_free_td (e, cdata->td_alt_virt); + grub_free (cdata); + + return GRUB_USB_ERR_NONE; +} + + +static grub_usb_err_t +grub_ehci_check_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, grub_size_t * actual) +{ + struct grub_ehci *e = dev->data; + struct grub_ehci_transfer_controller_data *cdata = + transfer->controller_data; + grub_uint32_t token; + + grub_dprintf ("ehci", + "check_transfer: EHCI STATUS=%08x, cdata=%08x, qh=%08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS), + (grub_uint32_t) cdata, (grub_uint32_t) cdata->qh_virt); + grub_dprintf ("ehci", "check_transfer: qh_hptr=%08x, ep_char=%08x\n", + grub_le_to_cpu32 (cdata->qh_virt->qh_hptr), + grub_le_to_cpu32 (cdata->qh_virt->ep_char)); + grub_dprintf ("ehci", "check_transfer: ep_cap=%08x, td_current=%08x\n", + grub_le_to_cpu32 (cdata->qh_virt->ep_cap), + grub_le_to_cpu32 (cdata->qh_virt->td_current)); + grub_dprintf ("ehci", "check_transfer: next_td=%08x, alt_next_td=%08x\n", + grub_le_to_cpu32 (cdata->qh_virt->td_overlay.next_td), + grub_le_to_cpu32 (cdata->qh_virt->td_overlay.alt_next_td)); + grub_dprintf ("ehci", "check_transfer: token=%08x, buffer[0]=%08x\n", + grub_le_to_cpu32 (cdata->qh_virt->td_overlay.token), + grub_le_to_cpu32 (cdata->qh_virt->td_overlay.buffer_page[0])); + + /* Check if EHCI is running and AL is enabled */ + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_HC_HALTED) != 0) + return grub_ehci_parse_notrun (dev, transfer, actual); + if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_AS_STATUS) == 0) + return grub_ehci_parse_notrun (dev, transfer, actual); + + token = grub_le_to_cpu32 (cdata->qh_virt->td_overlay.token); + + /* Detect QH halted */ + if ((token & GRUB_EHCI_STATUS_HALTED) != 0) + return grub_ehci_parse_halt (dev, transfer, actual); + + /* Detect QH not active - QH is not active and no next TD */ + if ((token & GRUB_EHCI_STATUS_ACTIVE) == 0) + { + /* It could be finish at all or short packet condition */ + if ((grub_le_to_cpu32 (cdata->qh_virt->td_overlay.next_td) + & GRUB_EHCI_TERMINATE) && + ((grub_le_to_cpu32 (cdata->qh_virt->td_current) + & GRUB_EHCI_QHTDPTR_MASK) == (grub_uint32_t) cdata->td_last_virt)) + /* Normal finish */ + return grub_ehci_parse_success (dev, transfer, actual); + else if ((token & GRUB_EHCI_TOTAL_MASK) != 0) + /* Short packet condition */ + /* But currently we don't handle it - higher level will do it */ + return grub_ehci_parse_success (dev, transfer, actual); + } + + return GRUB_USB_ERR_WAIT; +} + +static grub_usb_err_t +grub_ehci_cancel_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ehci *e = dev->data; + struct grub_ehci_transfer_controller_data *cdata = + transfer->controller_data; + grub_size_t actual; + int i; + grub_uint64_t maxtime; + + /* QH can be active and should be de-activated and halted */ + + grub_dprintf ("ehci", "cancel_transfer: begin\n"); + + /* First check if EHCI is running and AL is enabled and if not, + * there is no problem... */ + if (((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_HC_HALTED) != 0) || + ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_AS_STATUS) == 0)) + { + grub_ehci_pre_finish_transfer (transfer); + grub_ehci_free_tds (e, cdata->td_first_virt, transfer, &actual); + grub_ehci_free_td (e, cdata->td_alt_virt); + grub_free (cdata); + grub_dprintf ("ehci", "cancel_transfer: end - EHCI not running\n"); + return GRUB_USB_ERR_NONE; + } + + /* EHCI and AL are running. What to do? + * Try to Halt QH via de-scheduling QH. */ + /* Find index of current QH - we need previous QH, i.e. i-1 */ + i = ((int) (e->qh_virt - cdata->qh_virt)) / sizeof (struct grub_ehci_qh); + /* Unlink QH from AL */ + e->qh_virt[i - 1].qh_hptr = cdata->qh_virt->qh_hptr; + /* Ring the doorbell */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_AS_ADV_D + | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + /* Ensure command is written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND); + /* Wait answer with timeout */ + maxtime = grub_get_time_ms () + 2; + while (((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) + & GRUB_EHCI_ST_AS_ADVANCE) == 0) + && (grub_get_time_ms () < maxtime)); + + /* We do not detect the timeout because if timeout occurs, it most + * probably means something wrong with EHCI - maybe stopped etc. */ + + /* Shut up the doorbell */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + ~GRUB_EHCI_CMD_AS_ADV_D + & grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + grub_ehci_oper_write32 (e, GRUB_EHCI_STATUS, + GRUB_EHCI_ST_AS_ADVANCE + | grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)); + /* Ensure command is written */ + grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS); + + /* Now is QH out of AL and we can do anything with it... */ + grub_ehci_pre_finish_transfer (transfer); + grub_ehci_free_tds (e, cdata->td_first_virt, transfer, &actual); + grub_ehci_free_td (e, cdata->td_alt_virt); + + /* Finaly we should return QH back to the AL... */ + e->qh_virt[i - 1].qh_hptr = + grub_cpu_to_le32 (grub_dma_virt2phys + (cdata->qh_virt, e->qh_chunk)); + grub_free (cdata); + + grub_dprintf ("ehci", "cancel_transfer: end\n"); + + return GRUB_USB_ERR_NONE; +} + +static int +grub_ehci_hubports (grub_usb_controller_t dev) +{ + struct grub_ehci *e = (struct grub_ehci *) dev->data; + grub_uint32_t portinfo; + + portinfo = grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS) + & GRUB_EHCI_SPARAMS_N_PORTS; + grub_dprintf ("ehci", "root hub ports=%d\n", portinfo); + return portinfo; +} + +static grub_err_t +grub_ehci_portstatus (grub_usb_controller_t dev, + unsigned int port, unsigned int enable) +{ + struct grub_ehci *e = (struct grub_ehci *) dev->data; + grub_uint64_t endtime; + + grub_dprintf ("ehci", "portstatus: EHCI STATUS: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)); + grub_dprintf ("ehci", + "portstatus: begin, iobase=0x%02x, port=%d, status=0x%02x\n", + (grub_uint32_t) e->iobase, port, grub_ehci_port_read (e, + port)); + + /* In any case we need to disable port: + * - if enable==false - we should disable port + * - if enable==true we will do the reset and the specification says + * PortEnable should be FALSE in such case */ + /* Disable the port and wait for it. */ + grub_ehci_port_resbits (e, port, GRUB_EHCI_PORT_ENABLED); + endtime = grub_get_time_ms () + 1000; + while (grub_ehci_port_read (e, port) & GRUB_EHCI_PORT_ENABLED) + if (grub_get_time_ms () > endtime) + return grub_error (GRUB_ERR_IO, "portstatus: EHCI Timed out - disable"); + + if (!enable) /* We don't need reset port */ + { + grub_dprintf ("ehci", "portstatus: Disabled.\n"); + grub_dprintf ("ehci", "portstatus: end, status=0x%02x\n", + grub_ehci_port_read (e, port)); + return GRUB_ERR_NONE; + } + + grub_dprintf ("ehci", "portstatus: enable\n"); + + /* Now we will do reset - if HIGH speed device connected, it will + * result in Enabled state, otherwise port remains disabled. */ + /* Set RESET bit for 50ms */ + grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_RESET); + grub_millisleep (50); + + /* Reset RESET bit and wait for the end of reset */ + grub_ehci_port_resbits (e, port, GRUB_EHCI_PORT_RESET); + endtime = grub_get_time_ms () + 1000; + while (grub_ehci_port_read (e, port) & GRUB_EHCI_PORT_RESET) + if (grub_get_time_ms () > endtime) + return grub_error (GRUB_ERR_IO, + "portstatus: EHCI Timed out - reset port"); + /* Remember "we did the reset" - needed by detect_dev */ + e->reset |= (1 << port); + /* Test if port enabled, i.e. HIGH speed device connected */ + if ((grub_ehci_port_read (e, port) & GRUB_EHCI_PORT_ENABLED) != 0) /* yes! */ + { + grub_dprintf ("ehci", "portstatus: Enabled!\n"); + /* "Reset recovery time" (USB spec.) */ + grub_millisleep (10); + } + else /* no... */ + { + /* FULL speed device connected - change port ownership. + * It results in disconnected state of this EHCI port. */ + grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_OWNER); + return GRUB_USB_ERR_BADDEVICE; + } + + /* XXX: Fix it! There is possible problem - we can say to calling + * function that we lost device if it is FULL speed onlu via + * return value <> GRUB_ERR_NONE. It (maybe) displays also error + * message on screen - but this situation is not error, it is normal + * state! */ + + grub_dprintf ("ehci", "portstatus: end, status=0x%02x\n", + grub_ehci_port_read (e, port)); + + return GRUB_ERR_NONE; +} + +static grub_usb_speed_t +grub_ehci_detect_dev (grub_usb_controller_t dev, int port, int *changed) +{ + struct grub_ehci *e = (struct grub_ehci *) dev->data; + grub_uint32_t status, line_state; + + status = grub_ehci_port_read (e, port); + + grub_dprintf ("ehci", "detect_dev: EHCI STATUS: %08x\n", + grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)); + grub_dprintf ("ehci", "detect_dev: iobase=0x%02x, port=%d, status=0x%02x\n", + (grub_uint32_t) e->iobase, port, status); + + /* Connect Status Change bit - it detects change of connection */ + if (status & GRUB_EHCI_PORT_CONNECT_CH) + { + *changed = 1; + /* Reset bit Connect Status Change */ + grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_CONNECT_CH); + } + else + *changed = 0; + + if (!(status & GRUB_EHCI_PORT_CONNECT)) + { /* We should reset related "reset" flag in not connected state */ + e->reset &= ~(1 << port); + return GRUB_USB_SPEED_NONE; + } + /* Detected connected state, so we should return speed. + * But we can detect only LOW speed device and only at connection + * time when PortEnabled=FALSE. FULL / HIGH speed detection is made + * later by EHCI-specific reset procedure. + * Another thing - if detected speed is LOW at connection time, + * we should change port ownership to companion controller. + * So: + * 1. If we detect connected and enabled and EHCI-owned port, + * we can say it is HIGH speed. + * 2. If we detect connected and not EHCI-owned port, we can say + * NONE speed, because such devices are not handled by EHCI. + * 3. If we detect connected, not enabled but reset port, we can say + * NONE speed, because it means FULL device connected to port and + * such devices are not handled by EHCI. + * 4. If we detect connected, not enabled and not reset port, which + * has line state != "K", we will say HIGH - it could be FULL or HIGH + * device, we will see it later after end of EHCI-specific reset + * procedure. + * 5. If we detect connected, not enabled and not reset port, which + * has line state == "K", we can say NONE speed, because LOW speed + * device is connected and we should change port ownership. */ + if ((status & GRUB_EHCI_PORT_ENABLED) != 0) /* Port already enabled, return high speed. */ + return GRUB_USB_SPEED_HIGH; + if ((status & GRUB_EHCI_PORT_OWNER) != 0) /* EHCI is not port owner */ + return GRUB_USB_SPEED_NONE; /* EHCI driver is ignoring this port. */ + if ((e->reset & (1 << port)) != 0) /* Port reset was done = FULL speed */ + return GRUB_USB_SPEED_NONE; /* EHCI driver is ignoring this port. */ + else /* Port connected but not enabled - test port speed. */ + { + line_state = status & GRUB_EHCI_PORT_LINE_STAT; + if (line_state != GRUB_EHCI_PORT_LINE_LOWSP) + return GRUB_USB_SPEED_HIGH; + /* Detected LOW speed device, we should change + * port ownership. + * XXX: Fix it!: There should be test if related companion + * controler is available ! And what to do if it does not exist ? */ + grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_OWNER); + return GRUB_USB_SPEED_NONE; /* Ignore this port */ + /* Note: Reset of PORT_OWNER bit is done by EHCI HW when + * device is really disconnected from port. + * Don't do PORT_OWNER bit reset by SW when not connected signal + * is detected in port register ! */ + } +} + +static void +grub_ehci_inithw (void) +{ + grub_pci_iterate (grub_ehci_pci_iter); +} + +static grub_err_t +grub_ehci_restore_hw (void) +{ + struct grub_ehci *e; + grub_uint32_t n_ports; + int i; + + /* We should re-enable all EHCI HW similarly as on inithw */ + for (e = ehci; e; e = e->next) + { + /* Check if EHCI is halted and halt it if not */ + if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE) + grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI halt timeout"); + + /* Reset EHCI */ + if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE) + grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI reset timeout"); + + /* Setup some EHCI registers and enable EHCI */ + grub_ehci_oper_write32 (e, GRUB_EHCI_FL_BASE, e->framelist_phys); + grub_ehci_oper_write32 (e, GRUB_EHCI_CUR_AL_ADDR, + grub_dma_virt2phys (&e->qh_virt[1], + e->qh_chunk)); + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_RUNSTOP | + grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + + /* Set ownership of root hub ports to EHCI */ + grub_ehci_oper_write32 (e, GRUB_EHCI_CONFIG_FLAG, + GRUB_EHCI_CF_EHCI_OWNER); + + /* Enable asynchronous list */ + grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND, + GRUB_EHCI_CMD_AS_ENABL + | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)); + + /* Now should be possible to power-up and enumerate ports etc. */ + if ((grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS) + & GRUB_EHCI_SPARAMS_PPC) != 0) + { /* EHCI has port powering control */ + /* Power on all ports */ + n_ports = grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS) + & GRUB_EHCI_SPARAMS_N_PORTS; + for (i = 0; i < (int) n_ports; i++) + grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + i * 4, + GRUB_EHCI_PORT_POWER + | grub_ehci_oper_read32 (e, + GRUB_EHCI_PORT_STAT_CMD + + i * 4)); + } + } + + return GRUB_USB_ERR_NONE; +} + +static grub_err_t +grub_ehci_fini_hw (int noreturn __attribute__ ((unused))) +{ + struct grub_ehci *e; + + /* We should disable all EHCI HW to prevent any DMA access etc. */ + for (e = ehci; e; e = e->next) + { + /* Check if EHCI is halted and halt it if not */ + if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE) + grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI halt timeout"); + + /* Reset EHCI */ + if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE) + grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI reset timeout"); + } + + return GRUB_USB_ERR_NONE; +} + +static struct grub_usb_controller_dev usb_controller = { + .name = "ehci", + .iterate = grub_ehci_iterate, + .setup_transfer = grub_ehci_setup_transfer, + .check_transfer = grub_ehci_check_transfer, + .cancel_transfer = grub_ehci_cancel_transfer, + .hubports = grub_ehci_hubports, + .portstatus = grub_ehci_portstatus, + .detect_dev = grub_ehci_detect_dev +}; + +GRUB_MOD_INIT (ehci) +{ + COMPILE_TIME_ASSERT (sizeof (struct grub_ehci_td) == 64); + COMPILE_TIME_ASSERT (sizeof (struct grub_ehci_qh) == 96); + grub_ehci_inithw (); + grub_usb_controller_dev_register (&usb_controller); + grub_loader_register_preboot_hook (grub_ehci_fini_hw, grub_ehci_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); +} + +GRUB_MOD_FINI (ehci) +{ + grub_ehci_fini_hw (0); + grub_usb_controller_dev_unregister (&usb_controller); +} diff --git a/grub-core/bus/usb/emu/usb.c b/grub-core/bus/usb/emu/usb.c index 7d52decb2..38c5f01f1 100644 --- a/grub-core/bus/usb/emu/usb.c +++ b/grub-core/bus/usb/emu/usb.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static struct grub_usb_controller_dev usb_controller = { diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index 3c3ce4b89..3f5ca7b03 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_ohci_hcca { /* Pointers to Interrupt Endpoint Descriptors. Not used by @@ -220,7 +222,6 @@ grub_ohci_pci_iter (grub_pci_device_t dev, grub_pci_address_t addr; struct grub_ohci *o; grub_uint32_t revision; - int cs5536; int j; /* Determine IO base address. */ @@ -230,7 +231,6 @@ grub_ohci_pci_iter (grub_pci_device_t dev, { grub_uint64_t basereg; - cs5536 = 1; basereg = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_USB_OHCI_BASE); if (!(basereg & GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE)) { @@ -454,10 +454,12 @@ grub_ohci_pci_iter (grub_pci_device_t dev, fail: if (o) - grub_dma_free (o->td_chunk); - grub_dma_free (o->ed_bulk_chunk); - grub_dma_free (o->ed_ctrl_chunk); - grub_dma_free (o->hcca_chunk); + { + grub_dma_free (o->td_chunk); + grub_dma_free (o->ed_bulk_chunk); + grub_dma_free (o->ed_ctrl_chunk); + grub_dma_free (o->hcca_chunk); + } grub_free (o); return 0; @@ -1150,8 +1152,8 @@ grub_ohci_check_transfer (grub_usb_controller_t dev, return parse_halt (dev, transfer, actual); /* Finished ED detection */ - if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf) == - (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf) ) /* Empty ED */ + if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xfU) == + (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xfU) ) /* Empty ED */ { /* Check the HALT bit */ /* It looks like nonsense - it was tested previously... @@ -1424,18 +1426,22 @@ static struct grub_usb_controller_dev usb_controller = .detect_dev = grub_ohci_detect_dev }; +static struct grub_preboot *fini_hnd; + 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, - GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); + fini_hnd = grub_loader_register_preboot_hook (grub_ohci_fini_hw, + grub_ohci_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); } GRUB_MOD_FINI(ohci) { grub_ohci_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); grub_usb_controller_dev_unregister (&usb_controller); } diff --git a/grub-core/bus/usb/serial/common.c b/grub-core/bus/usb/serial/common.c index ee8794de0..55d1884cc 100644 --- a/grub-core/bus/usb/serial/common.c +++ b/grub-core/bus/usb/serial/common.c @@ -18,6 +18,9 @@ #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); void grub_usbserial_fini (struct grub_serial_port *port) diff --git a/grub-core/bus/usb/serial/ftdi.c b/grub-core/bus/usb/serial/ftdi.c index bd1713b27..07ac7ac52 100644 --- a/grub-core/bus/usb/serial/ftdi.c +++ b/grub-core/bus/usb/serial/ftdi.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + enum { GRUB_FTDI_MODEM_CTRL = 0x01, diff --git a/grub-core/bus/usb/serial/pl2303.c b/grub-core/bus/usb/serial/pl2303.c index 9e3b9ae7e..b9954116b 100644 --- a/grub-core/bus/usb/serial/pl2303.c +++ b/grub-core/bus/usb/serial/pl2303.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Convert speed to divisor. */ static grub_uint32_t is_speed_supported (unsigned int speed) diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index d082beac4..a9a4c45a2 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_UHCI_IOMASK (0x7FF << 5) #define N_QH 256 @@ -34,11 +36,33 @@ typedef enum { GRUB_UHCI_REG_USBCMD = 0x00, + GRUB_UHCI_REG_USBINTR = 0x04, GRUB_UHCI_REG_FLBASEADD = 0x08, GRUB_UHCI_REG_PORTSC1 = 0x10, - GRUB_UHCI_REG_PORTSC2 = 0x12 + GRUB_UHCI_REG_PORTSC2 = 0x12, + GRUB_UHCI_REG_USBLEGSUP = 0xc0 } grub_uhci_reg_t; +/* R/WC legacy support bits */ +#define GRUB_UHCI_LEGSUP_END_A20GATE (1 << 15) +#define GRUB_UHCI_TRAP_BY_64H_WSTAT (1 << 11) +#define GRUB_UHCI_TRAP_BY_64H_RSTAT (1 << 10) +#define GRUB_UHCI_TRAP_BY_60H_WSTAT (1 << 9) +#define GRUB_UHCI_TRAP_BY_60H_RSTAT (1 << 8) + +/* Reset all legacy support - clear all R/WC bits and all R/W bits */ +#define GRUB_UHCI_RESET_LEGSUP_SMI ( GRUB_UHCI_LEGSUP_END_A20GATE \ + | GRUB_UHCI_TRAP_BY_64H_WSTAT \ + | GRUB_UHCI_TRAP_BY_64H_RSTAT \ + | GRUB_UHCI_TRAP_BY_60H_WSTAT \ + | GRUB_UHCI_TRAP_BY_60H_RSTAT ) + +/* Some UHCI commands */ +#define GRUB_UHCI_CMD_RUN_STOP (1 << 0) +#define GRUB_UHCI_CMD_HCRESET (1 << 1) +#define GRUB_UHCI_CMD_MAXP (1 << 7) + +/* Important bits in structures */ #define GRUB_UHCI_LINK_TERMINATE 1 #define GRUB_UHCI_LINK_QUEUE_HEAD 2 @@ -179,6 +203,11 @@ grub_uhci_pci_iter (grub_pci_device_t dev, if (class != 0x0c || subclass != 0x03 || interf != 0x00) return 0; + /* Set bus master - needed for coreboot or broken BIOSes */ + addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); + grub_pci_write_word(addr, + GRUB_PCI_COMMAND_BUS_MASTER | grub_pci_read_word(addr)); + /* Determine IO base address. */ addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4); base = grub_pci_read (addr); @@ -193,6 +222,19 @@ grub_uhci_pci_iter (grub_pci_device_t dev, u->iobase = base & GRUB_UHCI_IOMASK; + /* Reset PIRQ and SMI */ + addr = grub_pci_make_address (dev, GRUB_UHCI_REG_USBLEGSUP); + grub_pci_write_word(addr, GRUB_UHCI_RESET_LEGSUP_SMI); + /* Reset the HC */ + grub_uhci_writereg16(u, GRUB_UHCI_REG_USBCMD, GRUB_UHCI_CMD_HCRESET); + grub_millisleep(5); + /* Disable interrupts and commands (just to be safe) */ + grub_uhci_writereg16(u, GRUB_UHCI_REG_USBINTR, 0); + /* Finish HC reset, HC remains disabled */ + grub_uhci_writereg16(u, GRUB_UHCI_REG_USBCMD, 0); + /* Read back to be sure PCI write is done */ + grub_uhci_readreg16(u, GRUB_UHCI_REG_USBCMD); + /* Reserve a page for the frame list. */ u->framelist = grub_memalign (4096, 4096); if (! u->framelist) @@ -250,9 +292,6 @@ grub_uhci_pci_iter (grub_pci_device_t dev, u->td[N_TD - 2].linkptr = 0; u->tdfree = u->td; - /* Make sure UHCI is disabled! */ - grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0); - /* Setup the frame list pointers. Since no isochronous transfers are and will be supported, they all point to the (same!) queue head. */ @@ -283,7 +322,8 @@ grub_uhci_pci_iter (grub_pci_device_t dev, u->qh[N_QH - 1].linkptr = 1; /* Enable UHCI again. */ - grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7)); + grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, + GRUB_UHCI_CMD_RUN_STOP | GRUB_UHCI_CMD_MAXP); /* UHCI is initialized and ready for transfers. */ grub_dprintf ("uhci", "UHCI initialized\n"); @@ -504,8 +544,11 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev, { grub_size_t actual = 0; /* Terminate and free. */ - td_prev->linkptr2 = 0; - td_prev->linkptr = 1; + if (td_prev) + { + td_prev->linkptr2 = 0; + td_prev->linkptr = 1; + } if (cdata->td_first) grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual); @@ -749,8 +792,7 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) else if (port == 1) reg = GRUB_UHCI_REG_PORTSC2; else - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "UHCI Root Hub port does not exist"); + return GRUB_USB_SPEED_NONE; status = grub_uhci_readreg16 (u, reg); diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c index 2bd805ef2..fb04e6572 100644 --- a/grub-core/bus/usb/usb.c +++ b/grub-core/bus/usb/usb.c @@ -24,8 +24,10 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_usb_controller_dev_t grub_usb_list; -struct grub_usb_attach_desc *attach_hooks; +static struct grub_usb_attach_desc *attach_hooks; void grub_usb_controller_dev_register (grub_usb_controller_dev_t usb) @@ -183,6 +185,12 @@ grub_usb_device_initialize (grub_usb_device_t dev) for (i = 0; i < 8; i++) dev->config[i].descconf = NULL; + if (descdev->configcnt == 0) + { + err = GRUB_USB_ERR_BADDEVICE; + goto fail; + } + for (i = 0; i < descdev->configcnt; i++) { int pos; @@ -332,7 +340,7 @@ grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc) void grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc) { - grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc)); + grub_list_remove (GRUB_AS_LIST (desc)); } diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c index f08910d2b..ee85232de 100644 --- a/grub-core/bus/usb/usbhub.c +++ b/grub-core/bus/usb/usbhub.c @@ -39,12 +39,14 @@ struct grub_usb_hub grub_usb_device_t dev; }; -struct grub_usb_hub *hubs; +static struct grub_usb_hub *hubs; /* Add a device that currently has device number 0 and resides on CONTROLLER, the Hub reported that the device speed is SPEED. */ static grub_usb_device_t -grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) +grub_usb_hub_add_dev (grub_usb_controller_t controller, + grub_usb_speed_t speed, + int port, int hubaddr) { grub_usb_device_t dev; int i; @@ -56,6 +58,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) dev->controller = *controller; dev->speed = speed; + dev->port = port; + dev->hubaddr = hubaddr; err = grub_usb_device_initialize (dev); if (err) @@ -97,6 +101,11 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) dev->initialized = 1; grub_usb_devs[i] = dev; + grub_dprintf ("usb", "Added new usb device: %08x, addr=%d\n", + (grub_uint32_t)dev, i); + grub_dprintf ("usb", "speed=%d, port=%d, hubaddr=%d\n", + speed, port, hubaddr); + /* Wait "recovery interval", spec. says 2ms */ grub_millisleep (2); @@ -110,7 +119,7 @@ static grub_usb_err_t grub_usb_add_hub (grub_usb_device_t dev) { struct grub_usb_usb_hubdesc hubdesc; - grub_err_t err; + grub_usb_err_t err; int i; err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN @@ -158,11 +167,13 @@ grub_usb_add_hub (grub_usb_device_t dev) if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) == GRUB_USB_EP_INTERRUPT) { + grub_size_t len; dev->hub_endpoint = endp; + len = endp->maxpacket; + if (len > sizeof (dev->statuschange)) + len = sizeof (dev->statuschange); dev->hub_transfer - = grub_usb_bulk_read_background (dev, endp->endp_addr, - grub_min (endp->maxpacket, - sizeof (dev->statuschange)), + = grub_usb_bulk_read_background (dev, endp->endp_addr, len, (char *) &dev->statuschange); break; } @@ -215,8 +226,10 @@ attach_root_port (struct grub_usb_hub *hub, int portno, return; hub->controller->dev->pending_reset = grub_get_time_ms () + 5000; + grub_millisleep (10); + /* Enable the port and create a device. */ - dev = grub_usb_hub_add_dev (hub->controller, speed); + dev = grub_usb_hub_add_dev (hub->controller, speed, portno, 0); hub->controller->dev->pending_reset = 0; if (! dev) return; @@ -312,7 +325,7 @@ poll_nonroot_hub (grub_usb_device_t dev) grub_usb_err_t err; unsigned i; grub_uint8_t changed; - grub_size_t actual; + grub_size_t actual, len; int j, total; if (!dev->hub_transfer) @@ -325,10 +338,11 @@ poll_nonroot_hub (grub_usb_device_t dev) changed = dev->statuschange; + len = dev->hub_endpoint->maxpacket; + if (len > sizeof (dev->statuschange)) + len = sizeof (dev->statuschange); dev->hub_transfer - = grub_usb_bulk_read_background (dev, dev->hub_endpoint->endp_addr, - grub_min (dev->hub_endpoint->maxpacket, - sizeof (dev->statuschange)), + = grub_usb_bulk_read_background (dev, dev->hub_endpoint->endp_addr, len, (char *) &dev->statuschange); if (err || actual == 0 || changed == 0) @@ -350,7 +364,7 @@ poll_nonroot_hub (grub_usb_device_t dev) GRUB_USB_REQ_GET_STATUS, 0, i, sizeof (status), (char *) &status); - grub_printf ("dev = %p, i = %d, status = %08x\n", + grub_dprintf ("usb", "dev = %p, i = %d, status = %08x\n", dev, i, status); if (err) @@ -470,7 +484,7 @@ poll_nonroot_hub (grub_usb_device_t dev) grub_millisleep (10); /* Add the device and assign a device address to it. */ - next_dev = grub_usb_hub_add_dev (&dev->controller, speed); + next_dev = grub_usb_hub_add_dev (&dev->controller, speed, i, dev->addr); dev->controller.dev->pending_reset = 0; if (! next_dev) continue; diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c index ebb8a2eb6..167fae5a2 100644 --- a/grub-core/bus/usb/usbtrans.c +++ b/grub-core/bus/usb/usbtrans.c @@ -97,7 +97,7 @@ grub_usb_control_msg (grub_usb_device_t dev, if (! transfer) { grub_dma_free (data_chunk); - return grub_errno; + return GRUB_USB_ERR_INTERNAL; } setupdata_chunk = grub_memalign_dma32 (32, sizeof (*setupdata)); @@ -105,7 +105,7 @@ grub_usb_control_msg (grub_usb_device_t dev, { grub_free (transfer); grub_dma_free (data_chunk); - return grub_errno; + return GRUB_USB_ERR_INTERNAL; } setupdata = grub_dma_get_virt (setupdata_chunk); @@ -139,7 +139,7 @@ grub_usb_control_msg (grub_usb_device_t dev, grub_free (transfer); grub_dma_free (setupdata_chunk); grub_dma_free (data_chunk); - return grub_errno; + return GRUB_USB_ERR_INTERNAL; } /* Build a Setup packet. XXX: Endianness. */ diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index 4f03997e0..048f8c0cb 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -33,6 +33,8 @@ #include #endif +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"exclude", 'x', 0, N_("Don't load host tables specified by comma-separated list."), @@ -136,6 +138,7 @@ iszero (grub_uint8_t *reg, int size) return 1; } +#if defined (__i386__) || defined (__x86_64__) grub_err_t grub_acpi_create_ebda (void) { @@ -163,7 +166,7 @@ grub_acpi_create_ebda (void) return 0; } - ebda = (grub_uint8_t *) UINT_TO_PTR ((*((grub_uint16_t *)0x40e)) << 4); + ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4); ebda_kb_len = *(grub_uint16_t *) ebda; if (! ebda || ebda_kb_len > 16) ebda_kb_len = 0; @@ -171,14 +174,14 @@ grub_acpi_create_ebda (void) /* FIXME: use low-memory mm allocation once it's available. */ grub_mmap_iterate (find_hook); - targetebda = (grub_uint8_t *) UINT_TO_PTR (highestlow); + targetebda = (grub_uint8_t *) (grub_addr_t) highestlow; grub_dprintf ("acpi", "creating ebda @%llx\n", (unsigned long long) highestlow); if (! highestlow) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't find space for the new EBDA"); - mmapregion = grub_mmap_register (PTR_TO_UINT64 (targetebda), ebda_len, + mmapregion = grub_mmap_register ((grub_addr_t) targetebda, ebda_len, GRUB_MEMORY_RESERVED); if (! mmapregion) return grub_errno; @@ -295,6 +298,7 @@ grub_acpi_create_ebda (void) return GRUB_ERR_NONE; } +#endif /* Create tables common to ACPIv1 and ACPIv2+ */ static void @@ -326,13 +330,13 @@ setup_common_tables (void) if (grub_memcmp (fadt->hdr.signature, GRUB_ACPI_FADT_SIGNATURE, sizeof (fadt->hdr.signature)) == 0) { - fadt->dsdt_addr = PTR_TO_UINT32 (table_dsdt); + fadt->dsdt_addr = (grub_addr_t) table_dsdt; fadt->facs_addr = facs_addr; /* Does a revision 2 exist at all? */ if (fadt->hdr.revision >= 3) { - fadt->dsdt_xaddr = PTR_TO_UINT64 (table_dsdt); + fadt->dsdt_xaddr = (grub_addr_t) table_dsdt; fadt->facs_xaddr = facs_addr; } @@ -363,7 +367,7 @@ setup_common_tables (void) rsdt->creator_rev = root_creator_rev; for (cur = acpi_tables; cur; cur = cur->next) - *(rsdt_entry++) = PTR_TO_UINT32 (cur->addr); + *(rsdt_entry++) = (grub_addr_t) cur->addr; /* Recompute checksum. */ rsdt->checksum = 0; @@ -381,7 +385,7 @@ setv1table (void) sizeof (rsdpv1_new->signature)); grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid)); rsdpv1_new->revision = 0; - rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (rsdt_addr); + rsdpv1_new->rsdt_addr = (grub_addr_t) rsdt_addr; rsdpv1_new->checksum = 0; rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new, sizeof (*rsdpv1_new)); @@ -406,7 +410,7 @@ setv2table (void) xsdt_entry = (grub_uint64_t *)(xsdt + 1); for (cur = acpi_tables; cur; cur = cur->next) - *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr); + *(xsdt_entry++) = (grub_addr_t) cur->addr; grub_memcpy (&(xsdt->signature), "XSDT", 4); xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables; xsdt->revision = 1; @@ -426,12 +430,12 @@ setv2table (void) grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid, sizeof (rsdpv2_new->rsdpv1.oemid)); rsdpv2_new->rsdpv1.revision = rev2; - rsdpv2_new->rsdpv1.rsdt_addr = PTR_TO_UINT32 (rsdt_addr); + rsdpv2_new->rsdpv1.rsdt_addr = (grub_addr_t) rsdt_addr; rsdpv2_new->rsdpv1.checksum = 0; rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum (&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1)); rsdpv2_new->length = sizeof (*rsdpv2_new); - rsdpv2_new->xsdt_addr = PTR_TO_UINT64 (xsdt); + rsdpv2_new->xsdt_addr = (grub_addr_t) xsdt; rsdpv2_new->checksum = 0; rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new, rsdpv2_new->length); @@ -461,7 +465,6 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) struct grub_arg_list *state = ctxt->state; struct grub_acpi_rsdp_v10 *rsdp; struct efiemu_acpi_table *cur, *t; - grub_err_t err; int i, mmapregion; int numoftables; @@ -504,7 +507,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) /* Set revision variables to replicate the same version as host. */ rev1 = ! rsdp->revision; rev2 = rsdp->revision; - rsdt = (struct grub_acpi_table_header *) UINT_TO_PTR (rsdp->rsdt_addr); + rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp->rsdt_addr; /* Load host tables. */ for (entry_ptr = (grub_uint32_t *) (rsdt + 1); entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt) @@ -514,7 +517,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) char signature[5]; struct efiemu_acpi_table *table; struct grub_acpi_table_header *curtable - = (struct grub_acpi_table_header *) UINT_TO_PTR (*entry_ptr); + = (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr; signature[4] = 0; for (i = 0; i < 4;i++) signature[i] = grub_tolower (curtable->signature[i]); @@ -538,7 +541,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) /* Load DSDT if not excluded. */ dsdt = (struct grub_acpi_table_header *) - UINT_TO_PTR (fadt->dsdt_addr); + (grub_addr_t) fadt->dsdt_addr; if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt")) && (! load_only || grub_strword (load_only, "dsdt")) && dsdt->length >= sizeof (*dsdt)) @@ -646,15 +649,17 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) { grub_file_close (file); free_tables (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "couldn't read file %s", args[i]); + return grub_errno; } if (grub_file_read (file, buf, size) != (int) size) { grub_file_close (file); free_tables (); - return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + args[i]); + return grub_errno; } grub_file_close (file); @@ -730,13 +735,20 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) } acpi_tables = 0; - if (! state[9].set && (err = grub_acpi_create_ebda ())) +#if defined (__i386__) || defined (__x86_64__) + if (! state[9].set) { - rsdpv1_new = 0; - rsdpv2_new = 0; - grub_mmap_free_and_unregister (mmapregion); - return err; + grub_err_t err; + err = grub_acpi_create_ebda (); + if (err) + { + rsdpv1_new = 0; + rsdpv2_new = 0; + grub_mmap_free_and_unregister (mmapregion); + return err; + } } +#endif #ifdef GRUB_MACHINE_EFI { diff --git a/grub-core/commands/acpihalt.c b/grub-core/commands/acpihalt.c index a39635677..177ec15f0 100644 --- a/grub-core/commands/acpihalt.c +++ b/grub-core/commands/acpihalt.c @@ -16,9 +16,30 @@ * along with GRUB. If not, see . */ +#ifdef GRUB_DSDT_TEST +#include +#include +#include +#include +#include + +#define grub_dprintf(cond, args...) printf ( args ) +#define grub_printf printf +typedef uint64_t grub_uint64_t; +typedef uint32_t grub_uint32_t; +typedef uint16_t grub_uint16_t; +typedef uint8_t grub_uint8_t; + +#endif + #include +#include + +#ifndef GRUB_DSDT_TEST #include +#include #include +#endif static inline grub_uint32_t decode_length (const grub_uint8_t *ptr, int *numlen) @@ -123,6 +144,7 @@ skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end) return 0; break; case GRUB_ACPI_EXTOPCODE_FIELD_OP: + case GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP: ptr++; ptr += decode_length (ptr, 0); break; @@ -156,11 +178,12 @@ get_sleep_type (grub_uint8_t *table, grub_uint8_t *end) break; case GRUB_ACPI_OPCODE_NAME: ptr++; - if (memcmp (ptr, "_S5_", 4) == 0) + if (memcmp (ptr, "_S5_", 4) == 0 || memcmp (ptr, "\\_S5_", 4) == 0) { int ll; grub_uint8_t *ptr2 = ptr; - ptr2 += 4; + grub_dprintf ("acpi", "S5 found\n"); + ptr2 += skip_name_string (ptr, end); if (*ptr2 != 0x12) { grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2); @@ -208,6 +231,47 @@ get_sleep_type (grub_uint8_t *table, grub_uint8_t *end) return sleep_type; } +#ifdef GRUB_DSDT_TEST +int +main (int argc, char **argv) +{ + FILE *f; + size_t len; + unsigned char *buf; + if (argc < 2) + printf ("Usage: %s FILE\n", argv[0]); + f = fopen (argv[1], "rb"); + if (!f) + { + printf ("Couldn't open file\n"); + return 1; + } + fseek (f, 0, SEEK_END); + len = ftell (f); + fseek (f, 0, SEEK_SET); + buf = malloc (len); + if (!buf) + { + printf ("Couldn't malloc buffer\n"); + fclose (f); + return 2; + } + if (fread (buf, 1, len, f) != len) + { + printf ("Read failed\n"); + free (buf); + fclose (f); + return 2; + } + + printf ("Sleep type = %d\n", get_sleep_type (buf, buf + len)); + free (buf); + fclose (f); + return 0; +} + +#else + void grub_acpi_halt (void) { @@ -262,5 +326,8 @@ grub_acpi_halt (void) } } - grub_printf ("ACPI shutdown failed\n"); + grub_millisleep (1500); + + grub_puts_ (N_("ACPI shutdown failed")); } +#endif diff --git a/grub-core/commands/i386/pc/pxecmd.c b/grub-core/commands/arc/lsdev.c similarity index 57% rename from grub-core/commands/i386/pc/pxecmd.c rename to grub-core/commands/arc/lsdev.c index b576a8ea4..5d4b0cd09 100644 --- a/grub-core/commands/i386/pc/pxecmd.c +++ b/grub-core/commands/arc/lsdev.c @@ -1,7 +1,6 @@ -/* pxe.c - command to control the pxe driver */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2011 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 @@ -18,35 +17,37 @@ */ #include -#include #include -#include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_err_t -grub_cmd_pxe_unload (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) +grub_cmd_lsdev (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) { - if (! grub_pxe_pxenv) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment"); - - grub_pxe_unload (); - + auto int hook (const char *name, const struct grub_arc_component *comp); + int hook (const char *name, const struct grub_arc_component *comp __attribute__ ((unused))) + { + grub_printf ("%s\n", name); + return 0; + } + grub_arc_iterate_devs (hook, 0); return 0; } static grub_command_t cmd; -GRUB_MOD_INIT(pxecmd) +GRUB_MOD_INIT(lsdev) { - cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload, - 0, - N_("Unload PXE environment.")); + cmd = grub_register_command ("lsdev", grub_cmd_lsdev, "", + N_("List devices.")); } -GRUB_MOD_FINI(pxecmd) +GRUB_MOD_FINI(lsdev) { grub_unregister_command (cmd); } diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c index 4651fb32a..5eb12e434 100644 --- a/grub-core/commands/blocklist.c +++ b/grub-core/commands/blocklist.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c index 1ec1e6f77..5149074c7 100644 --- a/grub-core/commands/boot.c +++ b/grub-core/commands/boot.c @@ -25,21 +25,23 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t (*grub_loader_boot_func) (void); static grub_err_t (*grub_loader_unload_func) (void); static int grub_loader_noreturn; -struct grub_preboot_t +struct grub_preboot { grub_err_t (*preboot_func) (int); grub_err_t (*preboot_rest_func) (void); grub_loader_preboot_hook_prio_t prio; - struct grub_preboot_t *next; - struct grub_preboot_t *prev; + struct grub_preboot *next; + struct grub_preboot *prev; }; static int grub_loader_loaded; -static struct grub_preboot_t *preboots_head = 0, +static struct grub_preboot *preboots_head = 0, *preboots_tail = 0; int @@ -49,18 +51,18 @@ grub_loader_is_loaded (void) } /* Register a preboot hook. */ -void * +struct grub_preboot * grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn), grub_err_t (*preboot_rest_func) (void), grub_loader_preboot_hook_prio_t prio) { - struct grub_preboot_t *cur, *new_preboot; + struct grub_preboot *cur, *new_preboot; if (! preboot_func && ! preboot_rest_func) return 0; - new_preboot = (struct grub_preboot_t *) - grub_malloc (sizeof (struct grub_preboot_t)); + new_preboot = (struct grub_preboot *) + grub_malloc (sizeof (struct grub_preboot)); if (! new_preboot) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "hook not added"); @@ -94,9 +96,9 @@ grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn), } void -grub_loader_unregister_preboot_hook (void *hnd) +grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) { - struct grub_preboot_t *preb = hnd; + struct grub_preboot *preb = hnd; if (preb->next) preb->next->prev = preb->prev; @@ -141,7 +143,7 @@ grub_err_t grub_loader_boot (void) { grub_err_t err = GRUB_ERR_NONE; - struct grub_preboot_t *cur; + struct grub_preboot *cur; if (! grub_loader_loaded) return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel"); diff --git a/grub-core/commands/cacheinfo.c b/grub-core/commands/cacheinfo.c new file mode 100644 index 000000000..92aaa218d --- /dev/null +++ b/grub-core/commands/cacheinfo.c @@ -0,0 +1,58 @@ +/* cacheinfo.c - disk cache statistics */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +static grub_err_t +grub_rescue_cmd_info (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + unsigned long hits, misses; + + grub_disk_cache_get_performance (&hits, &misses); + grub_printf_ (N_("Disk cache: hits = %lu, misses = %lu "), hits, misses); + if (hits + misses) + { + unsigned long ratio = hits * 10000 / (hits + misses); + grub_printf ("(%lu.%lu%%)\n", ratio / 100, ratio % 100); + } + else + grub_puts_ (N_("(N/A)")); + + return 0; +} + +static grub_command_t cmd_cacheinfo; + +GRUB_MOD_INIT(cacheinfo) +{ + cmd_cacheinfo = + grub_register_command ("cacheinfo", grub_rescue_cmd_info, + 0, N_("Get disk cache info.")); +} + +GRUB_MOD_FINI(cacheinfo) +{ + grub_unregister_command (cmd_cacheinfo); +} diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c index 79ecf75c7..9be6cbc8f 100644 --- a/grub-core/commands/cat.c +++ b/grub-core/commands/cat.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"dos", -1, 0, N_("Accept DOS-style CR/NL line endings."), 0, 0}, diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c index d9e76a4d7..5d5925dd5 100644 --- a/grub-core/commands/cmp.c +++ b/grub-core/commands/cmp.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define BUFFER_SIZE 512 static grub_err_t @@ -40,8 +42,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required"); - grub_printf ("Compare file `%s' with `%s':\n", args[0], - args[1]); + grub_printf_ (N_("Compare file `%s' with `%s':\n"), args[0], + args[1]); file1 = grub_file_open (args[0]); file2 = grub_file_open (args[1]); @@ -49,9 +51,9 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), goto cleanup; if (grub_file_size (file1) != grub_file_size (file2)) - grub_printf ("Files differ in size: %llu [%s], %llu [%s]\n", - (unsigned long long) grub_file_size (file1), args[0], - (unsigned long long) grub_file_size (file2), args[1]); + grub_printf_ (N_("Files differ in size: %llu [%s], %llu [%s]\n"), + (unsigned long long) grub_file_size (file1), args[0], + (unsigned long long) grub_file_size (file2), args[1]); else { pos = 0; @@ -76,9 +78,9 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), { if (buf1[i] != buf2[i]) { - grub_printf ("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n", - (unsigned long long) (i + pos), buf1[i], args[0], - buf2[i], args[1]); + grub_printf_ (N_("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n"), + (unsigned long long) (i + pos), buf1[i], + args[0], buf2[i], args[1]); goto cleanup; } } @@ -87,15 +89,14 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), } while (rd2); - grub_printf ("The files are identical.\n"); + /* TRANSLATORS: it's always exactly 2 files. */ + grub_printf_ (N_("The files are identical.\n")); } cleanup: - if (buf1) - grub_free (buf1); - if (buf2) - grub_free (buf2); + grub_free (buf1); + grub_free (buf2); if (file1) grub_file_close (file1); if (file2) diff --git a/grub-core/commands/configfile.c b/grub-core/commands/configfile.c index 2568b7ee6..124a09a9e 100644 --- a/grub-core/commands/configfile.c +++ b/grub-core/commands/configfile.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_source (grub_command_t cmd, int argc, char **args) { diff --git a/grub-core/commands/date.c b/grub-core/commands/date.c index 623db4943..d27162077 100644 --- a/grub-core/commands/date.c +++ b/grub-core/commands/date.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_DATETIME_SET_YEAR 1 #define GRUB_DATETIME_SET_MONTH 2 #define GRUB_DATETIME_SET_DAY 4 diff --git a/grub-core/commands/echo.c b/grub-core/commands/echo.c index 13bc1c3fd..81ba50d68 100644 --- a/grub-core/commands/echo.c +++ b/grub-core/commands/echo.c @@ -1,7 +1,7 @@ /* echo.c - Command to display a line of text */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2006,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 @@ -21,6 +21,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static const struct grub_arg_option options[] = { @@ -43,8 +46,14 @@ grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) for (i = 0; i < argc; i++) { char *arg = *args; + /* Unescaping results in a string no longer than the original. */ + char *unescaped = grub_malloc (grub_strlen (arg) + 1); + char *p = unescaped; args++; + if (!unescaped) + return grub_errno; + while (*arg) { /* In case `-e' is used, parse backslashes. */ @@ -57,11 +66,11 @@ grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) switch (*arg) { case '\\': - grub_printf ("\\"); + *p++ = '\\'; break; case 'a': - grub_printf ("\a"); + *p++ = '\a'; break; case 'c': @@ -69,23 +78,23 @@ grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) break; case 'f': - grub_printf ("\f"); + *p++ = '\f'; break; case 'n': - grub_printf ("\n"); + *p++ = '\n'; break; case 'r': - grub_printf ("\r"); + *p++ = '\r'; break; case 't': - grub_printf ("\t"); + *p++ = '\t'; break; case 'v': - grub_printf ("\v"); + *p++ = '\v'; break; } arg++; @@ -94,10 +103,14 @@ grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) /* This was not an escaped character, or escaping is not enabled. */ - grub_printf ("%c", *arg); + *p++ = *arg; arg++; } + *p = '\0'; + grub_xputs (unescaped); + grub_free (unescaped); + /* If another argument follows, insert a space. */ if (i != argc - 1) grub_printf (" " ); @@ -106,6 +119,8 @@ grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) if (newline) grub_printf ("\n"); + grub_refresh (); + return 0; } diff --git a/grub-core/commands/efi/fixvideo.c b/grub-core/commands/efi/fixvideo.c index 6430be5e3..a58c27916 100644 --- a/grub-core/commands/efi/fixvideo.c +++ b/grub-core/commands/efi/fixvideo.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static struct grub_video_patch { const char *name; @@ -54,24 +56,24 @@ scan_card (grub_pci_device_t dev, grub_pci_id_t pciid) { grub_target_addr_t base; - grub_printf ("Found graphic card: %s\n", p->name); + grub_dprintf ("fixvideo", "Found graphic card: %s\n", p->name); addr += 8 + p->mmio_bar * 4; base = grub_pci_read (addr); if ((! base) || (base & GRUB_PCI_ADDR_SPACE_IO) || (base & GRUB_PCI_ADDR_MEM_PREFETCH)) - grub_printf ("Invalid MMIO bar %d\n", p->mmio_bar); + grub_dprintf ("fixvideo", "Invalid MMIO bar %d\n", p->mmio_bar); else { base &= GRUB_PCI_ADDR_MEM_MASK; base += p->mmio_reg; if (*((volatile grub_uint32_t *) base) != p->mmio_old) - grub_printf ("Old value don't match\n"); + grub_dprintf ("fixvideo", "Old value doesn't match\n"); else { *((volatile grub_uint32_t *) base) = 0; if (*((volatile grub_uint32_t *) base)) - grub_printf ("Set MMIO fails\n"); + grub_dprintf ("fixvideo", "Setting MMIO fails\n"); } } @@ -80,7 +82,7 @@ scan_card (grub_pci_device_t dev, grub_pci_id_t pciid) p++; } - grub_printf ("Unknown graphic card: %x\n", pciid); + grub_dprintf ("fixvideo", "Unknown graphic card: %x\n", pciid); } return 0; diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c index 8c7c25abd..5eb490fd4 100644 --- a/grub-core/commands/efi/loadbios.c +++ b/grub-core/commands/efi/loadbios.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID; @@ -47,7 +49,7 @@ enable_rom_area (void) rom_ptr = (grub_uint32_t *) VBIOS_ADDR; if (*rom_ptr != BLANK_MEM) { - grub_printf ("ROM image is present.\n"); + grub_puts_ (N_("ROM image is present.")); return 0; } @@ -65,7 +67,7 @@ enable_rom_area (void) *rom_ptr = 0; if (*rom_ptr != 0) { - grub_printf ("Can\'t enable ROM area.\n"); + grub_puts_ (N_("Can\'t enable ROM area.")); return 0; } @@ -207,7 +209,7 @@ GRUB_MOD_INIT(loadbios) 0, N_("Fake BIOS.")); cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, - "BIOS_DUMP [INT10_DUMP]", + N_("BIOS_DUMP [INT10_DUMP]"), N_("Load BIOS dump.")); } diff --git a/grub-core/commands/efi/lsefimmap.c b/grub-core/commands/efi/lsefimmap.c index 2bb5dcb5d..215b45bff 100644 --- a/grub-core/commands/efi/lsefimmap.c +++ b/grub-core/commands/efi/lsefimmap.c @@ -23,6 +23,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define ADD_MEMORY_DESCRIPTOR(desc, size) \ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) diff --git a/grub-core/commands/efi/lsefisystab.c b/grub-core/commands/efi/lsefisystab.c index aa3e05aee..b2359253a 100644 --- a/grub-core/commands/efi/lsefisystab.c +++ b/grub-core/commands/efi/lsefisystab.c @@ -18,12 +18,15 @@ */ #include #include +#include #include #include #include #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct guid_mapping { grub_efi_guid_t guid; diff --git a/grub-core/commands/efi/lssal.c b/grub-core/commands/efi/lssal.c index 2ee993033..fa8005b88 100644 --- a/grub-core/commands/efi/lssal.c +++ b/grub-core/commands/efi/lssal.c @@ -23,6 +23,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static void disp_sal (void *table) diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c index e9274fbab..69574e2b0 100644 --- a/grub-core/commands/extcmd.c +++ b/grub-core/commands/extcmd.c @@ -22,6 +22,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); grub_err_t grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, diff --git a/grub-core/commands/gptsync.c b/grub-core/commands/gptsync.c index 6364c13f7..88d4b6296 100644 --- a/grub-core/commands/gptsync.c +++ b/grub-core/commands/gptsync.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Convert a LBA address to a CHS address in the INT 13 format. */ /* Taken from grub1. */ /* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63. @@ -229,7 +231,7 @@ grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)), return grub_errno; } - grub_printf ("New MBR is written to '%s'\n", args[0]); + grub_printf_ (N_("New MBR is written to '%s'\n"), args[0]); return GRUB_ERR_NONE; } diff --git a/grub-core/commands/halt.c b/grub-core/commands/halt.c index 3400115a0..f8596ecdc 100644 --- a/grub-core/commands/halt.c +++ b/grub-core/commands/halt.c @@ -22,13 +22,14 @@ #include #include -static grub_err_t +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_err_t __attribute__ ((noreturn)) grub_cmd_halt (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { grub_halt (); - return 0; } static grub_command_t cmd; diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c index 8b6806e45..fb737c2f8 100644 --- a/grub-core/commands/hashsum.c +++ b/grub-core/commands/hashsum.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING}, {"check", 'c', 0, N_("Check hash list file."), N_("FILE"), ARG_TYPE_STRING}, @@ -36,7 +38,7 @@ static const struct grub_arg_option options[] = { {0, 0, 0, 0, 0, 0} }; -struct { const char *name; const char *hashname; } aliases[] = +static struct { const char *name; const char *hashname; } aliases[] = { {"sha256sum", "sha256"}, {"sha512sum", "sha512"}, @@ -139,7 +141,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, grub_file_close (file); if (err) { - grub_printf ("%s: READ ERROR\n", p); + grub_printf_ (N_("%s: READ ERROR\n"), p); if (!keep) { grub_file_close (hashlist); @@ -153,7 +155,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, } if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0) { - grub_printf ("%s: HASH MISMATCH\n", p); + grub_printf_ (N_("%s: HASH MISMATCH\n"), p); if (!keep) { grub_file_close (hashlist); @@ -164,7 +166,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, mismatch++; continue; } - grub_printf ("%s: OK\n", p); + grub_printf_ (N_("%s: OK\n"), p); } if (mismatch || unread) return grub_error (GRUB_ERR_TEST_FAILURE, @@ -255,8 +257,8 @@ static grub_extcmd_t cmd, cmd_md5, cmd_sha1, cmd_sha256, cmd_sha512, cmd_crc; GRUB_MOD_INIT(hashsum) { cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, 0, - "hashsum -h HASH [-c FILE [-p PREFIX]] " - "[FILE1 [FILE2 ...]]", + N_("-h HASH [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), N_("Compute or check hash checksum."), options); cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0, diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c index b6ab78755..85189e8bc 100644 --- a/grub-core/commands/hdparm.c +++ b/grub-core/commands/hdparm.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -26,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"apm", 'B', 0, N_("Set Advanced Power Management\n" "(1=low, ..., 254=high, 255=off)."), @@ -61,60 +64,64 @@ enum grub_ata_smart_commands static int quiet = 0; static grub_err_t -grub_hdparm_do_ata_cmd (grub_disk_t disk, grub_uint8_t cmd, +grub_hdparm_do_ata_cmd (grub_ata_t ata, grub_uint8_t cmd, grub_uint8_t features, grub_uint8_t sectors, void * buffer, int size) { struct grub_disk_ata_pass_through_parms apt; grub_memset (&apt, 0, sizeof (apt)); - apt.taskfile[GRUB_ATA_REG_CMD] = cmd; - apt.taskfile[GRUB_ATA_REG_FEATURES] = features; - apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors; + apt.taskfile.cmd = cmd; + apt.taskfile.features = features; + apt.taskfile.sectors = sectors; + apt.taskfile.disk = 0xE0; + apt.buffer = buffer; apt.size = size; - if (grub_disk_ata_pass_through (disk, &apt)) + if (ata->dev->readwrite (ata, &apt, 0)) return grub_errno; return GRUB_ERR_NONE; } static int -grub_hdparm_do_check_powermode_cmd (grub_disk_t disk) +grub_hdparm_do_check_powermode_cmd (grub_ata_t ata) { struct grub_disk_ata_pass_through_parms apt; grub_memset (&apt, 0, sizeof (apt)); - apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE; + apt.taskfile.cmd = GRUB_ATA_CMD_CHECK_POWER_MODE; + apt.taskfile.disk = 0xE0; - if (grub_disk_ata_pass_through (disk, &apt)) + if (ata->dev->readwrite (ata, &apt, 0)) return -1; - return apt.taskfile[GRUB_ATA_REG_SECTORS]; + return apt.taskfile.sectors; } static int -grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features) +grub_hdparm_do_smart_cmd (grub_ata_t ata, grub_uint8_t features) { struct grub_disk_ata_pass_through_parms apt; grub_memset (&apt, 0, sizeof (apt)); - apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_SMART; - apt.taskfile[GRUB_ATA_REG_FEATURES] = features; - apt.taskfile[GRUB_ATA_REG_LBAMID] = 0x4f; - apt.taskfile[GRUB_ATA_REG_LBAHIGH] = 0xc2; + apt.taskfile.cmd = GRUB_ATA_CMD_SMART; + apt.taskfile.features = features; + apt.taskfile.lba_mid = 0x4f; + apt.taskfile.lba_high = 0xc2; + apt.taskfile.disk = 0xE0; - if (grub_disk_ata_pass_through (disk, &apt)) + if (ata->dev->readwrite (ata, &apt, 0)) return -1; if (features == GRUB_ATA_FEAT_SMART_STATUS) { - if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0x4f - && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2) + if ( apt.taskfile.lba_mid == 0x4f + && apt.taskfile.lba_high == 0xc2) return 0; /* Good SMART status. */ - else if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0xf4 - && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c) + else if ( apt.taskfile.lba_mid == 0xf4 + && apt.taskfile.lba_high == 0x2c) return 1; /* Bad SMART status. */ else return -1; @@ -124,12 +131,12 @@ grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features) static grub_err_t grub_hdparm_simple_cmd (const char * msg, - grub_disk_t disk, grub_uint8_t cmd) + grub_ata_t ata, grub_uint8_t cmd) { if (! quiet && msg) grub_printf ("%s", msg); - grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, 0); + grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, 0, 0, NULL, 0); if (! quiet && msg) grub_printf ("%s\n", ! err ? "" : ": not supported"); @@ -138,7 +145,7 @@ grub_hdparm_simple_cmd (const char * msg, static grub_err_t grub_hdparm_set_val_cmd (const char * msg, int val, - grub_disk_t disk, grub_uint8_t cmd, + grub_ata_t ata, grub_uint8_t cmd, grub_uint8_t features, grub_uint8_t sectors) { if (! quiet && msg && *msg) @@ -149,7 +156,7 @@ grub_hdparm_set_val_cmd (const char * msg, int val, grub_printf ("Disable %s", msg); } - grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors, + grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, features, sectors, NULL, 0); if (! quiet && msg) @@ -158,22 +165,20 @@ grub_hdparm_set_val_cmd (const char * msg, int val, } static const char * -le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes) +le16_to_char (grub_uint16_t *dest, const grub_uint16_t * src16, unsigned bytes) { - grub_uint16_t * dest16 = (grub_uint16_t *) dest; unsigned i; for (i = 0; i < bytes / 2; i++) - dest16[i] = grub_be_to_cpu16 (src16[i]); - return dest; + dest[i] = grub_be_to_cpu16 (src16[i]); + dest[i] = 0; + return (char *) dest; } static void -grub_hdparm_print_identify (const char * idbuf) +grub_hdparm_print_identify (const grub_uint16_t * idw) { - const grub_uint16_t * idw = (const grub_uint16_t *) idbuf; - /* Print identity strings. */ - char tmp[40]; + grub_uint16_t tmp[21]; grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40)); grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp, &idw[23], 8)); grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20)); @@ -273,6 +278,7 @@ static grub_err_t grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? { struct grub_arg_list *state = ctxt->state; + struct grub_ata *ata; /* Check command line. */ if (argc != 1) @@ -283,9 +289,6 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name"); args[0][len - 1] = 0; - if (! grub_disk_ata_pass_through) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available"); - int i = 0; int apm = get_int_arg (&state[i++]); int power = state[i++].set; @@ -311,15 +314,37 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed"); } + switch (disk->dev->id) + { + case GRUB_DISK_DEVICE_ATA_ID: + ata = disk->data; + break; + case GRUB_DISK_DEVICE_SCSI_ID: + if (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF) + == GRUB_SCSI_SUBSYSTEM_PATA + || (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF) + == GRUB_SCSI_SUBSYSTEM_AHCI)) + { + ata = ((struct grub_scsi *) disk->data)->data; + break; + } + default: + return grub_error (GRUB_ERR_IO, "not an ATA device"); + } + + /* Change settings. */ if (aam >= 0) grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1), - disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam); + ata, GRUB_ATA_CMD_SET_FEATURES, + (aam ? 0x42 : 0xc2), aam); if (apm >= 0) grub_hdparm_set_val_cmd ("Advanced Power Management", - (apm != 255 ? apm : -1), disk, GRUB_ATA_CMD_SET_FEATURES, - (apm != 255 ? 0x05 : 0x85), (apm != 255 ? apm : 0)); + (apm != 255 ? apm : -1), ata, + GRUB_ATA_CMD_SET_FEATURES, + (apm != 255 ? 0x05 : 0x85), + (apm != 255 ? apm : 0)); if (standby_tout >= 0) { @@ -330,28 +355,28 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? grub_printf (")"); } /* The IDLE cmd sets disk to idle mode and configures standby timer. */ - grub_hdparm_set_val_cmd ("", -1, disk, GRUB_ATA_CMD_IDLE, 0, standby_tout); + grub_hdparm_set_val_cmd ("", -1, ata, GRUB_ATA_CMD_IDLE, 0, standby_tout); } if (enable_smart >= 0) { if (! quiet) grub_printf ("%sable SMART operations", (enable_smart ? "En" : "Dis")); - int err = grub_hdparm_do_smart_cmd (disk, (enable_smart ? + int err = grub_hdparm_do_smart_cmd (ata, (enable_smart ? GRUB_ATA_FEAT_SMART_ENABLE : GRUB_ATA_FEAT_SMART_DISABLE)); if (! quiet) grub_printf ("%s\n", err ? ": not supported" : ""); } if (sec_freeze) - grub_hdparm_simple_cmd ("Freeze security settings", disk, + grub_hdparm_simple_cmd ("Freeze security settings", ata, GRUB_ATA_CMD_SECURITY_FREEZE_LOCK); /* Print/dump IDENTIFY. */ if (ident || dumpid) { - char buf[GRUB_DISK_SECTOR_SIZE]; - if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_IDENTIFY_DEVICE, + grub_uint16_t buf[GRUB_DISK_SECTOR_SIZE / 2]; + if (grub_hdparm_do_ata_cmd (ata, GRUB_ATA_CMD_IDENTIFY_DEVICE, 0, 0, buf, sizeof (buf))) grub_printf ("Cannot read ATA IDENTIFY data\n"); else @@ -359,7 +384,7 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? if (ident) grub_hdparm_print_identify (buf); if (dumpid) - hexdump (0, buf, sizeof (buf)); + hexdump (0, (char *) buf, sizeof (buf)); } } @@ -367,7 +392,7 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? if (power) { grub_printf ("Disk power mode is: "); - int mode = grub_hdparm_do_check_powermode_cmd (disk); + int mode = grub_hdparm_do_check_powermode_cmd (ata); if (mode < 0) grub_printf ("unknown\n"); else @@ -383,7 +408,7 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? { if (! quiet) grub_printf ("SMART status is: "); - int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS); + int err = grub_hdparm_do_smart_cmd (ata, GRUB_ATA_FEAT_SMART_STATUS); if (! quiet) grub_printf ("%s\n", (err < 0 ? "unknown" : err == 0 ? "OK" : "*BAD*")); @@ -392,11 +417,11 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? /* Change power mode. */ if (standby_now) - grub_hdparm_simple_cmd ("Set disk to standby mode", disk, + grub_hdparm_simple_cmd ("Set disk to standby mode", ata, GRUB_ATA_CMD_STANDBY_IMMEDIATE); if (sleep_now) - grub_hdparm_simple_cmd ("Set disk to sleep mode", disk, + grub_hdparm_simple_cmd ("Set disk to sleep mode", ata, GRUB_ATA_CMD_SLEEP); grub_disk_close (disk); diff --git a/grub-core/commands/help.c b/grub-core/commands/help.c index ff6d7ed2e..82f3200c7 100644 --- a/grub-core/commands/help.c +++ b/grub-core/commands/help.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_help (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc, char **args) diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c index 629f2a069..9ba83598a 100644 --- a/grub-core/commands/hexdump.c +++ b/grub-core/commands/hexdump.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"skip", 's', 0, N_("Skip offset bytes from the beginning of file."), 0, ARG_TYPE_INT}, diff --git a/grub-core/commands/i386/cmostest.c b/grub-core/commands/i386/cmostest.c index 994da11b0..6a4290155 100644 --- a/grub-core/commands/i386/cmostest.c +++ b/grub-core/commands/i386/cmostest.c @@ -20,6 +20,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_err_t parse_args (int argc, char *argv[], int *byte, int *bit) @@ -44,12 +47,17 @@ grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)), { int byte, bit; grub_err_t err; + grub_uint8_t value; err = parse_args (argc, argv, &byte, &bit); if (err) return err; - if (grub_cmos_read (byte) & (1 << bit)) + err = grub_cmos_read (byte, &value); + if (err) + return err; + + if (value & (1 << bit)) return GRUB_ERR_NONE; return grub_error (GRUB_ERR_TEST_FAILURE, "false"); @@ -61,13 +69,16 @@ grub_cmd_cmosclean (struct grub_command *cmd __attribute__ ((unused)), { int byte, bit; grub_err_t err; + grub_uint8_t value; err = parse_args (argc, argv, &byte, &bit); + if (err) + return err; + err = grub_cmos_read (byte, &value); if (err) return err; - grub_cmos_write (byte, grub_cmos_read (byte) & (~(1 << bit))); - return GRUB_ERR_NONE; + return grub_cmos_write (byte, value & (~(1 << bit))); } static grub_command_t cmd, cmd_clean; @@ -76,11 +87,11 @@ static grub_command_t cmd, cmd_clean; GRUB_MOD_INIT(cmostest) { cmd = grub_register_command ("cmostest", grub_cmd_cmostest, - "cmostest BYTE:BIT", - "Test bit at BYTE:BIT in CMOS."); + N_("BYTE:BIT"), + N_("Test bit at BYTE:BIT in CMOS.")); cmd_clean = grub_register_command ("cmosclean", grub_cmd_cmosclean, - "cmosclean BYTE:BIT", - "Clean bit at BYTE:BIT in CMOS."); + N_("BYTE:BIT"), + N_("Clean bit at BYTE:BIT in CMOS.")); } GRUB_MOD_FINI(cmostest) diff --git a/grub-core/commands/i386/cpuid.c b/grub-core/commands/i386/cpuid.c index f5f0f15a8..6a771ba74 100644 --- a/grub-core/commands/i386/cpuid.c +++ b/grub-core/commands/i386/cpuid.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define cpuid(num,a,b,c,d) \ asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ diff --git a/grub-core/commands/i386/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c index ed4211cca..6e82be437 100644 --- a/grub-core/commands/i386/pc/drivemap.c +++ b/grub-core/commands/i386/pc/drivemap.c @@ -29,9 +29,10 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */ -static grub_uint32_t *const int13slot = UINT_TO_PTR (4 * 0x13); +static grub_uint32_t *const int13slot = (grub_uint32_t *) (4 * 0x13); /* Remember to update enum opt_idxs accordingly. */ static const struct grub_arg_option options[] = { @@ -177,11 +178,11 @@ list_mappings (void) /* Show: list mappings. */ if (! map_head) { - grub_printf ("No drives have been remapped\n"); + grub_puts_ (N_("No drives have been remapped")); return GRUB_ERR_NONE; } - grub_printf ("OS disk #num ------> GRUB/BIOS device\n"); + grub_puts_ (N_("OS disk #num ------> GRUB/BIOS device")); drivemap_node_t *curnode = map_head; while (curnode) { @@ -362,7 +363,7 @@ uninstall_int13_handler (void) static int grub_get_root_biosnumber_drivemap (void) { - char *biosnum; + const char *biosnum; int ret = -1; grub_device_t dev; diff --git a/grub-core/commands/i386/pc/halt.c b/grub-core/commands/i386/pc/halt.c index 81eb6a1bb..e7c191de3 100644 --- a/grub-core/commands/i386/pc/halt.c +++ b/grub-core/commands/i386/pc/halt.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"no-apm", 'n', 0, N_("Do not use APM to halt the computer."), 0, 0}, diff --git a/grub-core/commands/i386/pc/lsapm.c b/grub-core/commands/i386/pc/lsapm.c index 30475d2ec..45b43b242 100644 --- a/grub-core/commands/i386/pc/lsapm.c +++ b/grub-core/commands/i386/pc/lsapm.c @@ -22,6 +22,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + int grub_apm_get_info (struct grub_apm_info *info) { @@ -72,27 +74,27 @@ grub_cmd_lsapm (grub_command_t cmd __attribute__ ((unused)), if (!grub_apm_get_info (&info)) return grub_error (GRUB_ERR_IO, "no APM found"); - grub_printf ("Vesion %u.%u\n" - "32-bit CS = 0x%x, len = 0x%x, offset = 0x%x\n" - "16-bit CS = 0x%x, len = 0x%x\n" - "DS = 0x%x, len = 0x%x\n", - info.version >> 8, info.version & 0xff, - info.cseg, info.cseg_len, info.offset, - info.cseg_16, info.cseg_16_len, - info.dseg, info.dseg_len); + grub_printf_ (N_("Vesion %u.%u\n" + "32-bit CS = 0x%x, len = 0x%x, offset = 0x%x\n" + "16-bit CS = 0x%x, len = 0x%x\n" + "DS = 0x%x, len = 0x%x\n"), + info.version >> 8, info.version & 0xff, + info.cseg, info.cseg_len, info.offset, + info.cseg_16, info.cseg_16_len, + info.dseg, info.dseg_len); grub_xputs (info.flags & GRUB_APM_FLAGS_16BITPROTECTED_SUPPORTED - ? "16-bit protected interface supported\n" - : "16-bit protected interface unsupported\n"); + ? _("16-bit protected interface supported\n") + : _("16-bit protected interface unsupported\n")); grub_xputs (info.flags & GRUB_APM_FLAGS_32BITPROTECTED_SUPPORTED - ? "32-bit protected interface supported\n" - : "32-bit protected interface unsupported\n"); + ? _("32-bit protected interface supported\n") + : _("32-bit protected interface unsupported\n")); grub_xputs (info.flags & GRUB_APM_FLAGS_CPUIDLE_SLOWS_DOWN - ? "CPU Idle slows down processor\n" - : "CPU Idle doesn't slow down processor\n"); + ? _("CPU Idle slows down processor\n") + : _("CPU Idle doesn't slow down processor\n")); grub_xputs (info.flags & GRUB_APM_FLAGS_DISABLED - ? "APM disabled\n" : "APM enabled\n"); + ? _("APM disabled\n") : _("APM enabled\n")); grub_xputs (info.flags & GRUB_APM_FLAGS_DISENGAGED - ? "APM disengaged\n" : "APM engaged\n"); + ? _("APM disengaged\n") : _("APM engaged\n")); return GRUB_ERR_NONE; } diff --git a/grub-core/commands/i386/pc/play.c b/grub-core/commands/i386/pc/play.c index 4ed937d4a..1adf296ec 100644 --- a/grub-core/commands/i386/pc/play.c +++ b/grub-core/commands/i386/pc/play.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define BASE_TEMPO (60 * GRUB_TICKS_PER_SECOND) /* The speaker port. */ @@ -190,7 +192,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), file = grub_file_open (args[0]); if (! file) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", args[0]); if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo)) { @@ -225,7 +227,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), if (*end) /* Was not a number either, assume it was supposed to be a file name. */ - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", args[0]); grub_dprintf ("play","tempo = %d\n", tempo); diff --git a/grub-core/commands/i386/pc/sendkey.c b/grub-core/commands/i386/pc/sendkey.c index c777ea60a..ab1090672 100644 --- a/grub-core/commands/i386/pc/sendkey.c +++ b/grub-core/commands/i386/pc/sendkey.c @@ -26,6 +26,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv2+"); static char sendkey[0x20]; /* Length of sendkey. */ @@ -33,23 +36,23 @@ static int keylen = 0; static int noled = 0; static const struct grub_arg_option options[] = { - {"num", 'n', 0, "set numlock mode", "[on|off]", ARG_TYPE_STRING}, - {"caps", 'c', 0, "set capslock mode", "[on|off]", ARG_TYPE_STRING}, - {"scroll", 's', 0, "set scrolllock mode", "[on|off]", ARG_TYPE_STRING}, - {"insert", 0, 0, "set insert mode", "[on|off]", ARG_TYPE_STRING}, - {"pause", 0, 0, "set pause mode", "[on|off]", ARG_TYPE_STRING}, - {"left-shift", 0, 0, "press left shift", "[on|off]", ARG_TYPE_STRING}, - {"right-shift", 0, 0, "press right shift", "[on|off]", ARG_TYPE_STRING}, - {"sysrq", 0, 0, "press SysRq", "[on|off]", ARG_TYPE_STRING}, - {"numkey", 0, 0, "press NumLock key", "[on|off]", ARG_TYPE_STRING}, - {"capskey", 0, 0, "press CapsLock key", "[on|off]", ARG_TYPE_STRING}, - {"scrollkey", 0, 0, "press ScrollLock key", "[on|off]", ARG_TYPE_STRING}, - {"insertkey", 0, 0, "press Insert key", "[on|off]", ARG_TYPE_STRING}, - {"left-alt", 0, 0, "press left alt", "[on|off]", ARG_TYPE_STRING}, - {"right-alt", 0, 0, "press right alt", "[on|off]", ARG_TYPE_STRING}, - {"left-ctrl", 0, 0, "press left ctrl", "[on|off]", ARG_TYPE_STRING}, - {"right-ctrl", 0, 0, "press right ctrl", "[on|off]", ARG_TYPE_STRING}, - {"no-led", 0, 0, "don't update LED state", 0, 0}, + {"num", 'n', 0, N_("set numlock mode"), "[on|off]", ARG_TYPE_STRING}, + {"caps", 'c', 0, N_("set capslock mode"), "[on|off]", ARG_TYPE_STRING}, + {"scroll", 's', 0, N_("set scrolllock mode"), "[on|off]", ARG_TYPE_STRING}, + {"insert", 0, 0, N_("set insert mode"), "[on|off]", ARG_TYPE_STRING}, + {"pause", 0, 0, N_("set pause mode"), "[on|off]", ARG_TYPE_STRING}, + {"left-shift", 0, 0, N_("press left shift"), "[on|off]", ARG_TYPE_STRING}, + {"right-shift", 0, 0, N_("press right shift"), "[on|off]", ARG_TYPE_STRING}, + {"sysrq", 0, 0, N_("press SysRq"), "[on|off]", ARG_TYPE_STRING}, + {"numkey", 0, 0, N_("press NumLock key"), "[on|off]", ARG_TYPE_STRING}, + {"capskey", 0, 0, N_("press CapsLock key"), "[on|off]", ARG_TYPE_STRING}, + {"scrollkey", 0, 0, N_("press ScrollLock key"), "[on|off]", ARG_TYPE_STRING}, + {"insertkey", 0, 0, N_("press Insert key"), "[on|off]", ARG_TYPE_STRING}, + {"left-alt", 0, 0, N_("press left alt"), "[on|off]", ARG_TYPE_STRING}, + {"right-alt", 0, 0, N_("press right alt"), "[on|off]", ARG_TYPE_STRING}, + {"left-ctrl", 0, 0, N_("press left ctrl"), "[on|off]", ARG_TYPE_STRING}, + {"right-ctrl", 0, 0, N_("press right ctrl"), "[on|off]", ARG_TYPE_STRING}, + {"no-led", 0, 0, N_("don't update LED state"), 0, 0}, {0, 0, 0, 0, 0, 0} }; static int simple_flag_offsets[] @@ -60,8 +63,8 @@ static grub_uint32_t andmask = 0xffffffff, ormask = 0; struct keysym { - char *unshifted_name; /* the name in unshifted state */ - char *shifted_name; /* the name in shifted state */ + const char *unshifted_name; /* the name in unshifted state */ + const char *shifted_name; /* the name in shifted state */ unsigned char unshifted_ascii; /* the ascii code in unshifted state */ unsigned char shifted_ascii; /* the ascii code in shifted state */ unsigned char keycode; /* keyboard scancode */ @@ -362,13 +365,13 @@ grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args) } static grub_extcmd_t cmd; -static void *preboot_hook; +static struct grub_preboot *preboot_hook; GRUB_MOD_INIT (sendkey) { cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey, 0, - "sendkey [KEYSTROKE1] [KEYSTROKE2] ...", - "Emulate a keystroke", options); + N_("[KEYSTROKE1] [KEYSTROKE2] ..."), + N_("Emulate a keystroke"), options); preboot_hook = grub_loader_register_preboot_hook (grub_sendkey_preboot, diff --git a/grub-core/commands/ieee1275/suspend.c b/grub-core/commands/ieee1275/suspend.c index f096cc9ba..844485077 100644 --- a/grub-core/commands/ieee1275/suspend.c +++ b/grub-core/commands/ieee1275/suspend.c @@ -24,12 +24,14 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_suspend (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - grub_printf ("Run 'go' to resume GRUB.\n"); + grub_puts_ (N_("Run 'go' to resume GRUB.")); grub_ieee1275_enter (); grub_cls (); return 0; diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c index 20d203e92..e7035b528 100644 --- a/grub-core/commands/iorw.c +++ b/grub-core/commands/iorw.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c index deb482a85..6c5913a54 100644 --- a/grub-core/commands/keylayouts.c +++ b/grub-core/commands/keylayouts.c @@ -28,6 +28,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static struct grub_keyboard_layout layout_us = { .keyboard_map = { /* Keyboard errors. Handled by driver. */ diff --git a/grub-core/commands/keystatus.c b/grub-core/commands/keystatus.c index 9e1486c9d..f3a669942 100644 --- a/grub-core/commands/keystatus.c +++ b/grub-core/commands/keystatus.c @@ -23,6 +23,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"shift", 's', 0, N_("Check Shift key."), 0, 0}, diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c index 1b0e968c5..4de2d84d5 100644 --- a/grub-core/commands/legacycfg.c +++ b/grub-core/commands/legacycfg.c @@ -33,6 +33,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t legacy_file (const char *filename) { @@ -83,9 +85,13 @@ legacy_file (const char *filename) { char *oldname = NULL; char *newsuffix; + char *ptr; + + for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); oldname = entryname; - parsed = grub_legacy_parse (buf, &entryname, &newsuffix); + parsed = grub_legacy_parse (ptr, &entryname, &newsuffix); + grub_free (buf); buf = NULL; if (newsuffix) { @@ -177,9 +183,6 @@ legacy_file (const char *filename) grub_free (suffix); grub_free (entrysrc); - if (menu && menu->size) - grub_show_menu (menu, 1); - return GRUB_ERR_NONE; } @@ -194,8 +197,8 @@ grub_cmd_legacy_source (struct grub_command *cmd, return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); extractor = (cmd->name[0] == 'e'); - new_env = (cmd->name[extractor ? sizeof ("extract_legacy_entries_") - 1 - : sizeof ("legacy_") - 1] == 'c'); + new_env = (cmd->name[extractor ? (sizeof ("extract_legacy_entries_") - 1) + : (sizeof ("legacy_") - 1)] == 'c'); if (new_env) grub_cls (); @@ -207,8 +210,15 @@ grub_cmd_legacy_source (struct grub_command *cmd, ret = legacy_file (args[0]); - if (new_env && !extractor) - grub_env_context_close (); + if (new_env) + { + grub_menu_t menu; + menu = grub_env_get_menu (); + if (menu && menu->size) + grub_show_menu (menu, 1, 0); + if (!extractor) + grub_env_context_close (); + } if (extractor) grub_env_extractor_close (!new_env); @@ -225,7 +235,9 @@ grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)), int argc, char **args) { int i; +#ifdef TODO int no_mem_option = 0; +#endif struct grub_command *cmd; char **cutargs; int cutargc; @@ -235,7 +247,9 @@ grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)), /* FIXME: really support this. */ if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0) { +#ifdef TODO no_mem_option = 1; +#endif argc--; args++; continue; @@ -330,7 +344,7 @@ grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)), int bsd_part = -1; { grub_device_t dev; - char *hdbiasstr; + const char *hdbiasstr; int hdbias = 0; hdbiasstr = grub_env_get ("legacy_hdbias"); if (hdbiasstr) @@ -709,7 +723,7 @@ grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unuse if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected"); - grub_printf ("Enter password:"); + grub_puts_ (N_("Enter password: ")); if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) return GRUB_ACCESS_DENIED; @@ -757,12 +771,12 @@ GRUB_MOD_INIT(legacycfg) = grub_register_command ("extract_legacy_entries_source", grub_cmd_legacy_source, N_("FILE"), - N_("Parse legacy config in same context taking onl entries")); + N_("Parse legacy config in same context taking only menu entries")); cmd_configfile_extract = grub_register_command ("extract_legacy_entries_configfile", grub_cmd_legacy_source, N_("FILE"), - N_("Parse legacy config in new context taking onl entries")); + N_("Parse legacy config in new context taking only menu entries")); cmd_kernel = grub_register_command ("legacy_kernel", grub_cmd_legacy_kernel, diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c index 38b3a84c6..1073712d5 100644 --- a/grub-core/commands/loadenv.c +++ b/grub-core/commands/loadenv.c @@ -28,6 +28,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME}, @@ -41,7 +43,7 @@ open_envblk_file (char *filename) if (! filename) { - char *prefix; + const char *prefix; prefix = grub_env_get ("prefix"); if (prefix) @@ -344,7 +346,7 @@ grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args) while (argc) { - char *value; + const char *value; value = grub_env_get (args[0]); if (value) diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c index 481d17db0..db9307780 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -31,6 +31,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static const struct grub_arg_option options[] = { @@ -58,6 +61,22 @@ grub_ls_list_devices (int longlist) grub_device_iterate (grub_ls_print_devices); grub_xputs ("\n"); + +#ifndef GRUB_UTIL + { + grub_net_app_level_t proto; + int first = 1; + FOR_NET_APP_LEVEL (proto) + { + if (first) + grub_puts_ (N_ ("Network protocols:")); + first = 0; + grub_printf ("%s ", proto->name); + } + grub_xputs ("\n"); + } +#endif + grub_refresh (); return 0; @@ -132,11 +151,12 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) if (units) { - grub_uint32_t whole, fraction; + grub_uint64_t whole, fraction; whole = grub_divmod64 (fsize, 100, &fraction); grub_snprintf (buf, sizeof (buf), - "%u.%02u%c", whole, fraction, + "%" PRIuGRUB_UINT64_T + ".%02" PRIuGRUB_UINT64_T "%c", whole, fraction, grub_human_sizes[units]); grub_printf ("%-12s", buf); } diff --git a/grub-core/commands/lsacpi.c b/grub-core/commands/lsacpi.c index 64b559665..fd19e380a 100644 --- a/grub-core/commands/lsacpi.c +++ b/grub-core/commands/lsacpi.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static void print_strn (grub_uint8_t *str, grub_size_t len) { diff --git a/grub-core/commands/lsmmap.c b/grub-core/commands/lsmmap.c index 657f81387..4815fd174 100644 --- a/grub-core/commands/lsmmap.c +++ b/grub-core/commands/lsmmap.c @@ -22,15 +22,17 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const char *names[] = { - [GRUB_MEMORY_AVAILABLE] = "available", - [GRUB_MEMORY_RESERVED] = "reserved", - [GRUB_MEMORY_ACPI] = "ACPI reclamaible", - [GRUB_MEMORY_NVS] = "NVS", - [GRUB_MEMORY_BADRAM] = "BadRAM", - [GRUB_MEMORY_CODE] = "firmware code", - [GRUB_MEMORY_HOLE] = "hole" + [GRUB_MEMORY_AVAILABLE] = N_("available"), + [GRUB_MEMORY_RESERVED] = N_("reserved"), + [GRUB_MEMORY_ACPI] = N_("ACPI reclamaible"), + [GRUB_MEMORY_NVS] = N_("ACPI non-volatile storage"), + [GRUB_MEMORY_BADRAM] = N_("BadRAM"), + [GRUB_MEMORY_CODE] = N_("firmware code"), + [GRUB_MEMORY_HOLE] = N_("hole") }; static grub_err_t @@ -44,11 +46,11 @@ grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)), grub_memory_type_t type) { if (type < ARRAY_SIZE (names) && names[type]) - grub_printf ("base_addr = 0x%llx, length = 0x%llx, %s\n", - (long long) addr, (long long) size, names[type]); + grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, %s\n"), + (long long) addr, (long long) size, _(names[type])); else - grub_printf ("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n", - (long long) addr, (long long) size, type); + grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n"), + (long long) addr, (long long) size, type); return 0; } #ifndef GRUB_MACHINE_EMU diff --git a/grub-core/commands/lspci.c b/grub-core/commands/lspci.c index fd2d4eaf2..9f836298f 100644 --- a/grub-core/commands/lspci.c +++ b/grub-core/commands/lspci.c @@ -23,11 +23,13 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_pci_classname { int class; int subclass; - char *desc; + const char *desc; }; static const struct grub_pci_classname grub_pci_classes[] = diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c index 28aac7d81..5984288ce 100644 --- a/grub-core/commands/memrw.c +++ b/grub-core/commands/memrw.c @@ -23,13 +23,15 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; static const struct grub_arg_option options[] = { {0, 'v', 0, N_("Save read value into variable VARNAME."), - "VARNAME", ARG_TYPE_STRING}, + N_("VARNAME"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c index 9718d1eab..57e4baa61 100644 --- a/grub-core/commands/menuentry.c +++ b/grub-core/commands/menuentry.c @@ -28,19 +28,19 @@ static const struct grub_arg_option options[] = { {"class", 1, GRUB_ARG_OPTION_REPEATABLE, - N_("Menu entry type."), "STRING", ARG_TYPE_STRING}, + N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING}, {"users", 2, 0, - N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING}, + N_("Users allowed to boot this entry."), N_("USERNAME"), ARG_TYPE_STRING}, {"hotkey", 3, 0, - N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING}, + N_("Keyboard key for this entry."), N_("KEY"), ARG_TYPE_STRING}, {"source", 4, 0, - N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING}, + N_("Menu entry definition as a string."), N_("STRING"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; static struct { - char *name; + const char *name; int key; } hotkey_aliases[] = { @@ -91,7 +91,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes, if (! menu_sourcecode) return grub_errno; - if (classes) + if (classes && classes[0]) { int i; for (i = 0; classes[i]; i++); /* count # of menuentry classes */ @@ -206,20 +206,6 @@ setparams_prefix (int argc, char **args) 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++) @@ -227,7 +213,7 @@ setparams_prefix (int argc, char **args) len += 3; /* 3 = 1 space + 2 quotes */ p = args[i]; while (*p) - len += grub_strchr (escape_characters, *p++) ? 2 : 1; + len += (*p++ == '\'' ? 3 : 1); } result = grub_malloc (len + 2); @@ -235,17 +221,17 @@ setparams_prefix (int argc, char **args) return 0; grub_strcpy (result, "setparams"); - i = 9; + p = result + 9; for (j = 0; j < argc; j++) { - result[i++] = ' '; - result[i++] = '"'; - i = strescpy (result + i, args[j], escape_characters) - result; - result[i++] = '"'; + *p++ = ' '; + *p++ = '\''; + p = grub_strchrsub (p, args[j], '\'', "'\\''"); + *p++ = '\''; } - result[i++] = '\n'; - result[i] = '\0'; + *p++ = '\n'; + *p = '\0'; return result; } @@ -269,7 +255,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) if (! ctxt->script) return grub_normal_add_menu_entry (argc, (const char **) args, - ctxt->state[0].args, ctxt->state[1].arg, + (ctxt->state[0].set ? ctxt->state[0].args + : NULL), ctxt->state[1].arg, ctxt->state[2].arg, 0, ctxt->state[3].arg, ctxt->extcmd->cmd->name[0] == 's'); diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index 5cf109fde..f436cd55d 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* cat FILE */ static grub_err_t grub_mini_cmd_cat (struct grub_command *cmd __attribute__ ((unused)), @@ -88,26 +90,6 @@ grub_mini_cmd_help (struct grub_command *cmd __attribute__ ((unused)), return 0; } -#if 0 -static void -grub_rescue_cmd_info (void) -{ - extern void grub_disk_cache_get_performance (unsigned long *, - unsigned long *); - unsigned long hits, misses; - - grub_disk_cache_get_performance (&hits, &misses); - grub_printf ("Disk cache: hits = %u, misses = %u ", hits, misses); - if (hits + misses) - { - unsigned long ratio = hits * 10000 / (hits + misses); - grub_printf ("(%u.%u%%)\n", ratio / 100, ratio % 100); - } - else - grub_printf ("(N/A)\n"); -} -#endif - /* dump ADDRESS [SIZE] */ static grub_err_t grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)), @@ -163,7 +145,7 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), { grub_dl_t mod; - grub_printf ("Name\tRef Count\tDependencies\n"); + grub_printf_ (N_("Name\tRef Count\tDependencies\n")); FOR_DL_MODULES (mod) { grub_dl_dep_t dep; @@ -183,13 +165,13 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), } /* exit */ -static grub_err_t +static grub_err_t __attribute__ ((noreturn)) grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused))) { grub_exit (); - return 0; + /* Not reached. */ } static grub_command_t cmd_cat, cmd_help; diff --git a/grub-core/commands/mips/yeeloong/lsspd.c b/grub-core/commands/mips/loongson/lsspd.c similarity index 75% rename from grub-core/commands/mips/yeeloong/lsspd.c rename to grub-core/commands/mips/loongson/lsspd.c index 539cda34c..76999368f 100644 --- a/grub-core/commands/mips/yeeloong/lsspd.c +++ b/grub-core/commands/mips/loongson/lsspd.c @@ -23,6 +23,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_err_t grub_cmd_lsspd (grub_command_t cmd __attribute__ ((unused)), @@ -36,43 +39,44 @@ grub_cmd_lsspd (grub_command_t cmd __attribute__ ((unused)), if (!grub_cs5536_find (&dev)) { - grub_printf ("No CS5536 found\n"); + grub_puts_ (N_("No CS5536 found")); return GRUB_ERR_NONE; } - grub_printf ("CS5536 at %d:%d.%d\n", grub_pci_get_bus (dev), - grub_pci_get_device (dev), grub_pci_get_function (dev)); + grub_printf_ (N_("CS5536 at %d:%d.%d\n"), grub_pci_get_bus (dev), + grub_pci_get_device (dev), grub_pci_get_function (dev)); err = grub_cs5536_init_smbus (dev, 0x7fff, &smbbase); if (err) return err; - grub_printf ("SMB base = 0x%x\n", smbbase); + grub_printf_ (N_("SMB base = 0x%x\n"), smbbase); for (i = GRUB_SMB_RAM_START_ADDR; i < GRUB_SMB_RAM_START_ADDR + GRUB_SMB_RAM_NUM_MAX; i++) { struct grub_smbus_spd spd; grub_memset (&spd, 0, sizeof (spd)); - grub_printf ("Device %d\n", i); + grub_printf_ (N_("Device %d\n"), i); err = grub_cs5536_read_spd (smbbase, i, &spd); if (err) { grub_print_error (); continue; } - grub_printf ("Written SPD bytes: %d B.\n", spd.written_size); - grub_printf ("Total flash size: %d B.\n", 1 << spd.log_total_flash_size); + grub_printf_ (N_("Written SPD bytes: %d B.\n"), spd.written_size); + grub_printf_ (N_("Total flash size: %d B.\n"), + 1 << spd.log_total_flash_size); if (spd.memory_type == GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2) { char str[sizeof (spd.ddr2.part_number) + 1]; - grub_printf ("Memory type: DDR2.\n"); + grub_puts_ (N_("Memory type: DDR2.")); grub_memcpy (str, spd.ddr2.part_number, sizeof (spd.ddr2.part_number)); str[sizeof (spd.ddr2.part_number)] = 0; - grub_printf ("Part no: %s.\n", str); + grub_printf_ (N_("Part no: %s.\n"), str); } else - grub_printf ("Memory type: Unknown.\n"); + grub_puts_ (N_("Memory type: Unknown.")); } return GRUB_ERR_NONE; @@ -83,7 +87,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(lsspd) { cmd = grub_register_command ("lsspd", grub_cmd_lsspd, 0, - "Print Memory information."); + N_("Print Memory information.")); } GRUB_MOD_FINI(lsspd) diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c index 31e768553..ab5ab5ea4 100644 --- a/grub-core/commands/parttool.c +++ b/grub-core/commands/parttool.c @@ -31,13 +31,15 @@ #include #include +GRUB_MOD_LICENSE ("GPLv2+"); + static struct grub_parttool *parts = 0; static int curhandle = 0; static grub_dl_t mymod; static char helpmsg[] = - "Perform COMMANDS on partition.\n" - "Use \"parttool PARTITION help\" for the list " - "of available commands."; + N_("Perform COMMANDS on partition.\n" + "Use \"parttool PARTITION help\" for the list " + "of available commands."); int grub_parttool_register(const char *part_name, @@ -126,7 +128,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), break; case GRUB_PARTTOOL_ARG_VAL: - grub_printf ("=VAL"); + grub_xputs (_("=VAL")); spacing -= 4; break; @@ -135,18 +137,18 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), } while (spacing-- > 0) grub_printf (" "); - grub_printf ("%s\n", curarg->desc); + grub_puts_ (curarg->desc); } } if (! found) - grub_printf ("Sorry no parttool is available for %s\n", + grub_printf_ (N_("Sorry no parttool is available for %s\n"), dev->disk->partition->partmap->name); return GRUB_ERR_NONE; } if (argc < 1) { - grub_printf ("%s\n", helpmsg); + grub_puts_ (helpmsg); return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments"); } diff --git a/grub-core/commands/password.c b/grub-core/commands/password.c index db5951cbb..8821607b8 100644 --- a/grub-core/commands/password.c +++ b/grub-core/commands/password.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; static grub_err_t diff --git a/grub-core/commands/password_pbkdf2.c b/grub-core/commands/password_pbkdf2.c index 6886987da..05a627219 100644 --- a/grub-core/commands/password_pbkdf2.c +++ b/grub-core/commands/password_pbkdf2.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; struct pbkdf2_password diff --git a/grub-core/commands/probe.c b/grub-core/commands/probe.c index abe84895d..a1d68cdeb 100644 --- a/grub-core/commands/probe.c +++ b/grub-core/commands/probe.c @@ -32,9 +32,11 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { - {"set", 's', GRUB_ARG_OPTION_OPTIONAL, + {"set", 's', 0, N_("Set a variable to return value."), "VAR", ARG_TYPE_STRING}, {"driver", 'd', 0, N_("Determine driver."), 0, 0}, {"partmap", 'p', 0, N_("Determine partition map type."), 0, 0}, @@ -72,7 +74,7 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) { const char *val = "none"; if (dev->net) - val = dev->net->dev->name; + val = dev->net->protocol->name; if (dev->disk) val = dev->disk->dev->name; if (state[0].set) @@ -134,7 +136,7 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) return err; if (! label) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "uuid for this FS isn't supported yet"); + "label for this FS isn't supported yet"); if (state[0].set) grub_env_set (state[0].arg, label); @@ -150,7 +152,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT (probe) { - cmd = grub_register_extcmd ("probe", grub_cmd_probe, 0, N_("[DEVICE]"), + cmd = grub_register_extcmd ("probe", grub_cmd_probe, 0, N_("DEVICE"), N_("Retrieve device info."), options); } diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c index 6a187fc3e..fe3e88b15 100644 --- a/grub-core/commands/read.c +++ b/grub-core/commands/read.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static char * grub_getline (void) { diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c index eedd53c91..46d364c99 100644 --- a/grub-core/commands/reboot.c +++ b/grub-core/commands/reboot.c @@ -22,13 +22,14 @@ #include #include -static grub_err_t +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_err_t __attribute__ ((noreturn)) grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { grub_reboot (); - return 0; } static grub_command_t cmd; diff --git a/grub-core/commands/regexp.c b/grub-core/commands/regexp.c index f27a147af..1e8a6f309 100644 --- a/grub-core/commands/regexp.c +++ b/grub-core/commands/regexp.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { { "set", 's', GRUB_ARG_OPTION_REPEATABLE, @@ -87,7 +89,6 @@ set_matches (char **varnames, char *str, grub_size_t nmatches, static grub_err_t grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args) { - int argn = 0; regex_t regex; int ret; grub_size_t s; diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index f265f86d6..d5117baef 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -31,11 +31,23 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + +struct cache_entry +{ + struct cache_entry *next; + char *key; + char *value; +}; + +static struct cache_entry *cache; + void FUNC_NAME (const char *key, const char *var, int no_floppy, char **hints, unsigned nhints) { int count = 0; + int is_cache = 0; grub_fs_autoload_hook_t saved_autoload; auto int iterate_device (const char *name); @@ -48,6 +60,12 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') return 0; +#ifdef DO_SEARCH_FS_UUID +#define compare_fn grub_strcasecmp +#else +#define compare_fn grub_strcmp +#endif + #ifdef DO_SEARCH_FILE { char *buf; @@ -79,10 +97,8 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, fs = grub_fs_probe (dev); #ifdef DO_SEARCH_FS_UUID -#define compare_fn grub_strcasecmp #define read_fn uuid #else -#define compare_fn grub_strcmp #define read_fn label #endif @@ -104,6 +120,31 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, } #endif + if (!is_cache && found && count == 0) + { + struct cache_entry *cache_ent; + cache_ent = grub_malloc (sizeof (*cache_ent)); + if (cache_ent) + { + cache_ent->key = grub_strdup (key); + cache_ent->value = grub_strdup (name); + if (cache_ent->value && cache_ent->key) + { + cache_ent->next = cache; + cache = cache_ent; + } + else + { + grub_free (cache_ent->value); + grub_free (cache_ent->key); + grub_free (cache_ent); + grub_errno = GRUB_ERR_NONE; + } + } + else + grub_errno = GRUB_ERR_NONE; + } + if (found) { count++; @@ -141,6 +182,32 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, void try (void) { unsigned i; + struct cache_entry **prev; + struct cache_entry *cache_ent; + + for (prev = &cache, cache_ent = *prev; cache_ent; + prev = &cache_ent->next, cache_ent = *prev) + if (compare_fn (cache_ent->key, key) == 0) + break; + if (cache_ent) + { + is_cache = 1; + if (iterate_device (cache_ent->value)) + { + is_cache = 0; + return; + } + is_cache = 0; + /* Cache entry was outdated. Remove it. */ + if (!count) + { + grub_free (cache_ent->key); + grub_free (cache_ent->value); + grub_free (cache_ent); + *prev = cache_ent->next; + } + } + for (i = 0; i < nhints; i++) { char *end; @@ -162,17 +229,20 @@ FUNC_NAME (const char *key, const char *var, int no_floppy, dev = grub_device_open (hints[i]); if (!dev) { - *end = ','; + if (!*end) + *end = ','; continue; } if (!dev->disk) { grub_device_close (dev); - *end = ','; + if (!*end) + *end = ','; continue; } ret = grub_partition_iterate (dev->disk, part_hook); - *end = ','; + if (!*end) + *end = ','; grub_device_close (dev); if (ret) return; diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c index 80741d7ab..35c5ee319 100644 --- a/grub-core/commands/search_wrap.c +++ b/grub-core/commands/search_wrap.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"file", 'f', 0, N_("Search devices by a file."), 0, 0}, @@ -40,6 +42,21 @@ static const struct grub_arg_option options[] = {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, N_("First try the device HINT. If HINT ends in comma, " "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, + {"hint-ieee1275", 0, GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT if on IEEE1275. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, + {"hint-bios", 0, GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT if on BIOS. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, + {"hint-baremetal", 0, GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, + {"hint-efi", 0, GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT if on EFI. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, + {"hint-arc", 0, GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT if on ARC. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -50,7 +67,12 @@ enum options SEARCH_FS_UUID, SEARCH_SET, SEARCH_NO_FLOPPY, - SEARCH_HINT + SEARCH_HINT, + SEARCH_HINT_IEEE1275, + SEARCH_HINT_BIOS, + SEARCH_HINT_BAREMETAL, + SEARCH_HINT_EFI, + SEARCH_HINT_ARC, }; static grub_err_t @@ -58,27 +80,98 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) { struct grub_arg_list *state = ctxt->state; const char *var = 0; - int nhints = 0; + int i = 0, j = 0, nhints = 0; + char **hints = NULL; if (state[SEARCH_HINT].set) - while (state[SEARCH_HINT].args[nhints]) + for (i = 0; state[SEARCH_HINT].args[i]; i++) nhints++; - if (argc == 0) +#ifdef GRUB_MACHINE_IEEE1275 + if (state[SEARCH_HINT_IEEE1275].set) + for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++) + nhints++; +#endif + +#ifdef GRUB_MACHINE_EFI + if (state[SEARCH_HINT_EFI].set) + for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++) + nhints++; +#endif + +#ifdef GRUB_MACHINE_PCBIOS + if (state[SEARCH_HINT_BIOS].set) + for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++) + nhints++; +#endif + +#ifdef GRUB_MACHINE_ARC + if (state[SEARCH_HINT_ARC].set) + for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++) + nhints++; +#endif + + if (state[SEARCH_HINT_BAREMETAL].set) + for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++) + nhints++; + + hints = grub_malloc (sizeof (hints[0]) * nhints); + if (!hints) + return grub_errno; + j = 0; + + if (state[SEARCH_HINT].set) + for (i = 0; state[SEARCH_HINT].args[i]; i++) + hints[j++] = state[SEARCH_HINT].args[i]; + +#ifdef GRUB_MACHINE_IEEE1275 + if (state[SEARCH_HINT_IEEE1275].set) + for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++) + hints[j++] = state[SEARCH_HINT_IEEE1275].args[i]; +#endif + +#ifdef GRUB_MACHINE_EFI + if (state[SEARCH_HINT_EFI].set) + for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++) + hints[j++] = state[SEARCH_HINT_EFI].args[i]; +#endif + +#ifdef GRUB_MACHINE_ARC + if (state[SEARCH_HINT_ARC].set) + for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++) + hints[j++] = state[SEARCH_HINT_ARC].args[i]; +#endif + +#ifdef GRUB_MACHINE_PCBIOS + if (state[SEARCH_HINT_BIOS].set) + for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++) + hints[j++] = state[SEARCH_HINT_BIOS].args[i]; +#endif + + if (state[SEARCH_HINT_BAREMETAL].set) + for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++) + hints[j++] = state[SEARCH_HINT_BAREMETAL].args[i]; + + /* Skip hints for future platforms. */ + for (j = 0; j < argc; j++) + if (grub_memcmp (args[j], "--hint-", sizeof ("--hint-") - 1) != 0) + break; + + if (argc == j) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); if (state[SEARCH_SET].set) var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root"; if (state[SEARCH_LABEL].set) - grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set, - state[SEARCH_HINT].args, nhints); + grub_search_label (args[j], var, state[SEARCH_NO_FLOPPY].set, + hints, nhints); else if (state[SEARCH_FS_UUID].set) - grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set, - state[SEARCH_HINT].args, nhints); + grub_search_fs_uuid (args[j], var, state[SEARCH_NO_FLOPPY].set, + hints, nhints); else if (state[SEARCH_FILE].set) - grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set, - state[SEARCH_HINT].args, nhints); + grub_search_fs_file (args[j], var, state[SEARCH_NO_FLOPPY].set, + hints, nhints); else return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); @@ -90,7 +183,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(search) { cmd = - grub_register_extcmd ("search", grub_cmd_search, GRUB_COMMAND_FLAG_EXTRACTOR, + grub_register_extcmd ("search", grub_cmd_search, + GRUB_COMMAND_FLAG_EXTRACTOR | GRUB_COMMAND_ACCEPT_DASH, N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]" " NAME"), N_("Search devices by file, filesystem label" diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c index 7b194ed17..81e7f726d 100644 --- a/grub-core/commands/setpci.c +++ b/grub-core/commands/setpci.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct pci_register { const char *name; @@ -32,7 +34,7 @@ struct pci_register unsigned size; }; -struct pci_register pci_registers[] = +static struct pci_register pci_registers[] = { {"VENDOR_ID", GRUB_PCI_REG_VENDOR , 2}, {"DEVICE_ID", GRUB_PCI_REG_DEVICE , 2}, @@ -64,12 +66,12 @@ struct pci_register pci_registers[] = static const struct grub_arg_option options[] = { - {0, 'd', 0, "Select device by vendor and device IDs.", - "[vendor]:[device]", ARG_TYPE_STRING}, - {0, 's', 0, "Select device by its position on the bus.", - "[bus]:[slot][.func]", ARG_TYPE_STRING}, - {0, 'v', 0, "Save read value into variable VARNAME.", - "VARNAME", ARG_TYPE_STRING}, + {0, 'd', 0, N_("Select device by vendor and device IDs."), + N_("[vendor]:[device]"), ARG_TYPE_STRING}, + {0, 's', 0, N_("Select device by its position on the bus."), + N_("[bus]:[slot][.func]"), ARG_TYPE_STRING}, + {0, 'v', 0, N_("Save read value into variable VARNAME."), + N_("VARNAME"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -126,7 +128,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) if (!write_mask) { - grub_printf ("Register %x of %d:%d.%d is %x\n", regaddr, + grub_printf (N_("Register %x of %d:%d.%d is %x\n"), regaddr, grub_pci_get_bus (dev), grub_pci_get_device (dev), grub_pci_get_function (dev), diff --git a/grub-core/commands/sleep.c b/grub-core/commands/sleep.c index da642fcd9..97e7a40a6 100644 --- a/grub-core/commands/sleep.c +++ b/grub-core/commands/sleep.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const struct grub_arg_option options[] = { {"verbose", 'v', 0, N_("Verbose countdown."), 0, 0}, diff --git a/grub-core/commands/terminal.c b/grub-core/commands/terminal.c index c8b1b6315..4ed3f1c6e 100644 --- a/grub-core/commands/terminal.c +++ b/grub-core/commands/terminal.c @@ -23,12 +23,15 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_term_autoload *grub_term_input_autoload = NULL; struct grub_term_autoload *grub_term_output_autoload = NULL; struct abstract_terminal { struct abstract_terminal *next; + struct abstract_terminal *prev; const char *name; grub_err_t (*init) (struct abstract_terminal *term); grub_err_t (*fini) (struct abstract_terminal *term); @@ -92,11 +95,15 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled, while (1) { for (term = *disabled; term; term = term->next) - if (grub_strcmp (args[i], term->name) == 0) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) break; if (term == 0) for (term = *enabled; term; term = term->next) - if (grub_strcmp (args[i], term->name) == 0) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) break; if (term) break; @@ -105,6 +112,8 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled, args[i]); for (aut = autoloads; aut; aut = aut->next) if (grub_strcmp (args[i], aut->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", aut->name) == 0) || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' && grub_memcmp (args[i], aut->name, grub_strlen (aut->name) - 1) == 0)) @@ -128,14 +137,16 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled, for (i = 1; i < argc; i++) { for (term = *disabled; term; term = term->next) - if (grub_strcmp (args[i], term->name) == 0) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) break; if (term) { if (term->init && term->init (term) != GRUB_ERR_NONE) return grub_errno; - grub_list_remove (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); } } @@ -147,14 +158,16 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled, for (i = 1; i < argc; i++) { for (term = *enabled; term; term = term->next) - if (grub_strcmp (args[i], term->name) == 0) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) break; if (term) { if (!term->next && term == *enabled) return grub_error (GRUB_ERR_BAD_ARGUMENT, "can't remove the last terminal"); - grub_list_remove (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); if (term->fini) term->fini (term); grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); @@ -165,14 +178,16 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled, for (i = 0; i < argc; i++) { for (term = *disabled; term; term = term->next) - if (grub_strcmp (args[i], term->name) == 0) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) break; if (term) { if (term->init && term->init (term) != GRUB_ERR_NONE) return grub_errno; - grub_list_remove (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); } } @@ -183,14 +198,16 @@ handle_command (int argc, char **args, struct abstract_terminal **enabled, { next = term->next; for (i = 0; i < argc; i++) - if (grub_strcmp (args[i], term->name) == 0) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) break; if (i == argc) { if (!term->next && term == *enabled) return grub_error (GRUB_ERR_BAD_ARGUMENT, "can't remove the last terminal"); - grub_list_remove (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); if (term->fini) term->fini (term); grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); @@ -206,15 +223,16 @@ grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, prev); (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name); (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init); (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini); return handle_command (argc, args, - (struct abstract_terminal **) &grub_term_inputs, - (struct abstract_terminal **) &grub_term_inputs_disabled, - grub_term_input_autoload, - N_ ("Active input terminals:"), - N_ ("Available input terminals:")); + (struct abstract_terminal **) (void *) &grub_term_inputs, + (struct abstract_terminal **) (void *) &grub_term_inputs_disabled, + grub_term_input_autoload, + N_ ("Active input terminals:"), + N_ ("Available input terminals:")); } static grub_err_t @@ -222,14 +240,16 @@ grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, prev); (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name); (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init); (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini); - return handle_command (argc, args, (struct abstract_terminal **) &grub_term_outputs, - (struct abstract_terminal **) &grub_term_outputs_disabled, - grub_term_output_autoload, - N_ ("Active output terminals:"), - N_ ("Available output terminals:")); + return handle_command (argc, args, + (struct abstract_terminal **) (void *) &grub_term_outputs, + (struct abstract_terminal **) (void *) &grub_term_outputs_disabled, + grub_term_output_autoload, + N_ ("Active output terminals:"), + N_ ("Available output terminals:")); } static grub_command_t cmd_terminal_input, cmd_terminal_output; diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c index e981c945a..50d5aba5e 100644 --- a/grub-core/commands/test.c +++ b/grub-core/commands/test.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* A simple implementation for signed numbers. */ static int grub_strtosl (char *arg, char **end, int base) diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c index 86b8a9253..fe06f3d1e 100644 --- a/grub-core/commands/testload.c +++ b/grub-core/commands/testload.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)), int argc, char *argv[]) diff --git a/grub-core/commands/time.c b/grub-core/commands/time.c new file mode 100644 index 000000000..224f92b3f --- /dev/null +++ b/grub-core/commands/time.c @@ -0,0 +1,68 @@ +/* echo.c - Command to display a line of text */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + + +static grub_err_t +grub_cmd_time (grub_command_t ctxt __attribute__ ((unused)), + int argc, char **args) +{ + grub_command_t cmd; + grub_uint32_t start; + grub_uint32_t end; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "command expected"); + + cmd = grub_command_find (args[0]); + + if (!cmd) + return grub_error (GRUB_ERR_UNKNOWN_COMMAND, "Unknown command `%s'\n", + args[0]); + + start = grub_get_time_ms (); + (cmd->func) (cmd, argc - 1, &args[1]); + end = grub_get_time_ms (); + + grub_printf_ (N_("Elapsed time: %d.%03d seconds \n"), (end - start) / 1000, + (end - start) % 1000); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(time) +{ + cmd = grub_register_command ("time", grub_cmd_time, + N_("COMMAND [ARGS]"), + N_("Measure time used by COMMAND")); +} + +GRUB_MOD_FINI(time) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/commands/true.c b/grub-core/commands/true.c index aa8125853..82775e7ef 100644 --- a/grub-core/commands/true.c +++ b/grub-core/commands/true.c @@ -21,6 +21,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_true (struct grub_command *cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c index 7f00c8856..4a051ad1f 100644 --- a/grub-core/commands/usbtest.c +++ b/grub-core/commands/usbtest.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static const char *usb_classes[] = { "Unknown", diff --git a/grub-core/commands/videoinfo.c b/grub-core/commands/videoinfo.c index 10f77915b..9e12ff55e 100644 --- a/grub-core/commands/videoinfo.c +++ b/grub-core/commands/videoinfo.c @@ -25,7 +25,10 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static unsigned height, width, depth; +static struct grub_video_mode_info *current_mode; static int hook (const struct grub_video_mode_info *info) @@ -39,44 +42,74 @@ hook (const struct grub_video_mode_info *info) if (info->mode_number == GRUB_VIDEO_MODE_NUMBER_INVALID) grub_printf (" "); else - grub_printf (" 0x%03x ", info->mode_number); + { + if (current_mode && info->mode_number == current_mode->mode_number) + grub_printf ("*"); + else + grub_printf (" "); + grub_printf (" 0x%03x ", info->mode_number); + } grub_printf ("%4d x %4d x %2d ", info->width, info->height, info->bpp); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) - grub_printf ("Text-only "); + grub_xputs (_("Text-only ")); /* Show mask and position details for direct color modes. */ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_RGB) - grub_printf ("Direct, mask: %d/%d/%d/%d pos: %d/%d/%d/%d", - info->red_mask_size, - info->green_mask_size, - info->blue_mask_size, - info->reserved_mask_size, - info->red_field_pos, - info->green_field_pos, - info->blue_field_pos, - info->reserved_field_pos); + grub_printf_ (N_("Direct, mask: %d/%d/%d/%d pos: %d/%d/%d/%d"), + info->red_mask_size, + info->green_mask_size, + info->blue_mask_size, + info->reserved_mask_size, + info->red_field_pos, + info->green_field_pos, + info->blue_field_pos, + info->reserved_field_pos); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) - grub_printf ("Packed "); + grub_xputs (_("Packed ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_YUV) - grub_printf ("YUV "); + grub_xputs (_("YUV ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PLANAR) - grub_printf ("Planar "); + grub_xputs (_("Planar ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_HERCULES) - grub_printf ("Hercules "); + grub_xputs (_("Hercules ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_CGA) - grub_printf ("CGA "); + grub_xputs (_("CGA ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_NONCHAIN4) - grub_printf ("Non-chain 4 "); + grub_xputs (_("Non-chain 4 ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) - grub_printf ("Monochrome "); + grub_xputs (_("Monochrome ")); if (info->mode_type & GRUB_VIDEO_MODE_TYPE_UNKNOWN) - grub_printf ("Unknown "); + grub_xputs (_("Unknown ")); - grub_printf ("\n"); + grub_xputs ("\n"); return 0; } +static void +print_edid (struct grub_video_edid_info *edid_info) +{ + unsigned int edid_width, edid_height; + + if (grub_video_edid_checksum (edid_info)) + { + grub_puts_ (N_(" EDID checksum invalid")); + grub_errno = GRUB_ERR_NONE; + return; + } + + grub_printf_ (N_(" EDID version: %u.%u\n"), + edid_info->version, edid_info->revision); + if (grub_video_edid_preferred_mode (edid_info, &edid_width, &edid_height) + == GRUB_ERR_NONE) + grub_printf_ (N_(" Preferred mode: %ux%u\n"), edid_width, edid_height); + else + { + grub_printf_ (N_(" No preferred mode available\n")); + grub_errno = GRUB_ERR_NONE; + } +} + static grub_err_t grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) @@ -114,25 +147,38 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), id = grub_video_get_driver_id (); - grub_printf ("List of supported video modes:\n"); - grub_printf ("Legend: P=Packed pixel, D=Direct color, " - "mask/pos=R/G/B/reserved\n"); + grub_puts_ (N_("List of supported video modes:")); + grub_puts_ (N_("Legend: P=Packed pixel, D=Direct color, " + "mask/pos=R/G/B/reserved")); FOR_VIDEO_ADAPTERS (adapter) { - grub_printf ("Adapter '%s':\n", adapter->name); + struct grub_video_mode_info info; + struct grub_video_edid_info edid_info; + + grub_printf_ (N_("Adapter '%s':\n"), adapter->name); if (!adapter->iterate) { - grub_printf (" No info available\n"); + grub_puts_ (N_(" No info available")); continue; } - if (adapter->id != id) + current_mode = NULL; + + if (adapter->id == id) + { + if (grub_video_get_info (&info) == GRUB_ERR_NONE) + current_mode = &info; + else + /* Don't worry about errors. */ + grub_errno = GRUB_ERR_NONE; + } + else { if (adapter->init ()) { - grub_printf (" Failed\n"); + grub_puts_ (N_(" Failed")); grub_errno = GRUB_ERR_NONE; continue; } @@ -143,6 +189,13 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), adapter->iterate (hook); + if (adapter->get_edid && adapter->get_edid (&edid_info) == GRUB_ERR_NONE) + print_edid (&edid_info); + else + grub_errno = GRUB_ERR_NONE; + + current_mode = NULL; + if (adapter->id != id) { if (adapter->fini ()) @@ -162,12 +215,13 @@ static grub_command_t cmd_vbe; GRUB_MOD_INIT(videoinfo) { - cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo, "[WxH[xD]]", + cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo, N_("[WxH[xD]]"), N_("List available video modes. If " "resolution is given show only modes" " matching it.")); #ifdef GRUB_MACHINE_PCBIOS - cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo, "[WxH[xD]]", + cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo, + N_("[WxH[xD]]"), N_("List available video modes. If " "resolution is given show only modes" " matching it.")); diff --git a/grub-core/commands/videotest.c b/grub-core/commands/videotest.c index 435ac2937..11949a6fc 100644 --- a/grub-core/commands/videotest.c +++ b/grub-core/commands/videotest.c @@ -28,6 +28,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) @@ -72,6 +74,8 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), grub_video_create_render_target (&text_layer, width, height, GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_ALPHA); + if (!text_layer) + goto fail; grub_video_set_active_render_target (text_layer); @@ -189,6 +193,11 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), grub_errno = GRUB_ERR_NONE; return grub_errno; + + fail: + grub_video_delete_render_target (text_layer); + grub_video_restore (); + return grub_errno; } static grub_command_t cmd; diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c index 6eab333b3..8afda3c99 100644 --- a/grub-core/commands/wildcard.c +++ b/grub-core/commands/wildcard.c @@ -139,6 +139,7 @@ make_regex (const char *start, const char *end, regex_t *regexp) case '.': case '(': case ')': + case '@': buffer[i++] = '\\'; buffer[i++] = ch; break; @@ -255,8 +256,7 @@ match_devices (const regex_t *regexp, int noparts) for (i = 0; devs && devs[i]; i++) grub_free (devs[i]); - if (devs) - grub_free (devs); + grub_free (devs); return 0; } @@ -266,7 +266,6 @@ 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; @@ -289,6 +288,8 @@ match_files (const char *prefix, const char *suffix, const char *end, if (regexec (regexp, name, 0, 0, 0)) return 0; + grub_dprintf ("expand", "matched\n"); + buffer = grub_xasprintf ("%s%s", dir, name); if (! buffer) return 1; @@ -325,10 +326,15 @@ match_files (const char *prefix, const char *suffix, const char *end, if (! fs) goto fail; - path = grub_strchr (dir, ')'); - if (! path) - goto fail; - path++; + if (dir[0] == '(') + { + path = grub_strchr (dir, ')'); + if (!path) + goto fail; + path++; + } + else + path = dir; if (fs->dir (dev, path, match)) goto fail; @@ -341,20 +347,17 @@ match_files (const char *prefix, const char *suffix, const char *end, fail: - if (dir) - grub_free (dir); + grub_free (dir); for (i = 0; files && files[i]; i++) grub_free (files[i]); - if (files) - grub_free (files); + grub_free (files); if (dev) grub_device_close (dev); - if (device_name) - grub_free (device_name); + grub_free (device_name); grub_error_pop (); return 0; @@ -424,8 +427,6 @@ wildcard_expand (const char *s, char ***strs) while (*start) { split_path (start, &noregexop, ®exop); - if (noregexop >= regexop) /* no more wildcards */ - break; if (make_regex (noregexop, regexop, ®exp)) goto fail; @@ -435,27 +436,8 @@ wildcard_expand (const char *s, char ***strs) if (start == noregexop) /* device part has regexop */ paths = match_devices (®exp, *start != '('); - else if (*start == '(') /* device part explicit wo regexop */ + else /* 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 { diff --git a/grub-core/commands/xnu_uuid.c b/grub-core/commands/xnu_uuid.c index 382d3196b..3d152a6d6 100644 --- a/grub-core/commands/xnu_uuid.c +++ b/grub-core/commands/xnu_uuid.c @@ -34,6 +34,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* This prefix is used by xnu and boot-132 to hash together with volume serial. */ static grub_uint8_t hash_prefix[16] @@ -49,10 +51,18 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *ptr; grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; + int low = 0; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); + if (argc > 1 && grub_strcmp (args[0], "-l") == 0) + { + low = 1; + argc--; + args++; + } + serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); GRUB_MD_MD5->init (&ctx); @@ -73,10 +83,11 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), (unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11], (unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13], (unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]); - for (ptr = uuid_string; *ptr; ptr++) - *ptr = grub_toupper (*ptr); + if (!low) + for (ptr = uuid_string; *ptr; ptr++) + *ptr = grub_toupper (*ptr); if (argc == 1) - grub_printf ("%s", uuid_string); + grub_printf ("%s\n", uuid_string); if (argc > 1) grub_env_set (args[1], uuid_string); @@ -89,9 +100,10 @@ static grub_command_t cmd; GRUB_MOD_INIT (xnu_uuid) { cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid, - N_("GRUBUUID [VARNAME]"), + N_("[-l] GRUBUUID [VARNAME]"), N_("Transform 64-bit UUID to format " - "suitable for XNU.")); + "suitable for XNU. If -l is given keep " + "it lowercase as done by blkid.")); } GRUB_MOD_FINI (xnu_uuid) diff --git a/grub-core/disk/AFSplitter.c b/grub-core/disk/AFSplitter.c new file mode 100644 index 000000000..ebcc35221 --- /dev/null +++ b/grub-core/disk/AFSplitter.c @@ -0,0 +1,89 @@ +/* + * AFsplitter - Anti forensic information splitter + * Copyright 2004, Clemens Fruhwirth + * + * AFsplitter diffuses information over a large stripe of data, + * therefor supporting secure data destruction. + * + * This program is grub_free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the grub_free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the grub_free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, + grub_uint8_t * dst, grub_size_t blocksize, + grub_size_t blocknumbers); + +static void +diffuse (const gcry_md_spec_t * hash, grub_uint8_t * src, + grub_uint8_t * dst, grub_size_t size) +{ + grub_size_t i; + grub_uint32_t IV; /* host byte order independend hash IV */ + + grub_size_t fullblocks = size / hash->mdlen; + int padding = size % hash->mdlen; + grub_uint8_t final[hash->mdlen]; + grub_uint8_t temp[sizeof (IV) + hash->mdlen]; + + /* hash block the whole data set with different IVs to produce + * more than just a single data block + */ + for (i = 0; i < fullblocks; i++) + { + IV = grub_cpu_to_be32 (i); + grub_memcpy (temp, &IV, sizeof (IV)); + grub_memcpy (temp + sizeof (IV), src + hash->mdlen * i, hash->mdlen); + grub_crypto_hash (hash, dst + hash->mdlen * i, temp, + sizeof (IV) + hash->mdlen); + } + + if (padding) + { + IV = grub_cpu_to_be32 (i); + grub_memcpy (temp, &IV, sizeof (IV)); + grub_memcpy (temp + sizeof (IV), src + hash->mdlen * i, padding); + grub_crypto_hash (hash, final, temp, sizeof (IV) + padding); + grub_memcpy (dst + hash->mdlen * i, final, padding); + } +} + +/** + * Merges the splitted master key stored on disk into the original key + */ +gcry_err_code_t +AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, grub_uint8_t * dst, + grub_size_t blocksize, grub_size_t blocknumbers) +{ + grub_size_t i; + grub_uint8_t *bufblock; + + bufblock = grub_zalloc (blocksize); + if (bufblock == NULL) + return GPG_ERR_OUT_OF_MEMORY; + + grub_memset (bufblock, 0, blocksize); + for (i = 0; i < blocknumbers - 1; i++) + { + grub_crypto_xor (bufblock, src + (blocksize * i), bufblock, blocksize); + diffuse (hash, bufblock, bufblock, blocksize); + } + grub_crypto_xor (dst, src + (i * blocksize), bufblock, blocksize); + + grub_free (bufblock); + return GPG_ERR_NO_ERROR; +} diff --git a/grub-core/disk/ahci.c b/grub-core/disk/ahci.c new file mode 100644 index 000000000..8c4fc2bfb --- /dev/null +++ b/grub-core/disk/ahci.c @@ -0,0 +1,740 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_ahci_cmd_head +{ + grub_uint32_t config; + grub_uint32_t transfered; + grub_uint64_t command_table_base; + grub_uint32_t unused[4]; +}; + +struct grub_ahci_prdt_entry +{ + grub_uint64_t data_base; + grub_uint32_t unused; + grub_uint32_t size; +}; + +struct grub_ahci_cmd_table +{ + grub_uint8_t cfis[0x40]; + grub_uint8_t command[0x10]; + grub_uint8_t reserved[0x30]; + struct grub_ahci_prdt_entry prdt[1]; +}; + +struct grub_ahci_hba_port +{ + grub_uint64_t command_list_base; + grub_uint64_t fis_base; + grub_uint32_t intstatus; + grub_uint32_t inten; + grub_uint32_t command; + grub_uint32_t unused1; + grub_uint32_t task_file_data; + grub_uint32_t sig; + grub_uint32_t status; + grub_uint32_t unused2; + grub_uint32_t sata_error; + grub_uint32_t sata_active; + grub_uint32_t command_issue; + grub_uint32_t unused3; + grub_uint32_t fbs; + grub_uint32_t unused4[15]; +}; + +enum grub_ahci_hba_port_command + { + GRUB_AHCI_HBA_PORT_CMD_ST = 0x01, + GRUB_AHCI_HBA_PORT_CMD_FRE = 0x10, + GRUB_AHCI_HBA_PORT_CMD_CR = 0x8000, + GRUB_AHCI_HBA_PORT_CMD_FR = 0x4000, + }; + +struct grub_ahci_hba +{ + grub_uint32_t cap; + grub_uint32_t global_control; + grub_uint32_t intr_status; + grub_uint32_t ports_implemented; + grub_uint32_t unused1[6]; + grub_uint32_t bios_handoff; + grub_uint32_t unused2[53]; + struct grub_ahci_hba_port ports[32]; +}; + +struct grub_ahci_received_fis +{ + char raw[4096]; +}; + +enum + { + GRUB_AHCI_HBA_CAP_NPORTS_MASK = 0x1f + }; + +enum + { + GRUB_AHCI_HBA_GLOBAL_CONTROL_RESET = 0x00000001, + GRUB_AHCI_HBA_GLOBAL_CONTROL_INTR_EN = 0x00000002, + GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN = 0x80000000, + }; + +enum + { + GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED = 1, + GRUB_AHCI_BIOS_HANDOFF_OS_OWNED = 2, + GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED = 8, + GRUB_AHCI_BIOS_HANDOFF_RWC = 8 + }; + + +struct grub_ahci_device +{ + struct grub_ahci_device *next; + struct grub_ahci_device **prev; + volatile struct grub_ahci_hba *hba; + int port; + int num; + struct grub_pci_dma_chunk *command_list_chunk; + volatile struct grub_ahci_cmd_head *command_list; + struct grub_pci_dma_chunk *command_table_chunk; + volatile struct grub_ahci_cmd_table *command_table; + struct grub_pci_dma_chunk *rfis; + int present; +}; + +static grub_err_t +grub_ahci_readwrite_real (struct grub_ahci_device *dev, + struct grub_disk_ata_pass_through_parms *parms, + int spinup); + + +enum + { + GRUB_AHCI_CONFIG_READ = 0, + GRUB_AHCI_CONFIG_CFIS_LENGTH_MASK = 0x1f, + GRUB_AHCI_CONFIG_ATAPI = 0x20, + GRUB_AHCI_CONFIG_WRITE = 0x40, + GRUB_AHCI_CONFIG_PREFETCH = 0x80, + GRUB_AHCI_CONFIG_RESET = 0x100, + GRUB_AHCI_CONFIG_BIST = 0x200, + GRUB_AHCI_CONFIG_CLEAR_R_OK = 0x400, + GRUB_AHCI_CONFIG_PMP_MASK = 0xf000, + GRUB_AHCI_CONFIG_PRDT_LENGTH_MASK = 0xffff0000, + }; +#define GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT 0 +#define GRUB_AHCI_CONFIG_PMP_SHIFT 12 +#define GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT 16 +#define GRUB_AHCI_INTERRUPT_ON_COMPLETE 0x80000000 + +#define GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH 0x200000 + +static struct grub_ahci_device *grub_ahci_devices; +static int numdevs; + +static int +init_port (struct grub_ahci_device *dev) +{ + struct grub_pci_dma_chunk *command_list; + struct grub_pci_dma_chunk *command_table; + grub_uint64_t endtime; + + command_list = grub_memalign_dma32 (1024, sizeof (struct grub_ahci_cmd_head)); + if (!command_list) + return 1; + + command_table = grub_memalign_dma32 (1024, + sizeof (struct grub_ahci_cmd_table)); + if (!command_table) + { + grub_dma_free (command_list); + return 1; + } + + grub_dprintf ("ahci", "found device ahci%d (port %d)\n", dev->num, dev->port); + + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE; + endtime = grub_get_time_ms () + 1000; + while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't stop FR\n"); + goto out; + } + + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST; + endtime = grub_get_time_ms () + 1000; + while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't stop CR\n"); + goto out; + } + + dev->hba->ports[dev->port].fbs = 2; + + dev->rfis = grub_memalign_dma32 (4096, + sizeof (struct grub_ahci_received_fis)); + grub_memset ((char *) grub_dma_get_virt (dev->rfis), 0, + sizeof (struct grub_ahci_received_fis)); + dev->hba->ports[dev->port].fis_base = grub_dma_get_phys (dev->rfis); + dev->hba->ports[dev->port].command_list_base + = grub_dma_get_phys (command_list); + dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_FRE; + while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't start FR\n"); + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE; + goto out; + } + dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST; + while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't start CR\n"); + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_CR; + goto out_stop_fr; + } + + dev->hba->ports[dev->port].command + = (dev->hba->ports[dev->port].command & 0x0fffffff) | (1 << 28) | 2 | 4; + + dev->command_list_chunk = command_list; + dev->command_list = grub_dma_get_virt (command_list); + dev->command_table_chunk = command_table; + dev->command_table = grub_dma_get_virt (command_table); + dev->command_list->command_table_base + = grub_dma_get_phys (command_table); + + return 0; + out_stop_fr: + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE; + endtime = grub_get_time_ms () + 1000; + while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't stop FR\n"); + break; + } + out: + grub_dma_free (command_list); + grub_dma_free (command_table); + grub_dma_free (dev->rfis); + return 1; +} + +static int NESTED_FUNC_ATTR +grub_ahci_pciinit (grub_pci_device_t dev, + grub_pci_id_t pciid __attribute__ ((unused))) +{ + grub_pci_address_t addr; + grub_uint32_t class; + grub_uint32_t bar; + unsigned i, nports; + volatile struct grub_ahci_hba *hba; + + /* Read class. */ + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + class = grub_pci_read (addr); + + /* Check if this class ID matches that of a PCI IDE Controller. */ + if (class >> 8 != 0x010601) + return 0; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG5); + bar = grub_pci_read (addr); + + if ((bar & (GRUB_PCI_ADDR_SPACE_MASK | GRUB_PCI_ADDR_MEM_TYPE_MASK + | GRUB_PCI_ADDR_MEM_PREFETCH)) + != (GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32)) + return 0; + + hba = grub_pci_device_map_range (dev, bar & GRUB_PCI_ADDR_MEM_MASK, + sizeof (hba)); + + if (! (hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_OS_OWNED)) + { + grub_uint64_t endtime; + + grub_dprintf ("ahci", "Requesting AHCI ownership\n"); + hba->bios_handoff = (hba->bios_handoff & ~GRUB_AHCI_BIOS_HANDOFF_RWC) + | GRUB_AHCI_BIOS_HANDOFF_OS_OWNED; + grub_dprintf ("ahci", "Waiting for BIOS to give up ownership\n"); + endtime = grub_get_time_ms () + 1000; + while ((hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED) + && grub_get_time_ms () < endtime); + if (hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED) + { + grub_dprintf ("ahci", "Forcibly taking ownership\n"); + hba->bios_handoff = GRUB_AHCI_BIOS_HANDOFF_OS_OWNED; + hba->bios_handoff |= GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED; + } + else + grub_dprintf ("ahci", "AHCI ownership obtained\n"); + } + else + grub_dprintf ("ahci", "AHCI is already in OS mode\n"); + + if (!(hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN)) + grub_dprintf ("ahci", "AHCI is in compat mode. Switching\n"); + else + grub_dprintf ("ahci", "AHCI is in AHCI mode.\n"); + + for (i = 0; i < 5; i++) + { + hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN; + grub_millisleep (1); + if (hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN) + break; + } + if (i == 5) + { + grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n"); + return 0; + } + + /* + { + grub_uint64_t endtime; + hba->global_control |= 1; + endtime = grub_get_time_ms () + 1000; + while (hba->global_control & 1) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't reset AHCI\n"); + return 0; + } + } + + for (i = 0; i < 5; i++) + { + hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN; + grub_millisleep (1); + if (hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN) + break; + } + if (i == 5) + { + grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n"); + return 0; + } + */ + + nports = (hba->cap & GRUB_AHCI_HBA_CAP_NPORTS_MASK) + 1; + + grub_dprintf ("ahci", "%d AHCI ports\n", nports); + + for (i = 0; i < nports; i++) + { + struct grub_ahci_device *adev; + grub_uint32_t st; + + if (!(hba->ports_implemented & (1 << i))) + continue; + + grub_dprintf ("ahci", "status %d:%x\n", i, hba->ports[i].status); + /* FIXME: support hotplugging. */ + st = hba->ports[i].status; + if ((st & 0xf) != 0x3 && (st & 0xf) != 0x1) + continue; + + adev = grub_malloc (sizeof (*adev)); + if (!adev) + return 1; + + adev->hba = hba; + adev->port = i; + adev->present = 1; + adev->num = numdevs++; + + if (init_port (adev)) + { + grub_free (adev); + return 1; + } + + grub_list_push (GRUB_AS_LIST_P (&grub_ahci_devices), + GRUB_AS_LIST (adev)); + } + + return 0; +} + +static grub_err_t +grub_ahci_initialize (void) +{ + grub_pci_iterate (grub_ahci_pciinit); + return grub_errno; +} + +static grub_err_t +grub_ahci_fini_hw (int noreturn __attribute__ ((unused))) +{ + struct grub_ahci_device *dev; + + for (dev = grub_ahci_devices; dev; dev = dev->next) + { + grub_uint64_t endtime; + + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE; + endtime = grub_get_time_ms () + 1000; + while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't stop FR\n"); + break; + } + + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST; + endtime = grub_get_time_ms () + 1000; + while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't stop CR\n"); + break; + } + grub_dma_free (dev->command_list_chunk); + grub_dma_free (dev->command_table_chunk); + grub_dma_free (dev->rfis); + dev->command_list_chunk = NULL; + dev->command_table_chunk = NULL; + dev->rfis = NULL; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_ahci_restore_hw (void) +{ + struct grub_ahci_device **pdev; + + for (pdev = &grub_ahci_devices; *pdev; pdev = &((*pdev)->next)) + if (init_port (*pdev)) + { + struct grub_ahci_device *odev; + odev = *pdev; + *pdev = (*pdev)->next; + grub_free (odev); + } + return GRUB_ERR_NONE; +} + + + + +static int +grub_ahci_iterate (int (*hook) (int id, int bus), + grub_disk_pull_t pull) +{ + struct grub_ahci_device *dev; + + if (pull != GRUB_DISK_PULL_NONE) + return 0; + + FOR_LIST_ELEMENTS(dev, grub_ahci_devices) + if (hook (GRUB_SCSI_SUBSYSTEM_AHCI, dev->num)) + return 1; + + return 0; +} + +#if 0 +static int +find_free_cmd_slot (struct grub_ahci_device *dev) +{ + int i; + for (i = 0; i < 32; i++) + { + if (dev->hda->ports[dev->port].command_issue & (1 << i)) + continue; + if (dev->hda->ports[dev->port].sata_active & (1 << i)) + continue; + return i; + } + return -1; +} +#endif + +enum + { + GRUB_AHCI_FIS_REG_H2D = 0x27 + }; + +static const int register_map[11] = { 3 /* Features */, + 12 /* Sectors */, + 4 /* LBA low */, + 5 /* LBA mid */, + 6 /* LBA high */, + 7 /* Device */, + 2 /* CMD register */, + 13 /* Sectors 48 */, + 8 /* LBA48 low */, + 9 /* LBA48 mid */, + 10 /* LBA48 high */ }; + +static grub_err_t +grub_ahci_readwrite_real (struct grub_ahci_device *dev, + struct grub_disk_ata_pass_through_parms *parms, + int spinup) +{ + struct grub_pci_dma_chunk *bufc; + grub_uint64_t endtime; + unsigned i; + grub_err_t err = GRUB_ERR_NONE; + + grub_dprintf ("ahci", "AHCI tfd = %x\n", + dev->hba->ports[dev->port].task_file_data); + + if ((dev->hba->ports[dev->port].task_file_data & 0x80)) + { + dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST; + endtime = grub_get_time_ms () + 1000; + while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't stop CR\n"); + break; + } + dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST; + endtime = grub_get_time_ms () + (spinup ? 10000 : 1000); + while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "couldn't start CR\n"); + break; + } + } + + dev->hba->ports[dev->port].sata_error = dev->hba->ports[dev->port].sata_error; + + grub_dprintf("ahci", "grub_ahci_read (size=%llu, cmdsize = %llu)\n", + (unsigned long long) parms->size, + (unsigned long long) parms->cmdsize); + + if (parms->cmdsize != 0 && parms->cmdsize != 12 && parms->cmdsize != 16) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "incorrect ATAPI command size"); + + if (parms->size > GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "too big data buffer"); + + bufc = grub_memalign_dma32 (1024, parms->size + (parms->size & 1)); + + dev->hba->ports[dev->port].command |= 8; + + grub_dprintf ("ahci", "AHCI tfd = %x\n", + dev->hba->ports[dev->port].task_file_data); + /* FIXME: support port multipliers. */ + dev->command_list[0].config + = (5 << GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT) + // | GRUB_AHCI_CONFIG_CLEAR_R_OK + | (0 << GRUB_AHCI_CONFIG_PMP_SHIFT) + | (1 << GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT) + | (parms->cmdsize ? GRUB_AHCI_CONFIG_ATAPI : 0) + | (parms->write ? GRUB_AHCI_CONFIG_WRITE : GRUB_AHCI_CONFIG_READ) + | (parms->taskfile.cmd == 8 ? (1 << 8) : 0); + dev->command_list[0].transfered = 0; + dev->command_list[0].command_table_base + = grub_dma_get_phys (dev->command_table_chunk); + grub_memset ((char *) dev->command_list[0].unused, 0, + sizeof (dev->command_list[0].unused)); + grub_memset ((char *) &dev->command_table[0], 0, + sizeof (dev->command_table[0])); + if (parms->cmdsize) + grub_memcpy ((char *) dev->command_table[0].command, parms->cmd, + parms->cmdsize); + + dev->command_table[0].cfis[0] = GRUB_AHCI_FIS_REG_H2D; + dev->command_table[0].cfis[1] = 0x80; + for (i = 0; i < sizeof (parms->taskfile.raw); i++) + dev->command_table[0].cfis[register_map[i]] = parms->taskfile.raw[i]; + + grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n", + dev->command_table[0].cfis[0], dev->command_table[0].cfis[1], + dev->command_table[0].cfis[2], dev->command_table[0].cfis[3], + dev->command_table[0].cfis[4], dev->command_table[0].cfis[5], + dev->command_table[0].cfis[6], dev->command_table[0].cfis[7]); + grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n", + dev->command_table[0].cfis[8], dev->command_table[0].cfis[9], + dev->command_table[0].cfis[10], dev->command_table[0].cfis[11], + dev->command_table[0].cfis[12], dev->command_table[0].cfis[13], + dev->command_table[0].cfis[14], dev->command_table[0].cfis[15]); + + dev->command_table[0].prdt[0].data_base = grub_dma_get_phys (bufc); + dev->command_table[0].prdt[0].unused = 0; + dev->command_table[0].prdt[0].size = (parms->size + (parms->size & 1) - 1) + | GRUB_AHCI_INTERRUPT_ON_COMPLETE; + + grub_dprintf ("ahci", "PRDT = %" PRIxGRUB_UINT64_T ", %x, %x (%" + PRIuGRUB_SIZE ")\n", + dev->command_table[0].prdt[0].data_base, + dev->command_table[0].prdt[0].unused, + dev->command_table[0].prdt[0].size, + (char *) &dev->command_table[0].prdt[0] + - (char *) &dev->command_table[0]); + + if (parms->write) + grub_memcpy ((char *) grub_dma_get_virt (bufc), parms->buffer, parms->size); + + grub_dprintf ("ahci", "AHCI command schedulded\n"); + grub_dprintf ("ahci", "AHCI tfd = %x\n", + dev->hba->ports[dev->port].task_file_data); + dev->hba->ports[dev->port].inten = 0xffffffff;//(1 << 2) | (1 << 5); + dev->hba->ports[dev->port].intstatus = 0xffffffff;//(1 << 2) | (1 << 5); + grub_dprintf ("ahci", "AHCI tfd = %x\n", + dev->hba->ports[dev->port].task_file_data); + dev->hba->ports[dev->port].command_issue |= 1; + grub_dprintf ("ahci", "AHCI sig = %x\n", dev->hba->ports[dev->port].sig); + grub_dprintf ("ahci", "AHCI tfd = %x\n", + dev->hba->ports[dev->port].task_file_data); + + endtime = grub_get_time_ms () + (spinup ? 10000 : 1000); + while ((dev->hba->ports[dev->port].command_issue & 1)) + if (grub_get_time_ms () > endtime) + { + grub_dprintf ("ahci", "AHCI status <%x %x %x>\n", + dev->hba->ports[dev->port].command_issue, + dev->hba->ports[dev->port].intstatus, + dev->hba->ports[dev->port].task_file_data); + err = grub_error (GRUB_ERR_IO, "AHCI transfer timeouted"); + break; + } + + grub_dprintf ("ahci", "AHCI command completed <%x %x %x %x %x, %x %x>\n", + dev->hba->ports[dev->port].command_issue, + dev->hba->ports[dev->port].intstatus, + dev->hba->ports[dev->port].task_file_data, + dev->command_list[0].transfered, + dev->hba->ports[dev->port].sata_error, + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x00], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x18]); + grub_dprintf ("ahci", + "last PIO FIS %08x %08x %08x %08x %08x %08x %08x %08x\n", + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x08], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x09], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0a], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0b], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0c], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0d], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0e], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0f]); + grub_dprintf ("ahci", + "last REG FIS %08x %08x %08x %08x %08x %08x %08x %08x\n", + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x10], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x11], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x12], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x13], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x14], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x15], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x16], + ((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x17]); + + if (!parms->write) + grub_memcpy (parms->buffer, (char *) grub_dma_get_virt (bufc), parms->size); + grub_dma_free (bufc); + + return err; +} + +static grub_err_t +grub_ahci_readwrite (grub_ata_t disk, + struct grub_disk_ata_pass_through_parms *parms, + int spinup) +{ + return grub_ahci_readwrite_real (disk->data, parms, spinup); +} + +static grub_err_t +grub_ahci_open (int id, int devnum, struct grub_ata *ata) +{ + struct grub_ahci_device *dev; + + if (id != GRUB_SCSI_SUBSYSTEM_AHCI) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an AHCI device"); + + FOR_LIST_ELEMENTS(dev, grub_ahci_devices) + if (dev->num == devnum) + break; + + if (! dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such AHCI device"); + + grub_dprintf ("ahci", "opening AHCI dev `ahci%d'\n", dev->num); + + ata->data = dev; + ata->dma = 1; + ata->maxbuffer = GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH; + ata->present = &dev->present; + + return GRUB_ERR_NONE; +} + +static struct grub_ata_dev grub_ahci_dev = + { + .iterate = grub_ahci_iterate, + .open = grub_ahci_open, + .readwrite = grub_ahci_readwrite, + }; + + + +static struct grub_preboot *fini_hnd; + +GRUB_MOD_INIT(ahci) +{ + /* To prevent two drivers operating on the same disks. */ + grub_disk_firmware_is_tainted = 1; + if (grub_disk_firmware_fini) + { + grub_disk_firmware_fini (); + grub_disk_firmware_fini = NULL; + } + + /* AHCI initialization. */ + grub_ahci_initialize (); + + /* AHCI devices are handled by scsi.mod. */ + grub_ata_dev_register (&grub_ahci_dev); + + fini_hnd = grub_loader_register_preboot_hook (grub_ahci_fini_hw, + grub_ahci_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); +} + +GRUB_MOD_FINI(ahci) +{ + grub_ahci_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); + + grub_ata_dev_unregister (&grub_ahci_dev); +} diff --git a/grub-core/disk/arc/arcdisk.c b/grub-core/disk/arc/arcdisk.c new file mode 100644 index 000000000..198dfcfff --- /dev/null +++ b/grub-core/disk/arc/arcdisk.c @@ -0,0 +1,329 @@ +/* ofdisk.c - Open Firmware disk access. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2006,2007,2008,2009,2011 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 + +static grub_arc_fileno_t last_handle = 0; +static char *last_path = NULL; +static int handle_writable = 0; + +static int lnum = 0; + +struct arcdisk_hash_ent +{ + char *devpath; + int num; + struct arcdisk_hash_ent *next; +}; + +#define ARCDISK_HASH_SZ 8 +static struct arcdisk_hash_ent *arcdisk_hash[ARCDISK_HASH_SZ]; + +static int +arcdisk_hash_fn (const char *devpath) +{ + int hash = 0; + while (*devpath) + hash ^= *devpath++; + return (hash & (ARCDISK_HASH_SZ - 1)); +} + +static struct arcdisk_hash_ent * +arcdisk_hash_find (const char *devpath) +{ + struct arcdisk_hash_ent *p = arcdisk_hash[arcdisk_hash_fn (devpath)]; + + while (p) + { + if (!grub_strcmp (p->devpath, devpath)) + break; + p = p->next; + } + return p; +} + +static struct arcdisk_hash_ent * +arcdisk_hash_add (char *devpath) +{ + struct arcdisk_hash_ent *p; + struct arcdisk_hash_ent **head = &arcdisk_hash[arcdisk_hash_fn(devpath)]; + + p = grub_malloc (sizeof (*p)); + if (!p) + return NULL; + + p->devpath = devpath; + p->next = *head; + p->num = lnum++; + *head = p; + return p; +} + + +static int +grub_arcdisk_iterate (int (*hook_in) (const char *name), + grub_disk_pull_t pull) +{ + auto int hook (const char *name, const struct grub_arc_component *comp); + int hook (const char *name, const struct grub_arc_component *comp) + { + if (!(comp->type == GRUB_ARC_COMPONENT_TYPE_DISK + || comp->type == GRUB_ARC_COMPONENT_TYPE_DISK + || comp->type == GRUB_ARC_COMPONENT_TYPE_TAPE)) + return 0; + return hook_in (name); + } + if (pull != GRUB_DISK_PULL_NONE) + return 0; + + return grub_arc_iterate_devs (hook, 1); +} + +#define RAW_SUFFIX "partition(10)" + +static grub_err_t +reopen (const char *name, int writable) +{ + grub_arc_fileno_t handle; + + if (last_path && grub_strcmp (last_path, name) == 0 + && (!writable || handle_writable)) + { + grub_dprintf ("arcdisk", "using already opened %s\n", name); + return GRUB_ERR_NONE; + } + if (last_path) + { + GRUB_ARC_FIRMWARE_VECTOR->close (last_handle); + grub_free (last_path); + last_path = NULL; + last_handle = 0; + handle_writable = 0; + } + if (GRUB_ARC_FIRMWARE_VECTOR->open (name, + writable ? GRUB_ARC_FILE_ACCESS_OPEN_RW + : GRUB_ARC_FILE_ACCESS_OPEN_RO, &handle)) + { + grub_dprintf ("arcdisk", "couldn't open %s\n", name); + return grub_error (GRUB_ERR_IO, "couldn't open %s", name); + } + handle_writable = writable; + last_path = grub_strdup (name); + if (!last_path) + return grub_errno; + last_handle = handle; + grub_dprintf ("arcdisk", "opened %s\n", name); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_arcdisk_open (const char *name, grub_disk_t disk) +{ + char *fullname, *optr; + const char *iptr; + int state = 0; + grub_err_t err; + grub_arc_err_t r; + struct grub_arc_fileinfo info; + struct arcdisk_hash_ent *hash; + + if (grub_memcmp (name, "arc/", 4) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not arc device"); + fullname = grub_malloc (2 * grub_strlen (name) + sizeof (RAW_SUFFIX)); + if (!fullname) + return grub_errno; + optr = fullname; + for (iptr = name + 4; *iptr; iptr++) + if (state == 0) + { + if (!grub_isdigit (*iptr)) + *optr++ = *iptr; + else + { + *optr++ = '('; + *optr++ = *iptr; + state = 1; + } + } + else + { + if (grub_isdigit (*iptr)) + *optr++ = *iptr; + else + { + *optr++ = ')'; + state = 0; + } + } + if (state) + *optr++ = ')'; + grub_memcpy (optr, RAW_SUFFIX, sizeof (RAW_SUFFIX)); + disk->data = fullname; + grub_dprintf ("arcdisk", "opening %s\n", fullname); + + hash = arcdisk_hash_find (fullname); + if (!hash) + hash = arcdisk_hash_add (fullname); + if (!hash) + return grub_errno; + + err = reopen (fullname, 0); + if (err) + return err; + + r = GRUB_ARC_FIRMWARE_VECTOR->getfileinformation (last_handle, &info); + if (r) + { + grub_uint64_t res = 0; + int i; + + grub_dprintf ("arcdisk", "couldn't retrieve size: %ld\n", r); + for (i = 40; i >= 9; i--) + { + grub_uint64_t pos = res | (1ULL << i); + char buf[512]; + long unsigned count = 0; + grub_dprintf ("arcdisk", + "seek to 0x%" PRIxGRUB_UINT64_T "\n", pos); + if (GRUB_ARC_FIRMWARE_VECTOR->seek (last_handle, &pos, 0)) + continue; + if (GRUB_ARC_FIRMWARE_VECTOR->read (last_handle, buf, + 0x200, &count)) + continue; + if (count == 0) + continue; + res |= (1ULL << i); + } + grub_dprintf ("arcdisk", + "determined disk size 0x%" PRIxGRUB_UINT64_T "\n", res); + disk->total_sectors = (res + 0x200) >> 9; + } + else + disk->total_sectors = (info.end >> 9); + + disk->id = hash->num; + return GRUB_ERR_NONE; +} + +static void +grub_arcdisk_close (grub_disk_t disk) +{ + grub_free (disk->data); +} + +static grub_err_t +grub_arcdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_err_t err; + grub_uint64_t pos = sector << 9; + unsigned long count; + grub_uint64_t totl = size << 9; + grub_arc_err_t r; + + err = reopen (disk->data, 0); + if (err) + return err; + r = GRUB_ARC_FIRMWARE_VECTOR->seek (last_handle, &pos, 0); + if (r) + { + grub_dprintf ("arcdisk", "seek to 0x%" PRIxGRUB_UINT64_T " failed: %ld\n", + pos, r); + return grub_error (GRUB_ERR_IO, "couldn't seek"); + } + + while (totl) + { + if (GRUB_ARC_FIRMWARE_VECTOR->read (last_handle, buf, + totl, &count)) + return grub_error (GRUB_ERR_READ_ERROR, "read failed"); + totl -= count; + buf += count; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_arcdisk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + grub_err_t err; + grub_uint64_t pos = sector << 9; + unsigned long count; + grub_uint64_t totl = size << 9; + grub_arc_err_t r; + + err = reopen (disk->data, 1); + if (err) + return err; + r = GRUB_ARC_FIRMWARE_VECTOR->seek (last_handle, &pos, 0); + if (r) + { + grub_dprintf ("arcdisk", "seek to 0x%" PRIxGRUB_UINT64_T " failed: %ld\n", + pos, r); + return grub_error (GRUB_ERR_IO, "couldn't seek"); + } + + while (totl) + { + if (GRUB_ARC_FIRMWARE_VECTOR->write (last_handle, buf, + totl, &count)) + return grub_error (GRUB_ERR_WRITE_ERROR, "write failed"); + totl -= count; + buf += count; + } + + return GRUB_ERR_NONE; +} + +static struct grub_disk_dev grub_arcdisk_dev = + { + .name = "arcdisk", + .id = GRUB_DISK_DEVICE_ARCDISK_ID, + .iterate = grub_arcdisk_iterate, + .open = grub_arcdisk_open, + .close = grub_arcdisk_close, + .read = grub_arcdisk_read, + .write = grub_arcdisk_write, + .next = 0 + }; + +void +grub_arcdisk_init (void) +{ + grub_disk_dev_register (&grub_arcdisk_dev); +} + +void +grub_arcdisk_fini (void) +{ + if (last_path) + { + GRUB_ARC_FIRMWARE_VECTOR->close (last_handle); + grub_free (last_path); + last_path = NULL; + last_handle = 0; + } + + grub_disk_dev_unregister (&grub_arcdisk_dev); +} diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c index fe677e2a0..c90e86832 100644 --- a/grub-core/disk/ata.c +++ b/grub-core/disk/ata.c @@ -21,158 +21,74 @@ #include #include #include -#include -#include #include -#include -/* At the moment, only two IDE ports are supported. */ -static const grub_port_t grub_ata_ioaddress[] = { GRUB_ATA_CH0_PORT1, - GRUB_ATA_CH1_PORT1 }; -static const grub_port_t grub_ata_ioaddress2[] = { GRUB_ATA_CH0_PORT2, - GRUB_ATA_CH1_PORT2 }; +GRUB_MOD_LICENSE ("GPLv3+"); -static struct grub_ata_device *grub_ata_devices; - -/* Wait for !BSY. */ -grub_err_t -grub_ata_wait_not_busy (struct grub_ata_device *dev, int milliseconds) -{ - /* ATA requires 400ns (after a write to CMD register) or - 1 PIO cycle (after a DRQ block transfer) before - first check of BSY. */ - grub_millisleep (1); - - int i = 1; - grub_uint8_t sts; - while ((sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS)) - & GRUB_ATA_STATUS_BUSY) - { - if (i >= milliseconds) - { - grub_dprintf ("ata", "timeout: %dms, status=0x%x\n", - milliseconds, sts); - return grub_error (GRUB_ERR_TIMEOUT, "ATA timeout"); - } - - grub_millisleep (1); - i++; - } - - return GRUB_ERR_NONE; -} - -static inline void -grub_ata_wait (void) -{ - grub_millisleep (50); -} - -/* Wait for !BSY, DRQ. */ -grub_err_t -grub_ata_wait_drq (struct grub_ata_device *dev, int rw, - int milliseconds) -{ - if (grub_ata_wait_not_busy (dev, milliseconds)) - return grub_errno; - - /* !DRQ implies error condition. */ - grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); - if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) - != GRUB_ATA_STATUS_DRQ) - { - grub_dprintf ("ata", "ata error: status=0x%x, error=0x%x\n", - sts, grub_ata_regget (dev, GRUB_ATA_REG_ERROR)); - if (! rw) - return grub_error (GRUB_ERR_READ_ERROR, "ATA read error"); - else - return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error"); - } - - return GRUB_ERR_NONE; -} +static grub_ata_dev_t grub_ata_dev_list; /* Byteorder has to be changed before strings can be read. */ static void -grub_ata_strncpy (char *dst, char *src, grub_size_t len) +grub_ata_strncpy (grub_uint16_t *dst16, grub_uint16_t *src16, grub_size_t len) { - grub_uint16_t *src16 = (grub_uint16_t *) src; - grub_uint16_t *dst16 = (grub_uint16_t *) dst; unsigned int i; for (i = 0; i < len / 2; i++) *(dst16++) = grub_be_to_cpu16 (*(src16++)); - dst[len] = '\0'; -} - -void -grub_ata_pio_read (struct grub_ata_device *dev, char *buf, grub_size_t size) -{ - grub_uint16_t *buf16 = (grub_uint16_t *) buf; - unsigned int i; - - /* Read in the data, word by word. */ - for (i = 0; i < size / 2; i++) - buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA)); + dst16[i] = 0; } static void -grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size) +grub_ata_dumpinfo (struct grub_ata *dev, grub_uint16_t *info) { - grub_uint16_t *buf16 = (grub_uint16_t *) buf; - unsigned int i; - - /* Write the data, word by word. */ - for (i = 0; i < size / 2; i++) - grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA); -} - -static void -grub_ata_dumpinfo (struct grub_ata_device *dev, char *info) -{ - char text[41]; + grub_uint16_t text[21]; /* The device information was read, dump it for debugging. */ - grub_ata_strncpy (text, info + 20, 20); - grub_dprintf ("ata", "Serial: %s\n", text); - grub_ata_strncpy (text, info + 46, 8); - grub_dprintf ("ata", "Firmware: %s\n", text); - grub_ata_strncpy (text, info + 54, 40); - grub_dprintf ("ata", "Model: %s\n", text); + grub_ata_strncpy (text, info + 10, 20); + grub_dprintf ("ata", "Serial: %s\n", (char *) text); + grub_ata_strncpy (text, info + 23, 8); + grub_dprintf ("ata", "Firmware: %s\n", (char *) text); + grub_ata_strncpy (text, info + 27, 40); + grub_dprintf ("ata", "Model: %s\n", (char *) text); if (! dev->atapi) { grub_dprintf ("ata", "Addressing: %d\n", dev->addr); grub_dprintf ("ata", "Sectors: %lld\n", (unsigned long long) dev->size); + grub_dprintf ("ata", "Sector size: %u\n", 1U << dev->log_sector_size); } } static grub_err_t -grub_atapi_identify (struct grub_ata_device *dev) +grub_atapi_identify (struct grub_ata *dev) { - char *info; + struct grub_disk_ata_pass_through_parms parms; + grub_uint16_t *info; + grub_err_t err; info = grub_malloc (GRUB_DISK_SECTOR_SIZE); if (! info) return grub_errno; - grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4); - grub_ata_wait (); - if (grub_ata_check_ready (dev)) + grub_memset (&parms, 0, sizeof (parms)); + parms.taskfile.disk = 0xE0; + parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE; + parms.size = GRUB_DISK_SECTOR_SIZE; + parms.buffer = info; + + err = dev->dev->readwrite (dev, &parms, *dev->present); + if (err) { - grub_free (info); - return grub_errno; + *dev->present = 0; + return err; } - grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE); - grub_ata_wait (); - - if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD)) + if (parms.size != GRUB_DISK_SECTOR_SIZE) { - grub_free (info); - return grub_errno; + *dev->present = 0; + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "device cannot be identified"); } - grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE); dev->atapi = 1; @@ -184,120 +100,53 @@ grub_atapi_identify (struct grub_ata_device *dev) } static grub_err_t -grub_atapi_wait_drq (struct grub_ata_device *dev, - grub_uint8_t ireason, - int milliseconds) +grub_ata_identify (struct grub_ata *dev) { - /* Wait for !BSY, DRQ, ireason */ - if (grub_ata_wait_not_busy (dev, milliseconds)) - return grub_errno; - - grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); - grub_uint8_t irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON); - - /* OK if DRQ is asserted and interrupt reason is as expected. */ - if ((sts & GRUB_ATA_STATUS_DRQ) - && (irs & GRUB_ATAPI_IREASON_MASK) == ireason) - return GRUB_ERR_NONE; - - /* !DRQ implies error condition. */ - grub_dprintf ("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n", - sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR)); - - if (! (sts & GRUB_ATA_STATUS_DRQ) - && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR) - { - if (ireason == GRUB_ATAPI_IREASON_CMD_OUT) - return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error"); - else - return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error"); - } - - return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error"); -} - -static grub_err_t -grub_atapi_packet (struct grub_ata_device *dev, char *packet, - grub_size_t size) -{ - grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); - if (grub_ata_check_ready (dev)) - return grub_errno; - - /* Send ATA PACKET command. */ - grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0); - grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0); - grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8); - grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF); - - grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET); - - /* Wait for !BSY, DRQ, !I/O, C/D. */ - if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD)) - return grub_errno; - - /* Write the packet. */ - grub_ata_pio_write (dev, packet, 12); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_ata_identify (struct grub_ata_device *dev) -{ - char *info; + struct grub_disk_ata_pass_through_parms parms; + grub_uint64_t *info64; + grub_uint32_t *info32; grub_uint16_t *info16; + grub_err_t err; - info = grub_malloc (GRUB_DISK_SECTOR_SIZE); - if (! info) + info64 = grub_malloc (GRUB_DISK_SECTOR_SIZE); + info32 = (grub_uint32_t *) info64; + info16 = (grub_uint16_t *) info64; + if (! info16) return grub_errno; - info16 = (grub_uint16_t *) info; + grub_memset (&parms, 0, sizeof (parms)); + parms.buffer = info16; + parms.size = GRUB_DISK_SECTOR_SIZE; + parms.taskfile.disk = 0xE0; - grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4); - grub_ata_wait (); - if (grub_ata_check_ready (dev)) + parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_DEVICE; + + err = dev->dev->readwrite (dev, &parms, *dev->present); + + if (err || parms.size != GRUB_DISK_SECTOR_SIZE) { - grub_free (info); - return grub_errno; - } - - grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE); - grub_ata_wait (); - - if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD)) - { - grub_free (info); + grub_uint8_t sts = parms.taskfile.status; + grub_free (info16); grub_errno = GRUB_ERR_NONE; - grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); - if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR - && (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04 /* ABRT */)) + && (parms.taskfile.error & 0x04 /* ABRT */)) /* Device without ATA IDENTIFY, try ATAPI. */ return grub_atapi_identify (dev); else if (sts == 0x00) - /* No device, return error but don't print message. */ - return GRUB_ERR_UNKNOWN_DEVICE; - + { + *dev->present = 0; + /* No device, return error but don't print message. */ + return GRUB_ERR_UNKNOWN_DEVICE; + } else - /* Other Error. */ - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "device cannot be identified"); - } - - grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE); - - /* Re-check status to avoid bogus identify data due to stuck DRQ. */ - grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); - if (sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) - { - grub_dprintf ("ata", "bad status=0x%x\n", sts); - grub_free (info); - /* No device, return error but don't print message. */ - grub_errno = GRUB_ERR_NONE; - return GRUB_ERR_UNKNOWN_DEVICE; + { + *dev->present = 0; + /* Other Error. */ + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "device cannot be identified"); + } } /* Now it is certain that this is not an ATAPI device. */ @@ -318,211 +167,43 @@ grub_ata_identify (struct grub_ata_device *dev) /* Determine the amount of sectors. */ if (dev->addr != GRUB_ATA_LBA48) - dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60])); + dev->size = grub_le_to_cpu32 (info32[30]); else - dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100])); + dev->size = grub_le_to_cpu64 (info64[25]); + + if (info16[106] & (1 << 12)) + { + grub_uint32_t secsize; + secsize = grub_le_to_cpu32 (grub_get_unaligned32 (&info16[117])); + if (secsize & (secsize - 1) || !secsize + || secsize > 1048576) + secsize = 256; + for (dev->log_sector_size = 0; + (1U << dev->log_sector_size) < secsize; + dev->log_sector_size++); + dev->log_sector_size++; + } + else + dev->log_sector_size = 9; /* Read CHS information. */ dev->cylinders = info16[1]; dev->heads = info16[3]; dev->sectors_per_track = info16[6]; - grub_ata_dumpinfo (dev, info); + grub_ata_dumpinfo (dev, info16); - grub_free(info); + grub_free (info16); return 0; } static grub_err_t -check_device (struct grub_ata_device *dev) -{ - grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); - grub_ata_wait (); - - /* Try to detect if the port is in use by writing to it, - waiting for a while and reading it again. If the value - was preserved, there is a device connected. */ - grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A); - grub_ata_wait (); - grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS); - grub_dprintf ("ata", "sectors=0x%x\n", sec); - if (sec != 0x5A) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected"); - - /* The above test may detect a second (slave) device - connected to a SATA controller which supports only one - (master) device. It is not safe to use the status register - READY bit to check for controller channel existence. Some - ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */ - - /* Use the IDENTIFY DEVICE command to query the device. */ - return grub_ata_identify (dev); -} - -static grub_err_t -grub_ata_device_initialize (int port, int device, int addr, int addr2) -{ - struct grub_ata_device *dev; - struct grub_ata_device **devp; - grub_err_t err; - - grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n", - port, device, addr, addr2); - - dev = grub_malloc (sizeof(*dev)); - if (! dev) - return grub_errno; - - /* Setup the device information. */ - dev->port = port; - dev->device = device; - dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE; - dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE; - dev->next = NULL; - - /* Register the device. */ - for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next); - *devp = dev; - - err = check_device (dev); - if (err) - grub_print_error (); - - return 0; -} - -static int NESTED_FUNC_ATTR -grub_ata_pciinit (grub_pci_device_t dev, - grub_pci_id_t pciid) -{ - static int compat_use[2] = { 0 }; - grub_pci_address_t addr; - grub_uint32_t class; - grub_uint32_t bar1; - grub_uint32_t bar2; - int rega; - int regb; - int i; - static int controller = 0; - int cs5536 = 0; - int nports = 2; - - /* Read class. */ - addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); - class = grub_pci_read (addr); - - /* AMD CS5536 Southbridge. */ - if (pciid == GRUB_CS5536_PCIID) - { - cs5536 = 1; - nports = 1; - } - - /* Check if this class ID matches that of a PCI IDE Controller. */ - if (!cs5536 && (class >> 16 != 0x0101)) - return 0; - - for (i = 0; i < nports; i++) - { - /* Set to 0 when the channel operated in compatibility mode. */ - int compat; - - /* We don't support non-compatibility mode for CS5536. */ - if (cs5536) - compat = 0; - else - compat = (class >> (8 + 2 * i)) & 1; - - rega = 0; - regb = 0; - - /* If the channel is in compatibility mode, just assign the - default registers. */ - if (compat == 0 && !compat_use[i]) - { - rega = grub_ata_ioaddress[i]; - regb = grub_ata_ioaddress2[i]; - compat_use[i] = 1; - } - else if (compat) - { - /* Read the BARs, which either contain a mmapped IO address - or the IO port address. */ - addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES - + sizeof (grub_uint64_t) * i); - bar1 = grub_pci_read (addr); - addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES - + sizeof (grub_uint64_t) * i - + sizeof (grub_uint32_t)); - bar2 = grub_pci_read (addr); - - /* Check if the BARs describe an IO region. */ - if ((bar1 & 1) && (bar2 & 1)) - { - rega = bar1 & ~3; - regb = bar2 & ~3; - } - } - - grub_dprintf ("ata", - "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n", - grub_pci_get_bus (dev), grub_pci_get_device (dev), - grub_pci_get_function (dev), compat, rega, regb); - - if (rega && regb) - { - grub_errno = GRUB_ERR_NONE; - grub_ata_device_initialize (controller * 2 + i, 0, rega, regb); - - /* Most errors raised by grub_ata_device_initialize() are harmless. - They just indicate this particular drive is not responding, most - likely because it doesn't exist. We might want to ignore specific - error types here, instead of printing them. */ - if (grub_errno) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - } - - grub_ata_device_initialize (controller * 2 + i, 1, rega, regb); - - /* Likewise. */ - if (grub_errno) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - } - } - } - - controller++; - - return 0; -} - -static grub_err_t -grub_ata_initialize (void) -{ - grub_pci_iterate (grub_ata_pciinit); - return 0; -} - -static void -grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector, - grub_size_t size) -{ - grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size); - grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF); - grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF); - grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF); -} - -static grub_err_t -grub_ata_setaddress (struct grub_ata_device *dev, - grub_ata_addressing_t addressing, +grub_ata_setaddress (struct grub_ata *dev, + struct grub_disk_ata_pass_through_parms *parms, grub_disk_addr_t sector, - grub_size_t size) + grub_size_t size, + grub_ata_addressing_t addressing) { switch (addressing) { @@ -544,14 +225,11 @@ grub_ata_setaddress (struct grub_ata_device *dev, return grub_error (GRUB_ERR_OUT_OF_RANGE, "sector %d cannot be addressed " "using CHS addressing", sector); - - grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head); - if (grub_ata_check_ready (dev)) - return grub_errno; - - grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect); - grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF); - grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8); + + parms->taskfile.disk = 0xE0 | head; + parms->taskfile.sectnum = sect; + parms->taskfile.cyllsb = cylinder & 0xFF; + parms->taskfile.cylmsb = cylinder >> 8; break; } @@ -559,26 +237,31 @@ grub_ata_setaddress (struct grub_ata_device *dev, case GRUB_ATA_LBA: if (size == 256) size = 0; - grub_ata_regset (dev, GRUB_ATA_REG_DISK, - 0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F)); - if (grub_ata_check_ready (dev)) - return grub_errno; + parms->taskfile.disk = 0xE0 | ((sector >> 24) & 0x0F); - grub_ata_setlba (dev, sector, size); + parms->taskfile.sectors = size; + parms->taskfile.lba_low = sector & 0xFF; + parms->taskfile.lba_mid = (sector >> 8) & 0xFF; + parms->taskfile.lba_high = (sector >> 16) & 0xFF; break; case GRUB_ATA_LBA48: if (size == 65536) size = 0; - grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4)); - if (grub_ata_check_ready (dev)) - return grub_errno; + parms->taskfile.disk = 0xE0; /* Set "Previous". */ - grub_ata_setlba (dev, sector >> 24, size >> 8); + parms->taskfile.sectors = size & 0xFF; + parms->taskfile.lba_low = sector & 0xFF; + parms->taskfile.lba_mid = (sector >> 8) & 0xFF; + parms->taskfile.lba_high = (sector >> 16) & 0xFF; + /* Set "Current". */ - grub_ata_setlba (dev, sector, size); + parms->taskfile.sectors48 = (size >> 8) & 0xFF; + parms->taskfile.lba48_low = (sector >> 24) & 0xFF; + parms->taskfile.lba48_mid = (sector >> 32) & 0xFF; + parms->taskfile.lba48_high = (sector >> 40) & 0xFF; break; } @@ -590,70 +273,77 @@ static grub_err_t grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf, int rw) { - struct grub_ata_device *dev = (struct grub_ata_device *) disk->data; + struct grub_ata *ata = disk->data; - grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n", (unsigned long long) size, rw); - - grub_ata_addressing_t addressing = dev->addr; + grub_ata_addressing_t addressing = ata->addr; grub_size_t batch; int cmd, cmd_write; + grub_size_t nsectors = 0; + + grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n", + (unsigned long long) size, rw); if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0) { batch = 65536; - cmd = GRUB_ATA_CMD_READ_SECTORS_EXT; - cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT; + if (ata->dma) + { + cmd = GRUB_ATA_CMD_READ_SECTORS_DMA_EXT; + cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_DMA_EXT; + } + else + { + cmd = GRUB_ATA_CMD_READ_SECTORS_EXT; + cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT; + } } else { if (addressing == GRUB_ATA_LBA48) addressing = GRUB_ATA_LBA; - batch = 256; - cmd = GRUB_ATA_CMD_READ_SECTORS; - cmd_write = GRUB_ATA_CMD_WRITE_SECTORS; + if (addressing != GRUB_ATA_CHS) + batch = 256; + else + batch = 1; + if (ata->dma) + { + cmd = GRUB_ATA_CMD_READ_SECTORS_DMA; + cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_DMA; + } + else + { + cmd = GRUB_ATA_CMD_READ_SECTORS; + cmd_write = GRUB_ATA_CMD_WRITE_SECTORS; + } } - grub_size_t nsectors = 0; + if (batch > (ata->maxbuffer >> ata->log_sector_size)) + batch = (ata->maxbuffer >> ata->log_sector_size); + while (nsectors < size) { + struct grub_disk_ata_pass_through_parms parms; + grub_err_t err; + if (size - nsectors < batch) batch = size - nsectors; grub_dprintf("ata", "rw=%d, sector=%llu, batch=%llu\n", rw, (unsigned long long) sector, (unsigned long long) batch); - - /* Send read/write command. */ - if (grub_ata_setaddress (dev, addressing, sector, batch)) - return grub_errno; - - grub_ata_regset (dev, GRUB_ATA_REG_CMD, (! rw ? cmd : cmd_write)); - - unsigned sect; - for (sect = 0; sect < batch; sect++) - { - /* Wait for !BSY, DRQ. */ - if (grub_ata_wait_drq (dev, rw, GRUB_ATA_TOUT_DATA)) - return grub_errno; - - /* Transfer data. */ - if (! rw) - grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE); - else - grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE); - - buf += GRUB_DISK_SECTOR_SIZE; - } - - if (rw) - { - /* Check for write error. */ - if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) - return grub_errno; - - if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) - & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) - return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error"); - } - + grub_memset (&parms, 0, sizeof (parms)); + grub_ata_setaddress (ata, &parms, sector, batch, addressing); + parms.taskfile.cmd = (! rw ? cmd : cmd_write); + parms.buffer = buf; + parms.size = batch << ata->log_sector_size; + parms.write = rw; + if (ata->dma) + parms.dma = 1; + + err = ata->dev->readwrite (ata, &parms, 0); + if (err) + return err; + if (parms.size != batch << ata->log_sector_size) + return grub_error (GRUB_ERR_READ_ERROR, "incomplete read"); + buf += batch << ata->log_sector_size; sector += batch; nsectors += batch; } @@ -663,75 +353,119 @@ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector, -static int -grub_ata_iterate (int (*hook) (const char *name)) +static inline void +grub_ata_real_close (struct grub_ata *ata) { - struct grub_ata_device *dev; + if (ata->dev->close) + ata->dev->close (ata); +} - for (dev = grub_ata_devices; dev; dev = dev->next) +static struct grub_ata * +grub_ata_real_open (int id, int bus) +{ + struct grub_ata *ata; + grub_ata_dev_t p; + + ata = grub_malloc (sizeof (*ata)); + if (!ata) + return NULL; + for (p = grub_ata_dev_list; p; p = p->next) { - char devname[10]; grub_err_t err; - - err = check_device (dev); - if (err) + if (p->open (id, bus, ata)) { grub_errno = GRUB_ERR_NONE; continue; } - - if (dev->atapi) - continue; - - grub_snprintf (devname, sizeof (devname), - "ata%d", dev->port * 2 + dev->device); - - if (hook (devname)) - return 1; + ata->dev = p; + /* Use the IDENTIFY DEVICE command to query the device. */ + err = grub_ata_identify (ata); + if (err) + { + grub_free (ata); + return NULL; + } + return ata; } + grub_free (ata); + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATA device"); + return NULL; +} +static int +grub_ata_iterate (int (*hook_in) (const char *name), + grub_disk_pull_t pull) +{ + auto int hook (int id, int bus); + int hook (int id, int bus) + { + struct grub_ata *ata; + int ret; + char devname[40]; + + ata = grub_ata_real_open (id, bus); + + if (!ata) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (ata->atapi) + { + grub_ata_real_close (ata); + return 0; + } + grub_snprintf (devname, sizeof (devname), + "%s%d", grub_scsi_names[id], bus); + ret = hook_in (devname); + grub_ata_real_close (ata); + return ret; + } + + grub_ata_dev_t p; + + for (p = grub_ata_dev_list; p; p = p->next) + if (p->iterate && p->iterate (hook, pull)) + return 1; return 0; } static grub_err_t grub_ata_open (const char *name, grub_disk_t disk) { - struct grub_ata_device *dev; - grub_err_t err; + unsigned id, bus; + struct grub_ata *ata; - for (dev = grub_ata_devices; dev; dev = dev->next) - { - char devname[10]; - grub_snprintf (devname, sizeof (devname), - "ata%d", dev->port * 2 + dev->device); - if (grub_strcmp (name, devname) == 0) - break; - } + for (id = 0; id < GRUB_SCSI_NUM_SUBSYSTEMS; id++) + if (grub_strncmp (grub_scsi_names[id], name, + grub_strlen (grub_scsi_names[id])) == 0 + && grub_isdigit (name[grub_strlen (grub_scsi_names[id])])) + break; + if (id == GRUB_SCSI_NUM_SUBSYSTEMS) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk"); + bus = grub_strtoul (name + grub_strlen (grub_scsi_names[id]), 0, 0); + ata = grub_ata_real_open (id, bus); + if (!ata) + return grub_errno; - if (! dev) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); - - if (dev->atapi) + if (ata->atapi) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk"); - err = check_device (dev); + disk->total_sectors = ata->size; + disk->log_sector_size = ata->log_sector_size; - if (err) - return err; + disk->id = grub_make_scsi_id (id, bus, 0); - disk->total_sectors = dev->size; - - disk->id = (unsigned long) dev; - - disk->data = dev; + disk->data = ata; return 0; } static void -grub_ata_close (grub_disk_t disk __attribute__((unused))) +grub_ata_close (grub_disk_t disk) { - + struct grub_ata *ata = disk->data; + grub_ata_real_close (ata); } static grub_err_t @@ -766,70 +500,35 @@ static struct grub_disk_dev grub_atadisk_dev = /* ATAPI code. */ -static int -grub_atapi_iterate (int (*hook) (int bus, int luns)) -{ - struct grub_ata_device *dev; - - for (dev = grub_ata_devices; dev; dev = dev->next) - { - grub_err_t err; - - err = check_device (dev); - if (err) - { - grub_errno = GRUB_ERR_NONE; - continue; - } - - if (! dev->atapi) - continue; - - if (hook (dev->port * 2 + dev->device, 1)) - return 1; - } - - return 0; - -} - static grub_err_t -grub_atapi_read (struct grub_scsi *scsi, - grub_size_t cmdsize __attribute__((unused)), - char *cmd, grub_size_t size, char *buf) +grub_atapi_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, + grub_size_t size, char *buf) { - struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data; + struct grub_ata *dev = scsi->data; + struct grub_disk_ata_pass_through_parms parms; + grub_err_t err; grub_dprintf("ata", "grub_atapi_read (size=%llu)\n", (unsigned long long) size); + grub_memset (&parms, 0, sizeof (parms)); - if (grub_atapi_packet (dev, cmd, size)) - return grub_errno; + parms.taskfile.disk = 0; + parms.taskfile.features = 0; + parms.taskfile.atapi_ireason = 0; + parms.taskfile.atapi_cnthigh = size >> 8; + parms.taskfile.atapi_cntlow = size & 0xff; + parms.taskfile.cmd = GRUB_ATA_CMD_PACKET; + parms.cmd = cmd; + parms.cmdsize = cmdsize; - grub_size_t nread = 0; - while (nread < size) - { - /* Wait for !BSY, DRQ, I/O, !C/D. */ - if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN, GRUB_ATA_TOUT_DATA)) - return grub_errno; - - /* Get byte count for this DRQ assertion. */ - unsigned cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8 - | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW); - grub_dprintf("ata", "DRQ count=%u\n", cnt); - - /* Count of last transfer may be uneven. */ - if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread))) - return grub_error (GRUB_ERR_READ_ERROR, "invalid ATAPI transfer count"); - - /* Read the data. */ - grub_ata_pio_read (dev, buf + nread, cnt); - - if (cnt & 1) - buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + GRUB_ATA_REG_DATA)); - - nread += cnt; - } + parms.size = size; + parms.buffer = buf; + + err = dev->dev->readwrite (dev, &parms, 0); + if (err) + return err; + if (parms.size != size) + return grub_error (GRUB_ERR_READ_ERROR, "incomplete ATAPI read"); return GRUB_ERR_NONE; } @@ -838,71 +537,107 @@ grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)), grub_size_t cmdsize __attribute__((unused)), char *cmd __attribute__((unused)), grub_size_t size __attribute__((unused)), - char *buf __attribute__((unused))) + const char *buf __attribute__((unused))) { // XXX: scsi.mod does not use write yet. return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented"); } static grub_err_t -grub_atapi_open (int devnum, struct grub_scsi *scsi) +grub_atapi_open (int id, int bus, struct grub_scsi *scsi) { - struct grub_ata_device *dev; - struct grub_ata_device *devfnd = 0; - grub_err_t err; + struct grub_ata *ata; - for (dev = grub_ata_devices; dev; dev = dev->next) - { - if (dev->port * 2 + dev->device == devnum) - { - devfnd = dev; - break; - } - } - - grub_dprintf ("ata", "opening ATAPI dev `ata%d'\n", devnum); - - if (! devfnd) + ata = grub_ata_real_open (id, bus); + if (!ata) + return grub_errno; + + if (! ata->atapi) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); - err = check_device (devfnd); - if (err) - return err; - - if (! devfnd->atapi) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); - - scsi->data = devfnd; + scsi->data = ata; + scsi->luns = 1; return GRUB_ERR_NONE; } +static int +grub_atapi_iterate (int NESTED_FUNC_ATTR (*hook_in) (int id, int bus, int luns), + grub_disk_pull_t pull) +{ + auto int hook (int id, int bus); + int hook (int id, int bus) + { + struct grub_ata *ata; + int ret; + + ata = grub_ata_real_open (id, bus); + + if (!ata) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (!ata->atapi) + { + grub_ata_real_close (ata); + return 0; + } + ret = hook_in (id, bus, 1); + grub_ata_real_close (ata); + return ret; + } + + grub_ata_dev_t p; + + for (p = grub_ata_dev_list; p; p = p->next) + if (p->iterate && p->iterate (hook, pull)) + return 1; + return 0; +} + +static void +grub_atapi_close (grub_scsi_t disk) +{ + struct grub_ata *ata = disk->data; + grub_ata_real_close (ata); +} + + +void +grub_ata_dev_register (grub_ata_dev_t dev) +{ + dev->next = grub_ata_dev_list; + grub_ata_dev_list = dev; +} + +void +grub_ata_dev_unregister (grub_ata_dev_t dev) +{ + grub_ata_dev_t *p, q; + + for (p = &grub_ata_dev_list, q = *p; q; p = &(q->next), q = q->next) + if (q == dev) + { + *p = q->next; + break; + } +} static struct grub_scsi_dev grub_atapi_dev = { - .name = "ata", - .id = GRUB_SCSI_SUBSYSTEM_ATAPI, .iterate = grub_atapi_iterate, .open = grub_atapi_open, + .close = grub_atapi_close, .read = grub_atapi_read, - .write = grub_atapi_write + .write = grub_atapi_write, + .next = 0 }; GRUB_MOD_INIT(ata) { - /* To prevent two drivers operating on the same disks. */ - grub_disk_firmware_is_tainted = 1; - if (grub_disk_firmware_fini) - { - grub_disk_firmware_fini (); - grub_disk_firmware_fini = NULL; - } - - /* ATA initialization. */ - grub_ata_initialize (); - grub_disk_dev_register (&grub_atadisk_dev); /* ATAPI devices are handled by scsi.mod. */ diff --git a/grub-core/disk/ata_pthru.c b/grub-core/disk/ata_pthru.c deleted file mode 100644 index f52725a49..000000000 --- a/grub-core/disk/ata_pthru.c +++ /dev/null @@ -1,107 +0,0 @@ -/* ata_pthru.c - ATA pass through for ata.mod. */ -/* - * 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 -#include -#include - - -/* ATA pass through support, used by hdparm.mod. */ -static grub_err_t -grub_ata_pass_through (grub_disk_t disk, - struct grub_disk_ata_pass_through_parms *parms) -{ - if (disk->dev->id != GRUB_DISK_DEVICE_ATA_ID) - return grub_error (GRUB_ERR_BAD_DEVICE, - "device not accessed via ata.mod"); - - struct grub_ata_device *dev = (struct grub_ata_device *) disk->data; - - if (! (parms->size == 0 || parms->size == GRUB_DISK_SECTOR_SIZE)) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "ATA multi-sector read and DATA OUT not implemented"); - - grub_dprintf ("ata", "ata_pass_through: cmd=0x%x, features=0x%x, sectors=0x%x\n", - parms->taskfile[GRUB_ATA_REG_CMD], - parms->taskfile[GRUB_ATA_REG_FEATURES], - parms->taskfile[GRUB_ATA_REG_SECTORS]); - grub_dprintf ("ata", "lba_high=0x%x, lba_mid=0x%x, lba_low=0x%x, size=%d\n", - parms->taskfile[GRUB_ATA_REG_LBAHIGH], - parms->taskfile[GRUB_ATA_REG_LBAMID], - parms->taskfile[GRUB_ATA_REG_LBALOW], parms->size); - - /* Set registers. */ - grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4 - | (parms->taskfile[GRUB_ATA_REG_DISK] & 0xf)); - if (grub_ata_check_ready (dev)) - return grub_errno; - - int i; - for (i = GRUB_ATA_REG_FEATURES; i <= GRUB_ATA_REG_LBAHIGH; i++) - grub_ata_regset (dev, i, parms->taskfile[i]); - - /* Start command. */ - grub_ata_regset (dev, GRUB_ATA_REG_CMD, parms->taskfile[GRUB_ATA_REG_CMD]); - - /* Wait for !BSY. */ - if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) - return grub_errno; - - /* Check status. */ - grub_int8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); - grub_dprintf ("ata", "status=0x%x\n", sts); - - /* Transfer data. */ - if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_DRQ) - { - if (parms->size != GRUB_DISK_SECTOR_SIZE) - return grub_error (GRUB_ERR_READ_ERROR, "DRQ unexpected"); - grub_ata_pio_read (dev, parms->buffer, GRUB_DISK_SECTOR_SIZE); - } - - /* Return registers. */ - for (i = GRUB_ATA_REG_ERROR; i <= GRUB_ATA_REG_STATUS; i++) - parms->taskfile[i] = grub_ata_regget (dev, i); - - grub_dprintf ("ata", "status=0x%x, error=0x%x, sectors=0x%x\n", - parms->taskfile[GRUB_ATA_REG_STATUS], - parms->taskfile[GRUB_ATA_REG_ERROR], - parms->taskfile[GRUB_ATA_REG_SECTORS]); - - if (parms->taskfile[GRUB_ATA_REG_STATUS] - & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) - return grub_error (GRUB_ERR_READ_ERROR, "ATA passthrough failed"); - - return GRUB_ERR_NONE; -} - - - -GRUB_MOD_INIT(ata_pthru) -{ - /* Register ATA pass through function. */ - grub_disk_ata_pass_through = grub_ata_pass_through; -} - -GRUB_MOD_FINI(ata_pthru) -{ - if (grub_disk_ata_pass_through == grub_ata_pass_through) - grub_disk_ata_pass_through = NULL; -} diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c new file mode 100644 index 000000000..7d63f3e46 --- /dev/null +++ b/grub-core/disk/cryptodisk.c @@ -0,0 +1,981 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2007,2010,2011 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 + +#ifdef GRUB_UTIL +#include +#include +#include +#include +#include +#include +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); + +grub_cryptodisk_dev_t grub_cryptodisk_list; + +static const struct grub_arg_option options[] = + { + {"uuid", 'u', 0, N_("Mount by UUID."), 0, 0}, + {"all", 'a', 0, N_("Mount all."), 0, 0}, + {"boot", 'b', 0, N_("Mount all volumes marked as boot."), 0, 0}, + {0, 0, 0, 0, 0, 0} + }; + +/* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */ +#define GF_POLYNOM 0x87 +static inline int GF_PER_SECTOR (const struct grub_cryptodisk *dev) +{ + return 1U << (dev->log_sector_size - GRUB_CRYPTODISK_GF_LOG_BYTES); +} + +static grub_cryptodisk_t cryptodisk_list = NULL; +static grub_uint8_t n = 0; + +static void +gf_mul_x (grub_uint8_t *g) +{ + int over = 0, over2 = 0; + unsigned j; + + for (j = 0; j < GRUB_CRYPTODISK_GF_BYTES; j++) + { + over2 = !!(g[j] & 0x80); + g[j] <<= 1; + g[j] |= over; + over = over2; + } + if (over) + g[0] ^= GF_POLYNOM; +} + + +static void +gf_mul_x_be (grub_uint8_t *g) +{ + int over = 0, over2 = 0; + int j; + + for (j = (int) GRUB_CRYPTODISK_GF_BYTES - 1; j >= 0; j--) + { + over2 = !!(g[j] & 0x80); + g[j] <<= 1; + g[j] |= over; + over = over2; + } + if (over) + g[GRUB_CRYPTODISK_GF_BYTES - 1] ^= GF_POLYNOM; +} + +static void +gf_mul_be (grub_uint8_t *o, const grub_uint8_t *a, const grub_uint8_t *b) +{ + unsigned i; + grub_uint8_t t[GRUB_CRYPTODISK_GF_BYTES]; + grub_memset (o, 0, GRUB_CRYPTODISK_GF_BYTES); + grub_memcpy (t, b, GRUB_CRYPTODISK_GF_BYTES); + for (i = 0; i < GRUB_CRYPTODISK_GF_SIZE; i++) + { + if (((a[GRUB_CRYPTODISK_GF_BYTES - i / 8 - 1] >> (i % 8))) & 1) + grub_crypto_xor (o, o, t, GRUB_CRYPTODISK_GF_BYTES); + gf_mul_x_be (t); + } +} + +static gcry_err_code_t +grub_crypto_pcbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + grub_crypto_xor (iv, ivt, outptr, cipher->cipher->blocksize); + } + return GPG_ERR_NO_ERROR; +} + +static gcry_err_code_t +grub_crypto_pcbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; + if (size % cipher->cipher->blocksize != 0) + return GPG_ERR_INV_ARG; + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + cipher->cipher->encrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (iv, ivt, outptr, cipher->cipher->blocksize); + } + return GPG_ERR_NO_ERROR; +} + +struct lrw_sector +{ + grub_uint8_t low[GRUB_CRYPTODISK_GF_BYTES]; + grub_uint8_t high[GRUB_CRYPTODISK_GF_BYTES]; + grub_uint8_t low_byte, low_byte_c; +}; + +static void +generate_lrw_sector (struct lrw_sector *sec, + const struct grub_cryptodisk *dev, + const grub_uint8_t *iv) +{ + grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES]; + grub_uint16_t c; + int j; + grub_memcpy (idx, iv, GRUB_CRYPTODISK_GF_BYTES); + sec->low_byte = (idx[GRUB_CRYPTODISK_GF_BYTES - 1] + & (GF_PER_SECTOR (dev) - 1)); + sec->low_byte_c = (((GF_PER_SECTOR (dev) - 1) & ~sec->low_byte) + 1); + idx[GRUB_CRYPTODISK_GF_BYTES - 1] &= ~(GF_PER_SECTOR (dev) - 1); + gf_mul_be (sec->low, dev->lrw_key, idx); + if (!sec->low_byte) + return; + + c = idx[GRUB_CRYPTODISK_GF_BYTES - 1] + GF_PER_SECTOR (dev); + if (c & 0x100) + { + for (j = GRUB_CRYPTODISK_GF_BYTES - 2; j >= 0; j--) + { + idx[j]++; + if (idx[j] != 0) + break; + } + } + idx[GRUB_CRYPTODISK_GF_BYTES - 1] = c; + gf_mul_be (sec->high, dev->lrw_key, idx); +} + +static void __attribute__ ((unused)) +lrw_xor (const struct lrw_sector *sec, + const struct grub_cryptodisk *dev, + grub_uint8_t *b) +{ + unsigned i; + + for (i = 0; i < sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES; + i += GRUB_CRYPTODISK_GF_BYTES) + grub_crypto_xor (b + i, b + i, sec->low, GRUB_CRYPTODISK_GF_BYTES); + grub_crypto_xor (b, b, dev->lrw_precalc + GRUB_CRYPTODISK_GF_BYTES * sec->low_byte, + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES); + if (!sec->low_byte) + return; + + for (i = sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES; + i < (1U << dev->log_sector_size); i += GRUB_CRYPTODISK_GF_BYTES) + grub_crypto_xor (b + i, b + i, sec->high, GRUB_CRYPTODISK_GF_BYTES); + grub_crypto_xor (b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES, + b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES, + dev->lrw_precalc, sec->low_byte * GRUB_CRYPTODISK_GF_BYTES); +} + +static gcry_err_code_t +grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, + grub_uint8_t * data, grub_size_t len, + grub_disk_addr_t sector, int encrypt) +{ + grub_size_t i; + gcry_err_code_t err; + + /* The only mode without IV. */ + if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey) + return (encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len) + : grub_crypto_ecb_decrypt (dev->cipher, data, data, len)); + + for (i = 0; i < len; i += (1U << dev->log_sector_size)) + { + grub_size_t sz = ((dev->cipher->cipher->blocksize + + sizeof (grub_uint32_t) - 1) + / sizeof (grub_uint32_t)); + grub_uint32_t iv[sz]; + + if (dev->rekey) + { + grub_uint64_t zone = sector >> dev->rekey_shift; + if (zone != dev->last_rekey) + { + err = dev->rekey (dev, zone); + if (err) + return err; + dev->last_rekey = zone; + } + } + + grub_memset (iv, 0, sz * sizeof (iv[0])); + switch (dev->mode_iv) + { + case GRUB_CRYPTODISK_MODE_IV_NULL: + break; + case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH: + { + grub_uint64_t tmp; + grub_uint64_t ctx[(dev->iv_hash->contextsize + 7) / 8]; + + grub_memset (ctx, 0, sizeof (ctx)); + + tmp = grub_cpu_to_le64 (sector << dev->log_sector_size); + dev->iv_hash->init (ctx); + dev->iv_hash->write (ctx, dev->iv_prefix, dev->iv_prefix_len); + dev->iv_hash->write (ctx, &tmp, sizeof (tmp)); + dev->iv_hash->final (ctx); + + grub_memcpy (iv, dev->iv_hash->read (ctx), sizeof (iv)); + } + break; + case GRUB_CRYPTODISK_MODE_IV_PLAIN64: + iv[1] = grub_cpu_to_le32 (sector >> 32); + case GRUB_CRYPTODISK_MODE_IV_PLAIN: + iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF); + break; + case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64: + iv[1] = grub_cpu_to_le32 (sector >> (32 - dev->log_sector_size)); + iv[0] = grub_cpu_to_le32 ((sector << dev->log_sector_size) + & 0xFFFFFFFF); + break; + case GRUB_CRYPTODISK_MODE_IV_BENBI: + { + grub_uint64_t num = (sector << dev->benbi_log) + 1; + iv[sz - 2] = grub_cpu_to_be32 (num >> 32); + iv[sz - 1] = grub_cpu_to_be32 (num & 0xFFFFFFFF); + } + break; + case GRUB_CRYPTODISK_MODE_IV_ESSIV: + iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF); + err = grub_crypto_ecb_encrypt (dev->essiv_cipher, iv, iv, + dev->cipher->cipher->blocksize); + if (err) + return err; + } + + switch (dev->mode) + { + case GRUB_CRYPTODISK_MODE_CBC: + if (encrypt) + err = grub_crypto_cbc_encrypt (dev->cipher, data + i, data + i, + (1U << dev->log_sector_size), iv); + else + err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i, + (1U << dev->log_sector_size), iv); + if (err) + return err; + break; + + case GRUB_CRYPTODISK_MODE_PCBC: + if (encrypt) + err = grub_crypto_pcbc_encrypt (dev->cipher, data + i, data + i, + (1U << dev->log_sector_size), iv); + else + err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i, + (1U << dev->log_sector_size), iv); + if (err) + return err; + break; + case GRUB_CRYPTODISK_MODE_XTS: + { + unsigned j; + err = grub_crypto_ecb_encrypt (dev->secondary_cipher, iv, iv, + dev->cipher->cipher->blocksize); + if (err) + return err; + + for (j = 0; j < (1U << dev->log_sector_size); + j += dev->cipher->cipher->blocksize) + { + grub_crypto_xor (data + i + j, data + i + j, iv, + dev->cipher->cipher->blocksize); + if (encrypt) + err = grub_crypto_ecb_encrypt (dev->cipher, data + i + j, + data + i + j, + dev->cipher->cipher->blocksize); + else + err = grub_crypto_ecb_decrypt (dev->cipher, data + i + j, + data + i + j, + dev->cipher->cipher->blocksize); + if (err) + return err; + grub_crypto_xor (data + i + j, data + i + j, iv, + dev->cipher->cipher->blocksize); + gf_mul_x ((grub_uint8_t *) iv); + } + } + break; + case GRUB_CRYPTODISK_MODE_LRW: + { + struct lrw_sector sec; + + generate_lrw_sector (&sec, dev, (grub_uint8_t *) iv); + lrw_xor (&sec, dev, data + i); + + if (encrypt) + err = grub_crypto_ecb_encrypt (dev->cipher, data + i, + data + i, + (1U << dev->log_sector_size)); + else + err = grub_crypto_ecb_decrypt (dev->cipher, data + i, + data + i, + (1U << dev->log_sector_size)); + if (err) + return err; + lrw_xor (&sec, dev, data + i); + } + break; + case GRUB_CRYPTODISK_MODE_ECB: + if (encrypt) + grub_crypto_ecb_encrypt (dev->cipher, data + i, data + i, + (1U << dev->log_sector_size)); + else + grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i, + (1U << dev->log_sector_size)); + break; + default: + return GPG_ERR_NOT_IMPLEMENTED; + } + sector++; + } + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_cryptodisk_decrypt (struct grub_cryptodisk *dev, + grub_uint8_t * data, grub_size_t len, + grub_disk_addr_t sector) +{ + return grub_cryptodisk_endecrypt (dev, data, len, sector, 0); +} + +gcry_err_code_t +grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t keysize) +{ + gcry_err_code_t err; + int real_keysize; + + real_keysize = keysize; + if (dev->mode == GRUB_CRYPTODISK_MODE_XTS) + real_keysize /= 2; + if (dev->mode == GRUB_CRYPTODISK_MODE_LRW) + real_keysize -= dev->cipher->cipher->blocksize; + + /* Set the PBKDF2 output as the cipher key. */ + err = grub_crypto_cipher_set_key (dev->cipher, key, real_keysize); + if (err) + return err; + + /* Configure ESSIV if necessary. */ + if (dev->mode_iv == GRUB_CRYPTODISK_MODE_IV_ESSIV) + { + grub_size_t essiv_keysize = dev->essiv_hash->mdlen; + grub_uint8_t hashed_key[essiv_keysize]; + + grub_crypto_hash (dev->essiv_hash, hashed_key, key, keysize); + err = grub_crypto_cipher_set_key (dev->essiv_cipher, + hashed_key, essiv_keysize); + if (err) + return err; + } + if (dev->mode == GRUB_CRYPTODISK_MODE_XTS) + { + err = grub_crypto_cipher_set_key (dev->secondary_cipher, + key + real_keysize, + keysize / 2); + if (err) + return err; + } + + if (dev->mode == GRUB_CRYPTODISK_MODE_LRW) + { + unsigned i; + grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES]; + + grub_free (dev->lrw_precalc); + grub_memcpy (dev->lrw_key, key + real_keysize, + dev->cipher->cipher->blocksize); + dev->lrw_precalc = grub_malloc ((1U << dev->log_sector_size)); + if (!dev->lrw_precalc) + return GPG_ERR_OUT_OF_MEMORY; + grub_memset (idx, 0, GRUB_CRYPTODISK_GF_BYTES); + for (i = 0; i < (1U << dev->log_sector_size); + i += GRUB_CRYPTODISK_GF_BYTES) + { + idx[GRUB_CRYPTODISK_GF_BYTES - 1] = i / GRUB_CRYPTODISK_GF_BYTES; + gf_mul_be (dev->lrw_precalc + i, idx, dev->lrw_key); + } + } + return GPG_ERR_NO_ERROR; +} + +static int +grub_cryptodisk_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) +{ + grub_cryptodisk_t i; + + if (pull != GRUB_DISK_PULL_NONE) + return 0; + + for (i = cryptodisk_list; i != NULL; i = i->next) + { + char buf[30]; + grub_snprintf (buf, sizeof (buf), "crypto%lu", i->id); + if (hook (buf)) + return 1; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cryptodisk_open (const char *name, grub_disk_t disk) +{ + grub_cryptodisk_t dev; + + if (grub_memcmp (name, "crypto", sizeof ("crypto") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); + + if (grub_memcmp (name, "cryptouuid/", sizeof ("cryptouuid/") - 1) == 0) + { + for (dev = cryptodisk_list; dev != NULL; dev = dev->next) + if (grub_strcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid) == 0) + break; + } + else + { + unsigned long id = grub_strtoul (name + sizeof ("crypto") - 1, 0, 0); + if (grub_errno) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); + /* Search for requested device in the list of CRYPTODISK devices. */ + for (dev = cryptodisk_list; dev != NULL; dev = dev->next) + if (dev->id == id) + break; + } + if (!dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); + + disk->log_sector_size = dev->log_sector_size; + +#ifdef GRUB_UTIL + if (dev->cheat) + { + if (dev->cheat_fd == -1) + dev->cheat_fd = open (dev->cheat, O_RDONLY); + if (dev->cheat_fd == -1) + return grub_error (GRUB_ERR_IO, "couldn't open %s: %s", + dev->cheat, strerror (errno)); + } +#endif + + if (!dev->source_disk) + { + grub_dprintf ("cryptodisk", "Opening device %s\n", name); + /* Try to open the source disk and populate the requested disk. */ + dev->source_disk = grub_disk_open (dev->source); + if (!dev->source_disk) + return grub_errno; + } + + disk->data = dev; + disk->total_sectors = dev->total_length; + disk->id = dev->id; + dev->ref++; + return GRUB_ERR_NONE; +} + +static void +grub_cryptodisk_close (grub_disk_t disk) +{ + grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data; + grub_dprintf ("cryptodisk", "Closing disk\n"); + + dev->ref--; + + if (dev->ref != 0) + return; +#ifdef GRUB_UTIL + if (dev->cheat) + { + close (dev->cheat_fd); + dev->cheat_fd = -1; + } +#endif + grub_disk_close (dev->source_disk); + dev->source_disk = NULL; +} + +static grub_err_t +grub_cryptodisk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data; + grub_err_t err; + gcry_err_code_t gcry_err; + +#ifdef GRUB_UTIL + if (dev->cheat) + { + err = grub_util_fd_seek (dev->cheat_fd, dev->cheat, + sector << disk->log_sector_size); + if (err) + return err; + if (grub_util_fd_read (dev->cheat_fd, buf, size << disk->log_sector_size) + != (ssize_t) (size << disk->log_sector_size)) + return grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", + dev->cheat); + return GRUB_ERR_NONE; + } +#endif + + grub_dprintf ("cryptodisk", + "Reading %" PRIuGRUB_SIZE " sectors from sector 0x%" + PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT64_T "\n", + size, sector, dev->offset); + + err = grub_disk_read (dev->source_disk, + (sector << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) + dev->offset, 0, + size << disk->log_sector_size, buf); + if (err) + { + grub_dprintf ("cryptodisk", "grub_disk_read failed with error %d\n", err); + return err; + } + gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) buf, + size << disk->log_sector_size, + sector, 0); + return grub_crypto_gcry_error (gcry_err); +} + +static grub_err_t +grub_cryptodisk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data; + gcry_err_code_t gcry_err; + char *tmp; + grub_err_t err; + +#ifdef GRUB_UTIL + if (dev->cheat) + { + err = grub_util_fd_seek (dev->cheat_fd, dev->cheat, + sector << disk->log_sector_size); + if (err) + return err; + if (grub_util_fd_write (dev->cheat_fd, buf, size << disk->log_sector_size) + != (ssize_t) (size << disk->log_sector_size)) + return grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", + dev->cheat); + return GRUB_ERR_NONE; + } +#endif + + tmp = grub_malloc (size << disk->log_sector_size); + if (!tmp) + return grub_errno; + grub_memcpy (tmp, buf, size << disk->log_sector_size); + + grub_dprintf ("cryptodisk", + "Writing %" PRIuGRUB_SIZE " sectors to sector 0x%" + PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT64_T "\n", + size, sector, dev->offset); + + gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) tmp, + size << disk->log_sector_size, + sector, 1); + if (gcry_err) + { + grub_free (tmp); + return grub_crypto_gcry_error (gcry_err); + } + + err = grub_disk_write (dev->source_disk, + (sector << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) + dev->offset, + 0, size << disk->log_sector_size, tmp); + grub_free (tmp); + return err; +} + +#ifdef GRUB_UTIL +static grub_disk_memberlist_t +grub_cryptodisk_memberlist (grub_disk_t disk) +{ + grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data; + grub_disk_memberlist_t list = NULL; + + list = grub_malloc (sizeof (*list)); + if (list) + { + list->disk = dev->source_disk; + list->next = NULL; + } + + return list; +} +#endif + +static void +cryptodisk_cleanup (void) +{ +#if 0 + grub_cryptodisk_t dev = cryptodisk_list; + grub_cryptodisk_t tmp; + + while (dev != NULL) + { + grub_free (dev->source); + grub_free (dev->cipher); + grub_free (dev->secondary_cipher); + grub_free (dev->essiv_cipher); + tmp = dev->next; + grub_free (dev); + dev = tmp; + } +#endif +} + +grub_err_t +grub_cryptodisk_insert (grub_cryptodisk_t newdev, const char *name, + grub_disk_t source) +{ + newdev->source = grub_strdup (name); + if (!newdev->source) + { + grub_free (newdev); + return grub_errno; + } + + newdev->id = n++; + newdev->source_id = source->id; + newdev->source_dev_id = source->dev->id; + newdev->next = cryptodisk_list; + cryptodisk_list = newdev; + + return GRUB_ERR_NONE; +} + +grub_cryptodisk_t +grub_cryptodisk_get_by_uuid (const char *uuid) +{ + grub_cryptodisk_t dev; + for (dev = cryptodisk_list; dev != NULL; dev = dev->next) + if (grub_strcasecmp (dev->uuid, uuid) == 0) + return dev; + return NULL; +} + +grub_cryptodisk_t +grub_cryptodisk_get_by_source_disk (grub_disk_t disk) +{ + grub_cryptodisk_t dev; + for (dev = cryptodisk_list; dev != NULL; dev = dev->next) + if (dev->source_id == disk->id && dev->source_dev_id == disk->dev->id) + return dev; + return NULL; +} + +#ifdef GRUB_UTIL +grub_err_t +grub_cryptodisk_cheat_insert (grub_cryptodisk_t newdev, const char *name, + grub_disk_t source, const char *cheat) +{ + newdev->cheat = grub_strdup (cheat); + newdev->source = grub_strdup (name); + if (!newdev->source || !newdev->cheat) + { + grub_free (newdev->source); + grub_free (newdev->cheat); + return grub_errno; + } + + newdev->cheat_fd = -1; + newdev->source_id = source->id; + newdev->source_dev_id = source->dev->id; + newdev->id = n++; + newdev->next = cryptodisk_list; + cryptodisk_list = newdev; + + return GRUB_ERR_NONE; +} + +void +grub_util_cryptodisk_print_abstraction (grub_disk_t disk) +{ + grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data; + + grub_printf ("cryptodisk %s ", dev->modname); + + if (dev->cipher) + grub_printf ("%s ", dev->cipher->cipher->modname); + if (dev->secondary_cipher) + grub_printf ("%s ", dev->secondary_cipher->cipher->modname); + if (dev->essiv_cipher) + grub_printf ("%s ", dev->essiv_cipher->cipher->modname); + if (dev->hash) + grub_printf ("%s ", dev->hash->modname); + if (dev->essiv_hash) + grub_printf ("%s ", dev->essiv_hash->modname); + if (dev->iv_hash) + grub_printf ("%s ", dev->iv_hash->modname); +} + +void +grub_util_cryptodisk_print_uuid (grub_disk_t disk) +{ + grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data; + grub_printf ("%s ", dev->uuid); +} + +#endif + +static int check_boot, have_it; +static char *search_uuid; + +static void +cryptodisk_close (grub_cryptodisk_t dev) +{ + grub_crypto_cipher_close (dev->cipher); + grub_crypto_cipher_close (dev->secondary_cipher); + grub_crypto_cipher_close (dev->essiv_cipher); + grub_free (dev); +} + +static grub_err_t +grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) +{ + grub_err_t err; + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; + + dev = grub_cryptodisk_get_by_source_disk (source); + + if (dev) + return GRUB_ERR_NONE; + + FOR_CRYPTODISK_DEVS (cr) + { + dev = cr->scan (source, search_uuid, check_boot); + if (grub_errno) + return grub_errno; + if (!dev) + continue; + + err = cr->recover_key (source, dev); + if (err) + { + cryptodisk_close (dev); + return err; + } + + grub_cryptodisk_insert (dev, name, source); + + have_it = 1; + + return GRUB_ERR_NONE; + } + return GRUB_ERR_NONE; +} + +#ifdef GRUB_UTIL +#include +grub_err_t +grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) +{ + grub_err_t err; + grub_cryptodisk_t dev; + grub_cryptodisk_dev_t cr; + grub_disk_t source; + + /* Try to open disk. */ + source = grub_disk_open (sourcedev); + if (!source) + return grub_errno; + + dev = grub_cryptodisk_get_by_source_disk (source); + + if (dev) + { + grub_disk_close (source); + return GRUB_ERR_NONE; + } + + FOR_CRYPTODISK_DEVS (cr) + { + dev = cr->scan (source, search_uuid, check_boot); + if (grub_errno) + return grub_errno; + if (!dev) + continue; + + grub_util_info ("cheatmounted %s (%s) at %s", sourcedev, dev->modname, + cheat); + err = grub_cryptodisk_cheat_insert (dev, sourcedev, source, cheat); + grub_disk_close (source); + if (err) + grub_free (dev); + + return GRUB_ERR_NONE; + } + + grub_disk_close (source); + + return GRUB_ERR_NONE; +} +#endif + +static int +grub_cryptodisk_scan_device (const char *name) +{ + grub_err_t err; + grub_disk_t source; + + /* Try to open disk. */ + source = grub_disk_open (name); + if (!source) + return grub_errno; + + err = grub_cryptodisk_scan_device_real (name, source); + + grub_disk_close (source); + + if (err) + grub_print_error (); + return have_it && search_uuid ? 1 : 0; +} + +static grub_err_t +grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + + if (argc < 1 && !state[1].set && !state[2].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + + have_it = 0; + if (state[0].set) + { + grub_cryptodisk_t dev; + + dev = grub_cryptodisk_get_by_uuid (args[0]); + if (dev) + { + grub_dprintf ("cryptodisk", + "already mounted as crypto%lu\n", dev->id); + return GRUB_ERR_NONE; + } + + check_boot = state[2].set; + search_uuid = args[0]; + grub_device_iterate (&grub_cryptodisk_scan_device); + search_uuid = NULL; + + if (!have_it) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); + return GRUB_ERR_NONE; + } + else if (state[1].set || (argc == 0 && state[2].set)) + { + search_uuid = NULL; + check_boot = state[2].set; + grub_device_iterate (&grub_cryptodisk_scan_device); + search_uuid = NULL; + return GRUB_ERR_NONE; + } + else + { + grub_err_t err; + grub_disk_t disk; + grub_cryptodisk_t dev; + + search_uuid = NULL; + check_boot = state[2].set; + disk = grub_disk_open (args[0]); + if (!disk) + return grub_errno; + + dev = grub_cryptodisk_get_by_source_disk (disk); + if (dev) + { + grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); + grub_disk_close (disk); + return GRUB_ERR_NONE; + } + + err = grub_cryptodisk_scan_device_real (args[0], disk); + + grub_disk_close (disk); + + return err; + } +} + +static struct grub_disk_dev grub_cryptodisk_dev = { + .name = "cryptodisk", + .id = GRUB_DISK_DEVICE_CRYPTODISK_ID, + .iterate = grub_cryptodisk_iterate, + .open = grub_cryptodisk_open, + .close = grub_cryptodisk_close, + .read = grub_cryptodisk_read, + .write = grub_cryptodisk_write, +#ifdef GRUB_UTIL + .memberlist = grub_cryptodisk_memberlist, +#endif + .next = 0 +}; + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT (cryptodisk) +{ + grub_disk_dev_register (&grub_cryptodisk_dev); + cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, + N_("SOURCE|-u UUID|-a|-b"), + N_("Mount a crypto device."), options); +} + +GRUB_MOD_FINI (cryptodisk) +{ + grub_disk_dev_unregister (&grub_cryptodisk_dev); + cryptodisk_cleanup (); +} diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c new file mode 100644 index 000000000..da9377649 --- /dev/null +++ b/grub-core/disk/diskfilter.c @@ -0,0 +1,1081 @@ +/* diskfilter.c - module to read RAID arrays. */ +/* + * 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 +#ifdef GRUB_UTIL +#include +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Linked list of DISKFILTER arrays. */ +static struct grub_diskfilter_vg *array_list; +grub_raid5_recover_func_t grub_raid5_recover_func; +grub_raid6_recover_func_t grub_raid6_recover_func; +grub_diskfilter_t grub_diskfilter_list; +static int inscnt = 0; +static int lv_num = 0; + +static struct grub_diskfilter_lv * +find_lv (const char *name); +static int is_lv_readable (struct grub_diskfilter_lv *lv); + + + +static grub_err_t +is_node_readable (const struct grub_diskfilter_node *node) +{ + /* Check whether we actually know the physical volume we want to + read from. */ + if (node->pv) + return !!(node->pv->disk); + if (node->lv) + return is_lv_readable (node->lv); + return 0; +} + +static int +is_lv_readable (struct grub_diskfilter_lv *lv) +{ + unsigned i, j; + if (!lv) + return 0; + for (i = 0; i < lv->segment_count; i++) + { + int need = lv->segments[i].node_count, have = 0; + switch (lv->segments[i].type) + { + case GRUB_DISKFILTER_RAID6: + need--; + case GRUB_DISKFILTER_RAID4: + case GRUB_DISKFILTER_RAID5: + need--; + case GRUB_DISKFILTER_STRIPED: + break; + + case GRUB_DISKFILTER_MIRROR: + need = 1; + break; + + case GRUB_DISKFILTER_RAID10: + { + unsigned int n; + n = lv->segments[i].layout & 0xFF; + if (n == 1) + n = (lv->segments[i].layout >> 8) & 0xFF; + need = lv->segments[i].node_count - n + 1; + } + break; + } + for (j = 0; j < lv->segments[i].node_count; j++) + { + if (is_node_readable (lv->segments[i].nodes + j)) + have++; + if (have >= need) + break; + } + if (have < need) + return 0; + } + + return 1; +} + +static grub_err_t +insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + struct grub_diskfilter_vg *array, + grub_disk_addr_t start_sector, const char *scanner_name, + grub_diskfilter_t diskfilter __attribute__ ((unused))); + +static int +scan_disk (const char *name) +{ + auto int hook (grub_disk_t disk, grub_partition_t p); + int hook (grub_disk_t disk, grub_partition_t p) + { + struct grub_diskfilter_vg *arr; + grub_disk_addr_t start_sector; + struct grub_diskfilter_pv_id id; + grub_diskfilter_t diskfilter; + + grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n", + name); +#ifdef GRUB_UTIL + grub_util_info ("Scanning for DISKFILTER devices on disk %s", name); +#endif + + disk->partition = p; + + for (arr = array_list; arr != NULL; arr = arr->next) + { + struct grub_diskfilter_pv *m; + for (m = arr->pvs; m; m = m->next) + if (m->disk && m->disk->id == disk->id + && m->disk->dev->id == disk->dev->id + && m->part_start == grub_partition_get_start (disk->partition) + && m->part_size == grub_disk_get_size (disk)) + return 0; + } + + for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = diskfilter->next) + { + id.uuid = 0; + id.uuidlen = 0; + arr = diskfilter->detect (disk, &id, &start_sector); + if (arr && + (! insert_array (disk, &id, arr, start_sector, diskfilter->name, + diskfilter))) + { + if (id.uuidlen) + grub_free (id.uuid); + return 0; + } + if (arr && id.uuidlen) + grub_free (id.uuid); + + /* This error usually means it's not diskfilter, no need to display + it. */ + if (grub_errno != GRUB_ERR_OUT_OF_RANGE) + grub_print_error (); + + grub_errno = GRUB_ERR_NONE; + } + + return 0; + } + grub_disk_t disk; + static int scan_depth = 0; + + if (scan_depth > 100) + return 0; + + disk = grub_disk_open (name); + if (!disk) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + scan_depth++; + if (hook (disk, 0)) + return 1; + if (grub_partition_iterate (disk, hook)) + return 1; + scan_depth--; + grub_disk_close (disk); + return 0; +} + +static void +scan_devices (const char *arname) +{ + grub_disk_dev_t p; + grub_disk_pull_t pull; + + for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++) + for (p = grub_disk_dev_list; p; p = p->next) + if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID + && p->iterate) + { + if ((p->iterate) (scan_disk, pull)) + return; + if (arname && is_lv_readable (find_lv (arname))) + return; + } +} + +static int +grub_diskfilter_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) +{ + struct grub_diskfilter_vg *array; + int islcnt = 0; + + if (pull == GRUB_DISK_PULL_RESCAN) + { + islcnt = inscnt; + scan_devices (NULL); + } + + if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN) + return 0; + + for (array = array_list; array; array = array->next) + { + struct grub_diskfilter_lv *lv; + if (array->lvs) + for (lv = array->lvs; lv; lv = lv->next) + if (lv->visible && lv->fullname && lv->became_readable_at >= islcnt) + { + if (hook (lv->fullname)) + return 1; + } + } + + return 0; +} + +#ifdef GRUB_UTIL +static grub_disk_memberlist_t +grub_diskfilter_memberlist (grub_disk_t disk) +{ + struct grub_diskfilter_lv *lv = disk->data; + grub_disk_memberlist_t list = NULL, tmp; + struct grub_diskfilter_pv *pv; + + if (lv->vg->pvs) + for (pv = lv->vg->pvs; pv; pv = pv->next) + { + if (!pv->disk) + grub_util_error (_("Couldn't find PV %s. Check your device.map"), + pv->name); + tmp = grub_malloc (sizeof (*tmp)); + tmp->disk = pv->disk; + tmp->next = list; + list = tmp; + } + + return list; +} + +static const char * +grub_diskfilter_getname (struct grub_disk *disk) +{ + struct grub_diskfilter_lv *array = disk->data; + + return array->vg->driver->name; +} +#endif + +static inline int +ascii2hex (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return 0; +} + +static struct grub_diskfilter_lv * +find_lv (const char *name) +{ + struct grub_diskfilter_vg *vg; + struct grub_diskfilter_lv *lv = NULL; + + if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0) + { + const char *uuidstr = name + sizeof ("mduuid/") - 1; + grub_size_t uuid_len = grub_strlen (uuidstr) / 2; + grub_uint8_t uuidbin[uuid_len]; + unsigned i; + for (i = 0; i < uuid_len; i++) + uuidbin[i] = ascii2hex (uuidstr[2 * i + 1]) + | (ascii2hex (uuidstr[2 * i]) << 4); + + for (vg = array_list; vg; vg = vg->next) + { + if (uuid_len == vg->uuid_len + && grub_memcmp (uuidbin, vg->uuid, uuid_len) == 0) + if (is_lv_readable (vg->lvs)) + return vg->lvs; + } + } + + for (vg = array_list; vg; vg = vg->next) + { + if (vg->lvs) + for (lv = vg->lvs; lv; lv = lv->next) + if (lv->fullname && grub_strcmp (lv->fullname, name) == 0 + && is_lv_readable (lv)) + return lv; + } + return NULL; +} + +static grub_err_t +grub_diskfilter_open (const char *name, grub_disk_t disk) +{ + struct grub_diskfilter_lv *lv; + + if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0 + && grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) != 0 + && grub_memcmp (name, "ldm/", sizeof ("ldm/") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown DISKFILTER device %s", + name); + + lv = find_lv (name); + + if (! lv) + { + scan_devices (name); + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + lv = find_lv (name); + } + + if (!lv) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown DISKFILTER device %s", + name); + + disk->id = lv->number; + disk->data = lv; + + grub_dprintf ("diskfilter", "%s: total_devs=%d, total_size=%lld\n", name, + lv->segments ? lv->segments->node_count : 0, + (unsigned long long) lv->size); + disk->total_sectors = lv->size; + grub_dprintf ("diskfilter", "%s: level=%d, total_sectors=%lld\n", name, + lv->segments ? lv->segments->type : 0, + (unsigned long long) disk->total_sectors); + + return 0; +} + +static void +grub_diskfilter_close (grub_disk_t disk __attribute ((unused))) +{ + return; +} + +static grub_err_t +read_lv (struct grub_diskfilter_lv *lv, grub_disk_addr_t sector, + grub_size_t size, char *buf); + +grub_err_t +grub_diskfilter_read_node (const struct grub_diskfilter_node *node, + grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + /* Check whether we actually know the physical volume we want to + read from. */ + if (node->pv) + { + if (node->pv->disk) + return grub_disk_read (node->pv->disk, sector + node->start + + node->pv->start_sector, + 0, size << GRUB_DISK_SECTOR_BITS, buf); + else + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "physical volume %s not found", node->pv->name); + + } + if (node->lv) + return read_lv (node->lv, sector + node->start, size, buf); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name); +} + +static grub_err_t +read_segment (struct grub_diskfilter_segment *seg, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_err_t err; + switch (seg->type) + { + case GRUB_DISKFILTER_STRIPED: + if (seg->node_count == 1) + return grub_diskfilter_read_node (&seg->nodes[0], + sector, size, buf); + case GRUB_DISKFILTER_MIRROR: + case GRUB_DISKFILTER_RAID10: + { + grub_disk_addr_t read_sector, far_ofs; + grub_uint64_t disknr, b, near, far, ofs; + unsigned int i, j; + + read_sector = grub_divmod64 (sector, seg->stripe_size, &b); + far = ofs = near = 1; + far_ofs = 0; + + if (seg->type == 1) + near = seg->node_count; + else if (seg->type == 10) + { + near = seg->layout & 0xFF; + far = (seg->layout >> 8) & 0xFF; + if (seg->layout >> 16) + { + ofs = far; + far_ofs = 1; + } + else + far_ofs = grub_divmod64 (seg->raid_member_size, + far * seg->stripe_size, 0); + + far_ofs *= seg->stripe_size; + } + + read_sector = grub_divmod64 (read_sector * near, + seg->node_count, + &disknr); + + ofs *= seg->stripe_size; + read_sector *= ofs; + + while (1) + { + grub_size_t read_size; + + read_size = seg->stripe_size - b; + if (read_size > size) + read_size = size; + + for (i = 0; i < near; i++) + { + unsigned int k; + + k = disknr; + for (j = 0; j < far; j++) + { + if (grub_errno == GRUB_ERR_READ_ERROR + || grub_errno == GRUB_ERR_UNKNOWN_DEVICE) + grub_errno = GRUB_ERR_NONE; + + err = grub_diskfilter_read_node (&seg->nodes[k], + read_sector + + j * far_ofs + b, + read_size, + buf); + if (! err) + break; + else if (err != GRUB_ERR_READ_ERROR + && err != GRUB_ERR_UNKNOWN_DEVICE) + return err; + k++; + if (k == seg->node_count) + k = 0; + } + + if (! err) + break; + + disknr++; + if (disknr == seg->node_count) + { + disknr = 0; + read_sector += ofs; + } + } + + if (err) + return err; + + buf += read_size << GRUB_DISK_SECTOR_BITS; + size -= read_size; + if (! size) + return GRUB_ERR_NONE; + + b = 0; + disknr += (near - i); + while (disknr >= seg->node_count) + { + disknr -= seg->node_count; + read_sector += ofs; + } + } + } + return GRUB_ERR_NONE; + + case GRUB_DISKFILTER_RAID4: + case GRUB_DISKFILTER_RAID5: + case GRUB_DISKFILTER_RAID6: + { + grub_disk_addr_t read_sector; + grub_uint64_t b, p, n, disknr, e; + + /* n = 1 for level 4 and 5, 2 for level 6. */ + n = seg->type / 3; + + /* Find the first sector to read. */ + read_sector = grub_divmod64 (sector, seg->stripe_size, &b); + read_sector = grub_divmod64 (read_sector, seg->node_count - n, + &disknr); + if (seg->type >= 5) + { + grub_divmod64 (read_sector, seg->node_count, &p); + + if (! (seg->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)) + p = seg->node_count - 1 - p; + + if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) + { + disknr += p + n; + } + else + { + grub_uint32_t q; + + q = p + (n - 1); + if (q >= seg->node_count) + q -= seg->node_count; + + if (disknr >= p) + disknr += n; + else if (disknr >= q) + disknr += q + 1; + } + + if (disknr >= seg->node_count) + disknr -= seg->node_count; + } + else + p = seg->node_count - n; + read_sector *= seg->stripe_size; + + while (1) + { + grub_size_t read_size; + int next_level; + + read_size = seg->stripe_size - b; + if (read_size > size) + read_size = size; + + e = 0; + /* Reset read error. */ + if (grub_errno == GRUB_ERR_READ_ERROR + || grub_errno == GRUB_ERR_UNKNOWN_DEVICE) + grub_errno = GRUB_ERR_NONE; + + err = grub_diskfilter_read_node (&seg->nodes[disknr], + read_sector + b, + read_size, + buf); + + if ((err) && (err != GRUB_ERR_READ_ERROR + && err != GRUB_ERR_UNKNOWN_DEVICE)) + return err; + e++; + + if (err) + { + grub_errno = GRUB_ERR_NONE; + if (seg->type == GRUB_DISKFILTER_RAID6) + { + err = ((grub_raid6_recover_func) ? + (*grub_raid6_recover_func) (seg, disknr, p, + buf, read_sector + b, + read_size) : + grub_error (GRUB_ERR_BAD_DEVICE, + "raid6rec is not loaded")); + } + else + { + err = ((grub_raid5_recover_func) ? + (*grub_raid5_recover_func) (seg, disknr, + buf, read_sector + b, + read_size) : + grub_error (GRUB_ERR_BAD_DEVICE, + "raid5rec is not loaded")); + } + + if (err) + return err; + } + + buf += read_size << GRUB_DISK_SECTOR_BITS; + size -= read_size; + sector += read_size; + if (! size) + break; + + b = 0; + disknr++; + + if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) + { + if (disknr == seg->node_count) + disknr = 0; + + next_level = (disknr == p); + } + else + { + if (disknr == p) + disknr += n; + + next_level = (disknr >= seg->node_count); + } + + if (next_level) + { + read_sector += seg->stripe_size; + + if (seg->type >= 5) + { + if (seg->layout & GRUB_RAID_LAYOUT_RIGHT_MASK) + p = (p == seg->node_count - 1) ? 0 : p + 1; + else + p = (p == 0) ? seg->node_count - 1 : p - 1; + + if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) + { + disknr = p + n; + if (disknr >= seg->node_count) + disknr -= seg->node_count; + } + else + { + disknr -= seg->node_count; + if (disknr == p) + disknr += n; + } + } + else + disknr = 0; + } + } + } + return GRUB_ERR_NONE; + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID level %d", seg->type); + } +} + +static grub_err_t +read_lv (struct grub_diskfilter_lv *lv, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + if (!lv) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume"); + + while (size) + { + grub_err_t err = 0; + struct grub_diskfilter_vg *vg = lv->vg; + struct grub_diskfilter_segment *seg = lv->segments; + grub_uint64_t extent; + grub_size_t to_read; + + extent = grub_divmod64 (sector, vg->extent_size, NULL); + + /* Find the right segment. */ + { + unsigned int i; + for (i = 0; i < lv->segment_count; i++) + { + if ((seg->start_extent <= extent) + && ((seg->start_extent + seg->extent_count) > extent)) + break; + seg++; + } + if (i == lv->segment_count) + return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment"); + } + to_read = ((seg->start_extent + seg->extent_count) + * vg->extent_size) - sector; + if (to_read > size) + to_read = size; + + err = read_segment (seg, sector - seg->start_extent * vg->extent_size, + to_read, buf); + if (err) + return err; + + size -= to_read; + sector += to_read; + buf += to_read << GRUB_DISK_SECTOR_BITS; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_diskfilter_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + return read_lv (disk->data, sector, size, buf); +} + +static grub_err_t +grub_diskfilter_write (grub_disk_t disk __attribute ((unused)), + grub_disk_addr_t sector __attribute ((unused)), + grub_size_t size __attribute ((unused)), + const char *buf __attribute ((unused))) +{ + return GRUB_ERR_NOT_IMPLEMENTED_YET; +} + +struct grub_diskfilter_vg * +grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid) +{ + struct grub_diskfilter_vg *p; + + for (p = array_list; p != NULL; p = p->next) + if ((p->uuid_len == uuidlen) && + (! grub_memcmp (p->uuid, uuid, p->uuid_len))) + return p; + return NULL; +} + +grub_err_t +grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg) +{ + struct grub_diskfilter_lv *lv, *p; + struct grub_diskfilter_vg *vgp; + unsigned i; + + grub_dprintf ("diskfilter", "Found array %s\n", vg->name); +#ifdef GRUB_UTIL + grub_util_info ("Found array %s", vg->name); +#endif + + for (lv = vg->lvs; lv; lv = lv->next) + { + lv->number = lv_num++; + + if (lv->fullname) + { + grub_size_t len; + int max_used_number = 0, need_new_name = 0; + len = grub_strlen (lv->fullname); + for (vgp = array_list; vgp; vgp = vgp->next) + for (p = vgp->lvs; p; p = p->next) + { + int cur_num; + char *num, *end; + if (!p->fullname) + continue; + if (grub_strncmp (p->fullname, lv->fullname, len) != 0) + continue; + if (p->fullname[len] == 0) + { + need_new_name = 1; + continue; + } + num = p->fullname + len + 1; + if (!grub_isdigit (num[0])) + continue; + cur_num = grub_strtoul (num, &end, 10); + if (end[0]) + continue; + if (cur_num > max_used_number) + max_used_number = cur_num; + } + if (need_new_name) + { + char *tmp; + tmp = grub_xasprintf ("%s_%d", lv->fullname, max_used_number + 1); + if (!tmp) + return grub_errno; + grub_free (lv->fullname); + lv->fullname = tmp; + } + } + /* RAID 1 doesn't use a chunksize but code assumes one so set + one. */ + for (i = 0; i < lv->segment_count; i++) + if (lv->segments[i].type == 1) + lv->segments[i].stripe_size = 64; + lv->vg = vg; + } + /* Add our new array to the list. */ + vg->next = array_list; + array_list = vg; + return GRUB_ERR_NONE; +} + +struct grub_diskfilter_vg * +grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, + char *name, grub_uint64_t disk_size, + grub_uint64_t stripe_size, + int layout, int level) +{ + struct grub_diskfilter_vg *array; + int i; + grub_uint64_t totsize; + struct grub_diskfilter_pv *pv; + grub_err_t err; + + switch (level) + { + case 1: + totsize = disk_size; + break; + + case 10: + { + int n; + n = layout & 0xFF; + if (n == 1) + n = (layout >> 8) & 0xFF; + + totsize = grub_divmod64 (nmemb * disk_size, n, 0); + } + break; + + case 0: + case 4: + case 5: + case 6: + totsize = (nmemb - level / 3) * disk_size; + break; + } + + array = grub_diskfilter_get_vg_by_uuid (uuidlen, uuid); + if (array) + { + if (array->lvs && array->lvs->size < totsize) + { + array->lvs->size = totsize; + if (array->lvs->segments) + array->lvs->segments->extent_count = totsize; + } + + if (array->lvs->segments + && array->lvs->segments->raid_member_size > disk_size) + array->lvs->segments->raid_member_size = disk_size; + + grub_free (uuid); + return array; + } + array = grub_zalloc (sizeof (*array)); + if (!array) + return NULL; + array->uuid = uuid; + array->uuid_len = uuidlen; + if (name) + { + /* Strip off the homehost if present. */ + char *colon = grub_strchr (name, ':'); + char *new_name = grub_xasprintf ("md/%s", + colon ? colon + 1 : name); + + if (! new_name) + goto fail; + + array->name = new_name; + } + array->extent_size = 1; + array->lvs = grub_zalloc (sizeof (*array->lvs)); + if (!array->lvs) + goto fail; + array->lvs->segment_count = 1; + array->lvs->visible = 1; + array->lvs->name = array->name; + array->lvs->fullname = array->name; + + array->lvs->size = totsize; + + array->lvs->segments = grub_zalloc (sizeof (*array->lvs->segments)); + if (!array->lvs->segments) + goto fail; + array->lvs->segments->stripe_size = stripe_size; + array->lvs->segments->layout = layout; + array->lvs->segments->start_extent = 0; + array->lvs->segments->extent_count = totsize; + array->lvs->segments->type = level; + array->lvs->segments->node_count = nmemb; + array->lvs->segments->raid_member_size = disk_size; + array->lvs->segments->nodes + = grub_zalloc (nmemb * sizeof (array->lvs->segments->nodes[0])); + array->lvs->segments->stripe_size = stripe_size; + for (i = 0; i < nmemb; i++) + { + pv = grub_zalloc (sizeof (*pv)); + if (!pv) + goto fail; + pv->id.uuidlen = 0; + pv->id.id = i; + pv->next = array->pvs; + array->pvs = pv; + array->lvs->segments->nodes[i].pv = pv; + } + + err = grub_diskfilter_vg_register (array); + if (err) + goto fail; + + return array; + + fail: + grub_free (array->lvs); + while (array->pvs) + { + pv = array->pvs->next; + grub_free (array->pvs); + array->pvs = pv; + } + grub_free (array); + return NULL; +} + +static grub_err_t +insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + struct grub_diskfilter_vg *array, + grub_disk_addr_t start_sector, const char *scanner_name, + grub_diskfilter_t diskfilter __attribute__ ((unused))) +{ + struct grub_diskfilter_pv *pv; + + grub_dprintf ("diskfilter", "Inserting %s into %s (%s)\n", disk->name, + array->name, scanner_name); +#ifdef GRUB_UTIL + grub_util_info ("Inserting %s into %s (%s)\n", disk->name, + array->name, scanner_name); + array->driver = diskfilter; +#endif + + for (pv = array->pvs; pv; pv = pv->next) + if (id->uuidlen == pv->id.uuidlen + && id->uuidlen + ? (grub_memcmp (pv->id.uuid, id->uuid, id->uuidlen) == 0) + : (pv->id.id == id->id)) + { + struct grub_diskfilter_lv *lv; + /* FIXME: Check whether the update time of the superblocks are + the same. */ + /* This could happen to LVM on RAID, pv->disk points to the + raid device, we shouldn't change it. */ + if (! pv->disk) + { + pv->disk = grub_disk_open (disk->name); + if (! pv->disk) + return grub_errno; + pv->part_start = grub_partition_get_start (disk->partition); + pv->part_size = grub_disk_get_size (disk); + + if (start_sector != (grub_uint64_t)-1) + pv->start_sector = start_sector; + pv->start_sector += pv->part_start; + } + /* Add the device to the array. */ + for (lv = array->lvs; lv; lv = lv->next) + if (!lv->became_readable_at && lv->fullname && is_lv_readable (lv)) + { + lv->became_readable_at = ++inscnt; + scan_disk (lv->fullname); + } + break; + } + + return 0; +} + +static void +free_array (void) +{ + while (array_list) + { + struct grub_diskfilter_vg *vg; + struct grub_diskfilter_pv *pv; + struct grub_diskfilter_lv *lv; + + vg = array_list; + array_list = array_list->next; + + while ((pv = vg->pvs)) + { + vg->pvs = pv->next; + grub_free (pv->name); + if (pv->disk) + grub_disk_close (pv->disk); + if (pv->id.uuidlen) + grub_free (pv->id.uuid); + grub_free (pv->internal_id); + grub_free (pv); + } + + while ((lv = vg->lvs)) + { + unsigned i; + vg->lvs = lv->next; + if (lv->name != lv->fullname) + grub_free (lv->fullname); + if (lv->name != vg->name) + grub_free (lv->name); + for (i = 0; i < lv->segment_count; i++) + grub_free (lv->segments[i].nodes); + grub_free (lv->segments); + grub_free (lv->internal_id); + grub_free (lv); + } + + grub_free (vg->uuid); + grub_free (vg->name); + grub_free (vg); + } + + array_list = 0; +} + +#ifdef GRUB_UTIL +struct grub_diskfilter_pv * +grub_diskfilter_get_pv_from_disk (grub_disk_t disk, + struct grub_diskfilter_vg **vg_out) +{ + struct grub_diskfilter_pv *pv; + struct grub_diskfilter_vg *vg; + + scan_disk (disk->name); + for (vg = array_list; vg; vg = vg->next) + for (pv = vg->pvs; pv; pv = pv->next) + { + if (pv->disk && pv->disk->id == disk->id + && pv->disk->dev->id == disk->dev->id + && pv->part_start == grub_partition_get_start (disk->partition) + && pv->part_size == grub_disk_get_size (disk)) + { + if (vg_out) + *vg_out = vg; + return pv; + } + } + return NULL; +} +#endif + +static struct grub_disk_dev grub_diskfilter_dev = + { + .name = "diskfilter", + .id = GRUB_DISK_DEVICE_DISKFILTER_ID, + .iterate = grub_diskfilter_iterate, + .open = grub_diskfilter_open, + .close = grub_diskfilter_close, + .read = grub_diskfilter_read, + .write = grub_diskfilter_write, +#ifdef GRUB_UTIL + .memberlist = grub_diskfilter_memberlist, + .raidname = grub_diskfilter_getname, +#endif + .next = 0 + }; + + +GRUB_MOD_INIT(diskfilter) +{ + grub_disk_dev_register (&grub_diskfilter_dev); +} + +GRUB_MOD_FINI(diskfilter) +{ + grub_disk_dev_unregister (&grub_diskfilter_dev); + free_array (); +} diff --git a/grub-core/disk/dmraid_nvidia.c b/grub-core/disk/dmraid_nvidia.c index d3f45935c..aa3a6ef6c 100644 --- a/grub-core/disk/dmraid_nvidia.c +++ b/grub-core/disk/dmraid_nvidia.c @@ -22,7 +22,9 @@ #include #include #include -#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #define NV_SIGNATURES 4 @@ -88,70 +90,91 @@ struct grub_nv_super struct grub_nv_array array; /* Array information */ } __attribute__ ((packed)); -static grub_err_t -grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array, - grub_disk_addr_t *start_sector) +static struct grub_diskfilter_vg * +grub_dmraid_nv_detect (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, + grub_disk_addr_t *start_sector) { grub_disk_addr_t sector; struct grub_nv_super sb; + int level; + int layout; + grub_uint64_t disk_size; + char *uuid; if (disk->partition) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition"); - - sector = grub_disk_get_size (disk) - 2; + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition"); + return NULL; + } + sector = grub_disk_get_size (disk); + if (sector == GRUB_DISK_SIZE_UNKNOWN) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); + return NULL; + } + sector -= 2; if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb)) - return grub_errno; + return NULL; if (grub_memcmp (sb.vendor, NV_ID_STRING, 6)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); + return NULL; + } if (sb.version != NV_VERSION) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unknown version: %d.%d", sb.version); + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unknown version: %d.%d", sb.version); + return NULL; + } switch (sb.array.raid_level) { case NV_LEVEL_0: - array->level = 0; - array->disk_size = sb.capacity / sb.array.total_volumes; + level = 0; + disk_size = sb.capacity / sb.array.total_volumes; break; case NV_LEVEL_1: - array->level = 1; - array->disk_size = sb.capacity; + level = 1; + disk_size = sb.capacity; break; case NV_LEVEL_5: - array->level = 5; - array->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC; - array->disk_size = sb.capacity / (sb.array.total_volumes - 1); + level = 5; + layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC; + disk_size = sb.capacity / (sb.array.total_volumes - 1); break; default: - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID level: %d", sb.array.raid_level); + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID level: %d", sb.array.raid_level); + return NULL; } - array->name = NULL; - array->number = 0; - array->total_devs = sb.array.total_volumes; - array->chunk_size = sb.array.stripe_block_size; - array->index = sb.unit_number; - array->uuid_len = sizeof (sb.array.signature); - array->uuid = grub_malloc (sizeof (sb.array.signature)); - if (! array->uuid) - return grub_errno; + uuid = grub_malloc (sizeof (sb.array.signature)); + if (! uuid) + return NULL; - grub_memcpy (array->uuid, (char *) &sb.array.signature, + grub_memcpy (uuid, (char *) &sb.array.signature, sizeof (sb.array.signature)); + id->uuidlen = 0; + id->id = sb.unit_number; + *start_sector = 0; - return 0; + return grub_diskfilter_make_raid (sizeof (sb.array.signature), + uuid, sb.array.total_volumes, + NULL, disk_size, + sb.array.stripe_block_size, layout, + level); } -static struct grub_raid grub_dmraid_nv_dev = +static struct grub_diskfilter grub_dmraid_nv_dev = { .name = "dmraid_nv", .detect = grub_dmraid_nv_detect, @@ -160,10 +183,10 @@ static struct grub_raid grub_dmraid_nv_dev = GRUB_MOD_INIT(dm_nv) { - grub_raid_register (&grub_dmraid_nv_dev); + grub_diskfilter_register (&grub_dmraid_nv_dev); } GRUB_MOD_FINI(dm_nv) { - grub_raid_unregister (&grub_dmraid_nv_dev); + grub_diskfilter_unregister (&grub_dmraid_nv_dev); } diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index 08094fa5c..85aa28fcf 100644 --- a/grub-core/disk/efi/efidisk.c +++ b/grub-core/disk/efi/efidisk.c @@ -33,12 +33,10 @@ struct grub_efidisk_data grub_efi_device_path_t *device_path; grub_efi_device_path_t *last_device_path; grub_efi_block_io_t *block_io; - grub_efi_disk_io_t *disk_io; struct grub_efidisk_data *next; }; -/* GUIDs. */ -static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID; +/* GUID. */ static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID; static struct grub_efidisk_data *fd_devices; @@ -86,54 +84,6 @@ find_last_device_path (const grub_efi_device_path_t *dp) return p; } -/* Compare device paths. */ -static int -compare_device_paths (const grub_efi_device_path_t *dp1, - const grub_efi_device_path_t *dp2) -{ - if (! dp1 || ! dp2) - /* Return non-zero. */ - return 1; - - while (1) - { - grub_efi_uint8_t type1, type2; - grub_efi_uint8_t subtype1, subtype2; - grub_efi_uint16_t len1, len2; - int ret; - - type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1); - type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2); - - if (type1 != type2) - return (int) type2 - (int) type1; - - subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1); - subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2); - - if (subtype1 != subtype2) - return (int) subtype1 - (int) subtype2; - - len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1); - len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2); - - if (len1 != len2) - return (int) len1 - (int) len2; - - ret = grub_memcmp (dp1, dp2, len1); - if (ret != 0) - return ret; - - if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1)) - break; - - dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1); - dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2); - } - - return 0; -} - static struct grub_efidisk_data * make_devices (void) { @@ -143,7 +93,7 @@ make_devices (void) struct grub_efidisk_data *devices = 0; /* Find handles which support the disk io interface. */ - handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_guid, + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_guid, 0, &num_handles); if (! handles) return 0; @@ -155,7 +105,6 @@ make_devices (void) grub_efi_device_path_t *ldp; struct grub_efidisk_data *d; grub_efi_block_io_t *bio; - grub_efi_disk_io_t *dio; dp = grub_efi_get_device_path (*handle); if (! dp) @@ -168,9 +117,7 @@ make_devices (void) bio = grub_efi_open_protocol (*handle, &block_io_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); - dio = grub_efi_open_protocol (*handle, &disk_io_guid, - GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (! bio || ! dio) + if (! bio) /* This should not happen... Why? */ continue; @@ -186,7 +133,6 @@ make_devices (void) d->device_path = dp; d->last_device_path = ldp; d->block_io = bio; - d->disk_io = dio; d->next = devices; devices = d; } @@ -220,7 +166,7 @@ find_parent_device (struct grub_efidisk_data *devices, if (parent == d) continue; - if (compare_device_paths (parent->device_path, dp) == 0) + if (grub_efi_compare_device_paths (parent->device_path, dp) == 0) { /* Found. */ if (! parent->last_device_path) @@ -255,7 +201,7 @@ iterate_child_devices (struct grub_efidisk_data *devices, ldp->length[0] = sizeof (*ldp); ldp->length[1] = 0; - if (compare_device_paths (dp, d->device_path) == 0) + if (grub_efi_compare_device_paths (dp, d->device_path) == 0) if (hook (p)) { grub_free (dp); @@ -279,11 +225,11 @@ add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d) { int ret; - ret = compare_device_paths (find_last_device_path ((*p)->device_path), - find_last_device_path (d->device_path)); + ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path), + find_last_device_path (d->device_path)); if (ret == 0) - ret = compare_device_paths ((*p)->device_path, - d->device_path); + ret = grub_efi_compare_device_paths ((*p)->device_path, + d->device_path); if (ret == 0) return; else if (ret > 0) @@ -432,34 +378,43 @@ enumerate_disks (void) } static int -grub_efidisk_iterate (int (*hook) (const char *name)) +grub_efidisk_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { struct grub_efidisk_data *d; char buf[16]; int count; - for (d = fd_devices, count = 0; d; d = d->next, count++) + switch (pull) { - grub_snprintf (buf, sizeof (buf), "fd%d", count); - grub_dprintf ("efidisk", "iterating %s\n", buf); - if (hook (buf)) - return 1; - } + case GRUB_DISK_PULL_NONE: + for (d = hd_devices, count = 0; d; d = d->next, count++) + { + grub_snprintf (buf, sizeof (buf), "hd%d", count); + grub_dprintf ("efidisk", "iterating %s\n", buf); + if (hook (buf)) + return 1; + } + break; + case GRUB_DISK_PULL_REMOVABLE: + for (d = fd_devices, count = 0; d; d = d->next, count++) + { + grub_snprintf (buf, sizeof (buf), "fd%d", count); + grub_dprintf ("efidisk", "iterating %s\n", buf); + if (hook (buf)) + return 1; + } - for (d = hd_devices, count = 0; d; d = d->next, count++) - { - grub_snprintf (buf, sizeof (buf), "hd%d", count); - grub_dprintf ("efidisk", "iterating %s\n", buf); - if (hook (buf)) - return 1; - } - - for (d = cd_devices, count = 0; d; d = d->next, count++) - { - grub_snprintf (buf, sizeof (buf), "cd%d", count); - grub_dprintf ("efidisk", "iterating %s\n", buf); - if (hook (buf)) - return 1; + for (d = cd_devices, count = 0; d; d = d->next, count++) + { + grub_snprintf (buf, sizeof (buf), "cd%d", count); + grub_dprintf ("efidisk", "iterating %s\n", buf); + if (hook (buf)) + return 1; + } + break; + default: + return 0; } return 0; @@ -536,8 +491,13 @@ grub_efidisk_open (const char *name, struct grub_disk *disk) and total sectors should be replaced with total blocks. */ grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n", m, (unsigned long long) m->last_block, m->block_size); - disk->total_sectors = (m->last_block - * (m->block_size >> GRUB_DISK_SECTOR_BITS)); + disk->total_sectors = m->last_block + 1; + if (m->block_size & (m->block_size - 1) || !m->block_size) + return grub_error (GRUB_ERR_IO, "invalid sector size %d", + m->block_size); + for (disk->log_sector_size = 0; + (1U << disk->log_sector_size) < m->block_size; + disk->log_sector_size++); disk->data = d; grub_dprintf ("efidisk", "opening %s succeeded\n", name); @@ -558,22 +518,20 @@ grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector, { /* For now, use the disk io interface rather than the block io's. */ struct grub_efidisk_data *d; - grub_efi_disk_io_t *dio; grub_efi_block_io_t *bio; grub_efi_status_t status; d = disk->data; - dio = d->disk_io; bio = d->block_io; grub_dprintf ("efidisk", "reading 0x%lx sectors at the sector 0x%llx from %s\n", (unsigned long) size, (unsigned long long) sector, disk->name); - status = efi_call_5 (dio->read, dio, bio->media->media_id, - (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS, - (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS, - buf); + status = efi_call_5 (bio->read_blocks, bio, bio->media->media_id, + (grub_efi_uint64_t) sector, + (grub_efi_uintn_t) size << disk->log_sector_size, + buf); if (status != GRUB_EFI_SUCCESS) return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error"); @@ -586,21 +544,19 @@ grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector, { /* For now, use the disk io interface rather than the block io's. */ struct grub_efidisk_data *d; - grub_efi_disk_io_t *dio; grub_efi_block_io_t *bio; grub_efi_status_t status; d = disk->data; - dio = d->disk_io; bio = d->block_io; grub_dprintf ("efidisk", "writing 0x%lx sectors at the sector 0x%llx to %s\n", (unsigned long) size, (unsigned long long) sector, disk->name); - status = efi_call_5 (dio->write, dio, bio->media->media_id, - (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS, - (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS, + status = efi_call_5 (bio->write_blocks, bio, bio->media->media_id, + (grub_efi_uint64_t) sector, + (grub_efi_uintn_t) size << disk->log_sector_size, (void *) buf); if (status != GRUB_EFI_SUCCESS) return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error"); @@ -708,10 +664,52 @@ grub_efidisk_get_device_handle (grub_disk_t disk) return 0; } +#define NEEDED_BUFLEN sizeof ("XdXXXXXXXXXX") +static inline int +get_diskname_from_path_real (const grub_efi_device_path_t *path, + struct grub_efidisk_data *head, + char *buf) +{ + int count = 0; + struct grub_efidisk_data *d; + for (d = head, count = 0; d; d = d->next, count++) + if (grub_efi_compare_device_paths (d->device_path, path) == 0) + { + grub_snprintf (buf, NEEDED_BUFLEN - 1, "d%d", count); + return 1; + } + return 0; +} + +static inline int +get_diskname_from_path (const grub_efi_device_path_t *path, + char *buf) +{ + if (get_diskname_from_path_real (path, hd_devices, buf + 1)) + { + buf[0] = 'h'; + return 1; + } + + if (get_diskname_from_path_real (path, fd_devices, buf + 1)) + { + buf[0] = 'f'; + return 1; + } + + if (get_diskname_from_path_real (path, cd_devices, buf + 1)) + { + buf[0] = 'c'; + return 1; + } + return 0; +} + char * grub_efidisk_get_device_name (grub_efi_handle_t *handle) { grub_efi_device_path_t *dp, *ldp; + char device_name[NEEDED_BUFLEN]; dp = grub_efi_get_device_path (handle); if (! dp) @@ -725,40 +723,14 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)) { - /* This is a hard disk partition. */ - grub_disk_t parent = 0; - grub_partition_t tpart = NULL; - char *device_name; + char *partition_name = NULL; + char *dev_name; grub_efi_device_path_t *dup_dp, *dup_ldp; grub_efi_hard_drive_device_path_t hd; - auto int find_parent_disk (const char *name); + grub_disk_t parent = 0; + auto int find_partition (grub_disk_t disk, const grub_partition_t part); - /* Find the disk which is the parent of a given hard disk partition. */ - int find_parent_disk (const char *name) - { - grub_disk_t disk; - - disk = grub_disk_open (name); - if (! disk) - return 1; - - if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) - { - struct grub_efidisk_data *d; - - d = disk->data; - if (compare_device_paths (d->device_path, dup_dp) == 0) - { - parent = disk; - return 1; - } - } - - grub_disk_close (disk); - return 0; - } - /* Find the identical partition. */ int find_partition (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t part) @@ -766,7 +738,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) if (grub_partition_get_start (part) == hd.partition_start && grub_partition_get_len (part) == hd.partition_size) { - tpart = part; + partition_name = grub_partition_get_name (part); return 1; } @@ -785,7 +757,9 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) dup_ldp->length[0] = sizeof (*dup_ldp); dup_ldp->length[1] = 0; - grub_efidisk_iterate (find_parent_disk); + if (!get_diskname_from_path (dup_dp, device_name)) + return 0; + parent = grub_disk_open (device_name); grub_free (dup_dp); if (! parent) @@ -793,58 +767,33 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) /* Find a partition which matches the hard drive device path. */ grub_memcpy (&hd, ldp, sizeof (hd)); - grub_partition_iterate (parent, find_partition); - - if (! tpart) + if (hd.partition_start == 0 + && hd.partition_size == grub_disk_get_size (parent)) { - grub_disk_close (parent); - return 0; + dev_name = grub_strdup (parent->name); } + else + { + grub_partition_iterate (parent, find_partition); - { - char *partition_name = grub_partition_get_name (tpart); - device_name = grub_xasprintf ("%s,%s", parent->name, partition_name); - grub_free (partition_name); - } + if (! partition_name) + { + grub_disk_close (parent); + return 0; + } + + dev_name = grub_xasprintf ("%s,%s", parent->name, partition_name); + grub_free (partition_name); + } grub_disk_close (parent); - return device_name; + return dev_name; } else { /* This should be an entire disk. */ - auto int find_disk (const char *name); - char *device_name = 0; - - int find_disk (const char *name) - { - grub_disk_t disk; - - disk = grub_disk_open (name); - if (! disk) - return 1; - - if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) - { - struct grub_efidisk_data *d; - - d = disk->data; - if (compare_device_paths (d->device_path, dp) == 0) - { - device_name = grub_strdup (disk->name); - grub_disk_close (disk); - return 1; - } - } - - grub_disk_close (disk); - return 0; - - } - - grub_efidisk_iterate (find_disk); - return device_name; + if (!get_diskname_from_path (dp, device_name)) + return 0; + return grub_strdup (device_name); } - - return 0; } diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c new file mode 100644 index 000000000..d3137bc16 --- /dev/null +++ b/grub-core/disk/geli.c @@ -0,0 +1,568 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2007,2010,2011 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 loosely based on FreeBSD geli implementation + (but no code was directly copied). FreeBSD geli is distributed under + following terms: */ +/*- + * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * 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 AUTHORS 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 AUTHORS 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Dirty trick to solve circular dependency. */ +#ifdef GRUB_UTIL + +#include + +#undef GRUB_MD_SHA256 +#undef GRUB_MD_SHA512 + +static const gcry_md_spec_t * +grub_md_sha256_real (void) +{ + const gcry_md_spec_t *ret; + ret = grub_crypto_lookup_md_by_name ("sha256"); + if (!ret) + grub_util_error ("Coulnd't load sha256"); + return ret; +} + +static const gcry_md_spec_t * +grub_md_sha512_real (void) +{ + const gcry_md_spec_t *ret; + ret = grub_crypto_lookup_md_by_name ("sha512"); + if (!ret) + grub_util_error ("Coulnd't load sha512"); + return ret; +} + +#define GRUB_MD_SHA256 grub_md_sha256_real() +#define GRUB_MD_SHA512 grub_md_sha512_real() +#endif + +struct grub_geli_key +{ + grub_uint8_t iv_key[64]; + grub_uint8_t cipher_key[64]; + grub_uint8_t hmac[64]; +} __attribute__ ((packed)); + +struct grub_geli_phdr +{ + grub_uint8_t magic[16]; +#define GELI_MAGIC "GEOM::ELI" + grub_uint32_t version; + grub_uint32_t flags; + grub_uint16_t alg; + grub_uint16_t keylen; + grub_uint16_t unused3[5]; + grub_uint32_t sector_size; + grub_uint8_t keys_used; + grub_uint32_t niter; + grub_uint8_t salt[64]; + struct grub_geli_key keys[2]; +} __attribute__ ((packed)); + +enum + { + GRUB_GELI_FLAGS_ONETIME = 1, + GRUB_GELI_FLAGS_BOOT = 2, + }; + +/* FIXME: support version 0. */ +/* FIXME: support big-endian pre-version-4 volumes. */ +/* FIXME: support for keyfiles. */ +/* FIXME: support for HMAC. */ +const char *algorithms[] = { + [0x01] = "des", + [0x02] = "3des", + [0x03] = "blowfish", + [0x04] = "cast5", + /* FIXME: 0x05 is skipjack, but we don't have it. */ + [0x0b] = "aes", + /* FIXME: 0x10 is null. */ + [0x15] = "camellia128", + [0x16] = "aes" +}; + +#define MAX_PASSPHRASE 256 + +static gcry_err_code_t +geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno) +{ + gcry_err_code_t gcry_err; + const struct { + char magic[4]; + grub_uint64_t zone; + } __attribute__ ((packed)) tohash + = { {'e', 'k', 'e', 'y'}, grub_cpu_to_le64 (zoneno) }; + grub_uint64_t key[(dev->hash->mdlen + 7) / 8]; + + grub_dprintf ("geli", "rekeying %" PRIuGRUB_UINT64_T " keysize=%d\n", + zoneno, dev->rekey_derived_size); + gcry_err = grub_crypto_hmac_buffer (dev->hash, dev->rekey_key, 64, + &tohash, sizeof (tohash), key); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + return grub_cryptodisk_setkey (dev, (grub_uint8_t *) key, + dev->rekey_derived_size); +} + +static inline int +ascii2hex (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return 0; +} + +static inline gcry_err_code_t +make_uuid (const struct grub_geli_phdr *header, + char *uuid) +{ + grub_uint8_t uuidbin[GRUB_MD_SHA256->mdlen]; + gcry_err_code_t err; + grub_uint8_t *iptr; + char *optr; + + err = grub_crypto_hmac_buffer (GRUB_MD_SHA256, + header->salt, sizeof (header->salt), + "uuid", sizeof ("uuid") - 1, uuidbin); + if (err) + return err; + + optr = uuid; + for (iptr = uuidbin; iptr < &uuidbin[ARRAY_SIZE (uuidbin)]; iptr++) + { + grub_snprintf (optr, 3, "%02x", *iptr); + optr += 2; + } + *optr = 0; + return GPG_ERR_NO_ERROR; +} + +#ifdef GRUB_UTIL + +#include +#include +#include +#include +#include +#include +#include +#include + +char * +grub_util_get_geli_uuid (const char *dev) +{ + int fd = open (dev, O_RDONLY); + grub_uint64_t s; + unsigned log_secsize; + grub_uint8_t hdr[512]; + struct grub_geli_phdr *header; + char *uuid; + gcry_err_code_t err; + + if (fd < 0) + return NULL; + + s = grub_util_get_fd_sectors (fd, &log_secsize); + grub_util_fd_seek (fd, dev, (s << log_secsize) - 512); + + uuid = xmalloc (GRUB_MD_SHA256->mdlen * 2 + 1); + if (grub_util_fd_read (fd, (void *) &hdr, 512) < 0) + grub_util_error (_("couldn't read ELI metadata")); + + COMPILE_TIME_ASSERT (sizeof (header) <= 512); + header = (void *) &hdr; + + /* Look for GELI magic sequence. */ + if (grub_memcmp (header->magic, GELI_MAGIC, sizeof (GELI_MAGIC)) + || grub_le_to_cpu32 (header->version) > 5 + || grub_le_to_cpu32 (header->version) < 1) + grub_util_error (_("wrong ELI magic or version")); + + err = make_uuid ((void *) &hdr, uuid); + if (err) + return NULL; + + return uuid; +} +#endif + +static grub_cryptodisk_t +configure_ciphers (grub_disk_t disk, const char *check_uuid, + int boot_only) +{ + grub_cryptodisk_t newdev; + struct grub_geli_phdr header; + grub_crypto_cipher_handle_t cipher = NULL, secondary_cipher = NULL; + const struct gcry_cipher_spec *ciph; + const char *ciphername = NULL; + gcry_err_code_t gcry_err; + char uuid[GRUB_MD_SHA256->mdlen * 2 + 1]; + grub_disk_addr_t sector; + grub_err_t err; + + sector = grub_disk_get_size (disk); + if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0) + return NULL; + + /* Read the GELI header. */ + err = grub_disk_read (disk, sector - 1, 0, sizeof (header), &header); + if (err) + return NULL; + + /* Look for GELI magic sequence. */ + if (grub_memcmp (header.magic, GELI_MAGIC, sizeof (GELI_MAGIC)) + || grub_le_to_cpu32 (header.version) > 5 + || grub_le_to_cpu32 (header.version) < 1) + { + grub_dprintf ("geli", "wrong magic %02x\n", header.magic[0]); + return NULL; + } + + if ((grub_le_to_cpu32 (header.sector_size) + & (grub_le_to_cpu32 (header.sector_size) - 1)) + || grub_le_to_cpu32 (header.sector_size) == 0) + { + grub_dprintf ("geli", "incorrect sector size %d\n", + grub_le_to_cpu32 (header.sector_size)); + return NULL; + } + + if (grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_ONETIME) + { + grub_dprintf ("geli", "skipping one-time volume\n"); + return NULL; + } + + if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) + { + grub_dprintf ("geli", "not a boot volume\n"); + return NULL; + } + + gcry_err = make_uuid (&header, uuid); + if (gcry_err) + { + grub_crypto_gcry_error (gcry_err); + return NULL; + } + + if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) + { + grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid); + return NULL; + } + + if (grub_le_to_cpu16 (header.alg) >= ARRAY_SIZE (algorithms) + || algorithms[grub_le_to_cpu16 (header.alg)] == NULL) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher 0x%x unknown", + grub_le_to_cpu16 (header.alg)); + return NULL; + } + + ciphername = algorithms[grub_le_to_cpu16 (header.alg)]; + ciph = grub_crypto_lookup_cipher_by_name (ciphername); + if (!ciph) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available", + ciphername); + return NULL; + } + + /* Configure the cipher used for the bulk data. */ + cipher = grub_crypto_cipher_open (ciph); + if (!cipher) + return NULL; + + if (grub_le_to_cpu16 (header.alg) == 0x16) + { + secondary_cipher = grub_crypto_cipher_open (ciph); + if (!secondary_cipher) + return NULL; + } + + if (grub_le_to_cpu16 (header.keylen) > 1024) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d", + grub_le_to_cpu16 (header.keylen)); + return NULL; + } + + newdev = grub_zalloc (sizeof (struct grub_cryptodisk)); + if (!newdev) + return NULL; + newdev->cipher = cipher; + newdev->secondary_cipher = secondary_cipher; + newdev->offset = 0; + newdev->source_disk = NULL; + newdev->benbi_log = 0; + if (grub_le_to_cpu16 (header.alg) == 0x16) + { + newdev->mode = GRUB_CRYPTODISK_MODE_XTS; + newdev->mode_iv = GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64; + } + else + { + newdev->mode = GRUB_CRYPTODISK_MODE_CBC; + newdev->mode_iv = GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH; + } + newdev->essiv_cipher = NULL; + newdev->essiv_hash = NULL; + newdev->hash = GRUB_MD_SHA512; + newdev->iv_hash = GRUB_MD_SHA256; + + for (newdev->log_sector_size = 0; + (1U << newdev->log_sector_size) < grub_le_to_cpu32 (header.sector_size); + newdev->log_sector_size++); + + if (grub_le_to_cpu32 (header.version) >= 5) + { + newdev->rekey = geli_rekey; + newdev->rekey_shift = 20; + } + +#ifdef GRUB_UTIL + newdev->modname = "geli"; +#endif + + newdev->total_length = grub_disk_get_size (disk) - 1; + grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid)); + COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= 32 * 2 + 1); + return newdev; +} + +static grub_err_t +recover_key (grub_disk_t source, grub_cryptodisk_t dev) +{ + grub_size_t keysize; + grub_uint8_t digest[dev->hash->mdlen]; + grub_uint8_t geomkey[dev->hash->mdlen]; + grub_uint8_t verify_key[dev->hash->mdlen]; + grub_uint8_t zero[dev->cipher->cipher->blocksize]; + char passphrase[MAX_PASSPHRASE] = ""; + unsigned i; + gcry_err_code_t gcry_err; + struct grub_geli_phdr header; + char *tmp; + grub_disk_addr_t sector; + grub_err_t err; + + sector = grub_disk_get_size (source); + if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not a geli"); + + /* Read the GELI header. */ + err = grub_disk_read (source, sector - 1, 0, sizeof (header), &header); + if (err) + return err; + + keysize = grub_le_to_cpu16 (header.keylen) / 8; + grub_memset (zero, 0, sizeof (zero)); + + grub_puts_ (N_("Attempting to decrypt master key...")); + + /* Get the passphrase from the user. */ + tmp = NULL; + if (source->partition) + tmp = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition ? "," : "", tmp ? : "", + dev->uuid); + grub_free (tmp); + if (!grub_password_get (passphrase, MAX_PASSPHRASE)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); + + /* Calculate the PBKDF2 of the user supplied passphrase. */ + if (grub_le_to_cpu32 (header.niter) != 0) + { + grub_uint8_t pbkdf_key[64]; + gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, + grub_strlen (passphrase), + header.salt, + sizeof (header.salt), + grub_le_to_cpu32 (header.niter), + pbkdf_key, sizeof (pbkdf_key)); + + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + gcry_err = grub_crypto_hmac_buffer (dev->hash, NULL, 0, pbkdf_key, + sizeof (pbkdf_key), geomkey); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + } + else + { + struct grub_crypto_hmac_handle *hnd; + + hnd = grub_crypto_hmac_init (dev->hash, NULL, 0); + if (!hnd) + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt)); + grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase)); + + gcry_err = grub_crypto_hmac_fini (hnd, geomkey); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + } + + gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey, + sizeof (geomkey), "\1", 1, digest); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey, + sizeof (geomkey), "\0", 1, verify_key); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + grub_dprintf ("geli", "keylen = %" PRIuGRUB_SIZE "\n", keysize); + + /* Try to recover master key from each active keyslot. */ + for (i = 0; i < ARRAY_SIZE (header.keys); i++) + { + struct grub_geli_key candidate_key; + grub_uint8_t key_hmac[dev->hash->mdlen]; + + /* Check if keyslot is enabled. */ + if (! (header.keys_used & (1 << i))) + continue; + + grub_dprintf ("geli", "Trying keyslot %d\n", i); + + gcry_err = grub_crypto_cipher_set_key (dev->cipher, + digest, keysize); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + gcry_err = grub_crypto_cbc_decrypt (dev->cipher, &candidate_key, + &header.keys[i], + sizeof (candidate_key), + zero); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + gcry_err = grub_crypto_hmac_buffer (dev->hash, verify_key, + sizeof (verify_key), + &candidate_key, + (sizeof (candidate_key) + - sizeof (candidate_key.hmac)), + key_hmac); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + + if (grub_memcmp (candidate_key.hmac, key_hmac, dev->hash->mdlen) != 0) + continue; + grub_printf_ (N_("Slot %d opened\n"), i); + + /* Set the master key. */ + if (!dev->rekey) + { + grub_size_t real_keysize = keysize; + if (grub_le_to_cpu16 (header.alg) == 0x16) + real_keysize *= 2; + gcry_err = grub_cryptodisk_setkey (dev, candidate_key.cipher_key, + real_keysize); + if (gcry_err) + return grub_crypto_gcry_error (gcry_err); + } + else + { + grub_size_t real_keysize = keysize; + if (grub_le_to_cpu16 (header.alg) == 0x16) + real_keysize *= 2; + /* For a reason I don't know, the IV key is used in rekeying. */ + grub_memcpy (dev->rekey_key, candidate_key.iv_key, + sizeof (candidate_key.iv_key)); + dev->rekey_derived_size = real_keysize; + dev->last_rekey = -1; + COMPILE_TIME_ASSERT (sizeof (dev->rekey_key) + >= sizeof (candidate_key.iv_key)); + } + + dev->iv_prefix_len = sizeof (candidate_key.iv_key); + grub_memcpy (dev->iv_prefix, candidate_key.iv_key, + sizeof (candidate_key.iv_key)); + + COMPILE_TIME_ASSERT (sizeof (dev->iv_prefix) >= sizeof (candidate_key.iv_key)); + + return GRUB_ERR_NONE; + } + + return GRUB_ACCESS_DENIED; +} + +struct grub_cryptodisk_dev geli_crypto = { + .scan = configure_ciphers, + .recover_key = recover_key +}; + +GRUB_MOD_INIT (geli) +{ + grub_cryptodisk_dev_register (&geli_crypto); +} + +GRUB_MOD_FINI (geli) +{ + grub_cryptodisk_dev_unregister (&geli_crypto); +} diff --git a/grub-core/disk/host.c b/grub-core/disk/host.c index c51966293..5ee0d2e56 100644 --- a/grub-core/disk/host.c +++ b/grub-core/disk/host.c @@ -27,8 +27,12 @@ int grub_disk_host_i_want_a_reference; static int -grub_host_iterate (int (*hook) (const char *name)) +grub_host_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { + if (pull != GRUB_DISK_PULL_NONE) + return 0; + if (hook ("host")) return 1; return 0; diff --git a/grub-core/disk/i386/pc/biosdisk.c b/grub-core/disk/i386/pc/biosdisk.c index 3f9015fb9..173e734d8 100644 --- a/grub-core/disk/i386/pc/biosdisk.c +++ b/grub-core/disk/i386/pc/biosdisk.c @@ -27,6 +27,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static int cd_drive = 0; static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap); @@ -282,37 +285,46 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive) } static int -grub_biosdisk_iterate (int (*hook) (const char *name)) +grub_biosdisk_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull __attribute__ ((unused))) { - int drive; int num_floppies; + int drive; /* For hard disks, attempt to read the MBR. */ - for (drive = 0x80; drive < 0x90; drive++) + switch (pull) { - if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1, - GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0) + case GRUB_DISK_PULL_NONE: + for (drive = 0x80; drive < 0x90; drive++) { - grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive); - break; + if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1, + GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0) + { + grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive); + break; + } + + if (grub_biosdisk_call_hook (hook, drive)) + return 1; + } + return 0; + + case GRUB_DISK_PULL_REMOVABLE: + if (cd_drive) + { + if (grub_biosdisk_call_hook (hook, cd_drive)) + return 1; } - if (grub_biosdisk_call_hook (hook, drive)) - return 1; + /* For floppy disks, we can get the number safely. */ + num_floppies = grub_biosdisk_get_num_floppies (); + for (drive = 0; drive < num_floppies; drive++) + if (grub_biosdisk_call_hook (hook, drive)) + return 1; + return 0; + default: + return 0; } - - if (cd_drive) - { - if (grub_biosdisk_call_hook (hook, cd_drive)) - return 1; - } - - /* For floppy disks, we can get the number safely. */ - num_floppies = grub_biosdisk_get_num_floppies (); - for (drive = 0; drive < num_floppies; drive++) - if (grub_biosdisk_call_hook (hook, drive)) - return 1; - return 0; } @@ -338,7 +350,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) if ((cd_drive) && (drive == cd_drive)) { data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; - data->sectors = 32; + data->sectors = 8; + disk->log_sector_size = 11; /* TODO: get the correct size. */ total_sectors = GRUB_DISK_SIZE_UNKNOWN; } @@ -347,6 +360,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) /* HDD */ int version; + disk->log_sector_size = 9; + version = grub_biosdisk_check_int13_extensions (drive); if (version) { @@ -367,6 +382,15 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) correctly but returns zero. So if it is zero, compute it by C/H/S returned by the LBA BIOS call. */ total_sectors = drp->cylinders * drp->heads * drp->sectors; + if (drp->bytes_per_sector + && !(drp->bytes_per_sector & (drp->bytes_per_sector - 1)) + && drp->bytes_per_sector >= 512 + && drp->bytes_per_sector <= 16384) + { + for (disk->log_sector_size = 0; + (1 << disk->log_sector_size) < drp->bytes_per_sector; + disk->log_sector_size++); + } } } } @@ -429,7 +453,7 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + (data->sectors - << GRUB_DISK_SECTOR_BITS)); + << disk->log_sector_size)); dap->length = sizeof (*dap); dap->reserved = 0; dap->blocks = size; @@ -443,9 +467,6 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, if (cmd) return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom"); - dap->blocks = ALIGN_UP (dap->blocks, 4) >> 2; - dap->block >>= 2; - for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++) if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap)) break; @@ -501,10 +522,12 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk, /* Return the number of sectors which can be read safely at a time. */ static grub_size_t -get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors) +get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector) { grub_size_t size; - grub_uint32_t offset; + grub_uint64_t offset; + struct grub_biosdisk_data *data = disk->data; + grub_uint32_t sectors = data->sectors; /* OFFSET = SECTOR % SECTORS */ grub_divmod64 (sector, sectors, &offset); @@ -512,8 +535,8 @@ get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors) size = sectors - offset; /* Limit the max to 0x7f because of Phoenix EDD. */ - if (size > 0x7f) - size = 0x7f; + if (size > ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size)) + size = ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size); return size; } @@ -522,21 +545,11 @@ static grub_err_t grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) { - struct grub_biosdisk_data *data = disk->data; - while (size) { grub_size_t len; - grub_size_t cdoff = 0; - len = get_safe_sectors (sector, data->sectors); - - if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) - { - cdoff = (sector & 3) << GRUB_DISK_SECTOR_BITS; - len = ALIGN_UP (sector + len, 4) - (sector & ~3); - sector &= ~3; - } + len = get_safe_sectors (disk, sector); if (len > size) len = size; @@ -545,9 +558,10 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, GRUB_MEMORY_MACHINE_SCRATCH_SEG)) return grub_errno; - grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdoff), - len << GRUB_DISK_SECTOR_BITS); - buf += len << GRUB_DISK_SECTOR_BITS; + grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, + len << disk->log_sector_size); + + buf += len << disk->log_sector_size; sector += len; size -= len; } @@ -568,18 +582,18 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, { grub_size_t len; - len = get_safe_sectors (sector, data->sectors); + len = get_safe_sectors (disk, sector); if (len > size) len = size; grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf, - len << GRUB_DISK_SECTOR_BITS); + len << disk->log_sector_size); if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len, GRUB_MEMORY_MACHINE_SCRATCH_SEG)) return grub_errno; - buf += len << GRUB_DISK_SECTOR_BITS; + buf += len << disk->log_sector_size; sector += len; size -= len; } @@ -608,11 +622,12 @@ grub_disk_biosdisk_fini (void) GRUB_MOD_INIT(biosdisk) { struct grub_biosdisk_cdrp *cdrp - = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_uint8_t boot_drive; if (grub_disk_firmware_is_tainted) { - grub_printf ("Firmware is marked as tainted, refusing to initialize.\n"); + grub_puts_ (N_("Firmware is marked as tainted, refusing to initialize.")); return; } grub_disk_firmware_fini = grub_disk_biosdisk_fini; @@ -620,10 +635,16 @@ GRUB_MOD_INIT(biosdisk) grub_memset (cdrp, 0, sizeof (*cdrp)); cdrp->size = sizeof (*cdrp); cdrp->media_type = 0xFF; - if ((! grub_biosdisk_get_cdinfo_int13_extensions (grub_boot_drive, cdrp)) && - ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK) - == GRUB_BIOSDISK_CDTYPE_NO_EMUL)) + boot_drive = (grub_boot_device >> 24); + if ((! grub_biosdisk_get_cdinfo_int13_extensions (boot_drive, cdrp)) + && ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK) + == GRUB_BIOSDISK_CDTYPE_NO_EMUL)) cd_drive = cdrp->drive_no; + /* Since diskboot.S rejects devices over 0x90 it must be a CD booted with + cdboot.S + */ + if (boot_drive >= 0x90) + cd_drive = boot_drive; grub_disk_dev_register (&grub_biosdisk_dev); } diff --git a/grub-core/disk/ieee1275/nand.c b/grub-core/disk/ieee1275/nand.c index a2c717cdb..94d62bc4f 100644 --- a/grub-core/disk/ieee1275/nand.c +++ b/grub-core/disk/ieee1275/nand.c @@ -23,6 +23,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_nand_data { grub_ieee1275_ihandle_t handle; @@ -30,7 +32,8 @@ struct grub_nand_data }; static int -grub_nand_iterate (int (*hook) (const char *name)) +grub_nand_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { auto int dev_iterate (struct grub_ieee1275_devalias *alias); int dev_iterate (struct grub_ieee1275_devalias *alias) @@ -44,6 +47,9 @@ grub_nand_iterate (int (*hook) (const char *name)) return 0; } + if (pull != GRUB_DISK_PULL_NONE) + return 0; + return grub_devalias_iterate (dev_iterate); } diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index 85c34609e..4481837de 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -62,11 +62,10 @@ ofdisk_hash_find (const char *devpath) } static struct ofdisk_hash_ent * -ofdisk_hash_add (char *devpath) +ofdisk_hash_add_real (char *devpath) { + struct ofdisk_hash_ent *p; struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; - struct ofdisk_hash_ent *p, *pcan; - char *curcan; p = grub_malloc(sizeof (*p)); if (!p) @@ -76,17 +75,27 @@ ofdisk_hash_add (char *devpath) p->next = *head; p->shortest = 0; *head = p; + return p; +} + +static struct ofdisk_hash_ent * +ofdisk_hash_add (char *devpath, char *curcan) +{ + struct ofdisk_hash_ent *p, *pcan; + + p = ofdisk_hash_add_real (devpath); + + grub_dprintf ("disk", "devpath = %s, canonical = %s\n", devpath, curcan); - curcan = grub_ieee1275_canonicalise_devname (devpath); if (!curcan) { - grub_errno = GRUB_ERR_NONE; + p->shortest = devpath; return p; } pcan = ofdisk_hash_find (curcan); if (!pcan) - pcan = ofdisk_hash_add (curcan); + pcan = ofdisk_hash_add_real (curcan); else grub_free (curcan); @@ -118,17 +127,22 @@ scan (void) return 0; grub_dprintf ("disk", "disk name = %s\n", alias->name); + grub_dprintf ("disk", "disk name = %s, path = %s\n", alias->name, + alias->path); - op = ofdisk_hash_find (alias->path); + op = ofdisk_hash_find (alias->name); if (!op) { char *name = grub_strdup (alias->name); - if (!name) + char *can = grub_strdup (alias->path); + if (!name || !can) { grub_errno = GRUB_ERR_NONE; + grub_free (name); + grub_free (can); return 0; } - op = ofdisk_hash_add (name); + op = ofdisk_hash_add (name, can); } return 0; } @@ -138,9 +152,14 @@ scan (void) } static int -grub_ofdisk_iterate (int (*hook) (const char *name)) +grub_ofdisk_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { unsigned i; + + if (pull != GRUB_DISK_PULL_NONE) + return 0; + scan (); for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++) @@ -179,8 +198,14 @@ grub_ofdisk_iterate (int (*hook) (const char *name)) if (grub_strncmp (ent->shortest, "cdrom", 5) == 0) continue; - if (hook (ent->shortest)) - return 1; + { + char buffer[sizeof ("ieee1275/") + grub_strlen (ent->shortest)]; + char *ptr; + ptr = grub_stpcpy (buffer, "ieee1275/"); + grub_strcpy (ptr, ent->shortest); + if (hook (buffer)) + return 1; + } } } return 0; @@ -222,21 +247,34 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) char prop[64]; grub_ssize_t actual; - devpath = compute_dev_path (name); + if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "not IEEE1275 device"); + devpath = compute_dev_path (name + sizeof ("ieee1275/") - 1); if (! devpath) return grub_errno; grub_dprintf ("disk", "Opening `%s'.\n", devpath); if (grub_ieee1275_finddevice (devpath, &dev)) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); + { + grub_free (devpath); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "can't read device properties"); + } if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), &actual)) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); + { + grub_free (devpath); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); + } if (grub_strcmp (prop, "block")) - return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); + { + grub_free (devpath); + return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); + } /* XXX: There is no property to read the number of blocks. There should be a property `#blocks', but it is not there. Perhaps it @@ -247,7 +285,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) struct ofdisk_hash_ent *op; op = ofdisk_hash_find (devpath); if (!op) - op = ofdisk_hash_add (devpath); + op = ofdisk_hash_add (devpath, NULL); else grub_free (devpath); if (!op) @@ -273,10 +311,9 @@ grub_ofdisk_close (grub_disk_t disk) } static grub_err_t -grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) +grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) { - grub_ssize_t status, actual; + grub_ssize_t status; unsigned long long pos; if (disk->data != last_devpath) @@ -305,15 +342,28 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, last_devpath = disk->data; } - pos = sector * 512UL; + pos = sector << GRUB_DISK_SECTOR_BITS; grub_ieee1275_seek (last_ihandle, pos, &status); if (status < 0) return grub_error (GRUB_ERR_READ_ERROR, "seek error, can't seek block %llu", (long long) sector); - grub_ieee1275_read (last_ihandle, buf, size * 512UL, &actual); - if (actual != (grub_ssize_t) (size * 512UL)) + return 0; +} + +static grub_err_t +grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_err_t err; + grub_ssize_t actual; + err = grub_ofdisk_prepare (disk, sector); + if (err) + return err; + grub_ieee1275_read (last_ihandle, buf, size << GRUB_DISK_SECTOR_BITS, + &actual); + if (actual != (grub_ssize_t) (size << GRUB_DISK_SECTOR_BITS)) return grub_error (GRUB_ERR_READ_ERROR, "read error on block: %llu", (long long) sector); @@ -321,12 +371,21 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, } static grub_err_t -grub_ofdisk_write (grub_disk_t disk __attribute ((unused)), - grub_disk_addr_t sector __attribute ((unused)), - grub_size_t size __attribute ((unused)), - const char *buf __attribute ((unused))) +grub_ofdisk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) { - return GRUB_ERR_NOT_IMPLEMENTED_YET; + grub_err_t err; + grub_ssize_t actual; + err = grub_ofdisk_prepare (disk, sector); + if (err) + return err; + grub_ieee1275_write (last_ihandle, buf, size << GRUB_DISK_SECTOR_BITS, + &actual); + if (actual != (grub_ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + return grub_error (GRUB_ERR_WRITE_ERROR, "write error on block: %llu", + (long long) sector); + + return 0; } static struct grub_disk_dev grub_ofdisk_dev = diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c new file mode 100644 index 000000000..08568e9d5 --- /dev/null +++ b/grub-core/disk/ldm.c @@ -0,0 +1,997 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009,2011 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 + +#ifdef GRUB_UTIL +#include +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define LDM_GUID_STRLEN 64 +#define LDM_NAME_STRLEN 32 + +typedef grub_uint8_t *grub_ldm_id_t; + +enum { STRIPE = 1, SPANNED = 2, RAID5 = 3 }; + +#define LDM_LABEL_SECTOR 6 +struct grub_ldm_vblk { + char magic[4]; + grub_uint8_t unused1[12]; + grub_uint16_t update_status; + grub_uint8_t flags; + grub_uint8_t type; + grub_uint32_t unused2; + grub_uint8_t dynamic[104]; +} __attribute__ ((packed)); +#define LDM_VBLK_MAGIC "VBLK" + +enum + { + STATUS_CONSISTENT = 0, + STATUS_STILL_ACTIVE = 1, + STATUS_NOT_ACTIVE_YET = 2 + }; + +enum + { + ENTRY_COMPONENT = 0x32, + ENTRY_PARTITION = 0x33, + ENTRY_DISK = 0x34, + ENTRY_VOLUME = 0x51, + }; + +struct grub_ldm_label +{ + char magic[8]; + grub_uint32_t unused1; + grub_uint16_t ver_major; + grub_uint16_t ver_minor; + grub_uint8_t unused2[32]; + char disk_guid[LDM_GUID_STRLEN]; + char host_guid[LDM_GUID_STRLEN]; + char group_guid[LDM_GUID_STRLEN]; + char group_name[LDM_NAME_STRLEN]; + grub_uint8_t unused3[11]; + grub_uint64_t pv_start; + grub_uint64_t pv_size; + grub_uint64_t config_start; + grub_uint64_t config_size; +} __attribute__ ((packed)); + + +#define LDM_MAGIC "PRIVHEAD" + + + +static inline grub_uint64_t +read_int (grub_uint8_t *in, grub_size_t s) +{ + grub_uint8_t *ptr2; + grub_uint64_t ret; + ret = 0; + for (ptr2 = in; ptr2 < in + s; ptr2++) + { + ret <<= 8; + ret |= *ptr2; + } + return ret; +} + +static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM; + +static grub_disk_addr_t +gpt_ldm_sector (grub_disk_t dsk) +{ + grub_disk_addr_t sector = 0; + grub_err_t err; + auto int hook (grub_disk_t disk, const grub_partition_t p); + int hook (grub_disk_t disk, const grub_partition_t p) + { + struct grub_gpt_partentry gptdata; + grub_partition_t p2; + + p2 = disk->partition; + disk->partition = p->parent; + if (grub_disk_read (disk, p->offset, p->index, + sizeof (gptdata), &gptdata)) + { + disk->partition = p2; + return 0; + } + disk->partition = p2; + + if (! grub_memcmp (&gptdata.type, &ldm_type, 16)) + { + sector = p->start + p->len - 1; + return 1; + } + return 0; + } + err = grub_gpt_partition_map_iterate (dsk, hook); + if (err) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + return sector; +} + +static struct grub_diskfilter_vg * +make_vg (grub_disk_t disk, + const struct grub_ldm_label *label) +{ + grub_disk_addr_t startsec, endsec, cursec; + struct grub_diskfilter_vg *vg; + grub_err_t err; + + /* First time we see this volume group. We've to create the + whole volume group structure. */ + vg = grub_malloc (sizeof (*vg)); + if (! vg) + return NULL; + vg->extent_size = 1; + vg->name = grub_malloc (LDM_NAME_STRLEN + 1); + vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1); + if (! vg->uuid || !vg->name) + { + grub_free (vg->uuid); + grub_free (vg->name); + return NULL; + } + grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN); + grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN); + vg->name[LDM_NAME_STRLEN] = 0; + vg->uuid[LDM_GUID_STRLEN] = 0; + vg->uuid_len = grub_strlen (vg->uuid); + + vg->lvs = NULL; + vg->pvs = NULL; + + startsec = grub_be_to_cpu64 (label->config_start); + endsec = startsec + grub_be_to_cpu64 (label->config_size); + + /* First find disks. */ + for (cursec = startsec + 0x12; cursec < endsec; cursec++) + { + struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_ldm_vblk)]; + unsigned i; + err = grub_disk_read (disk, cursec, 0, + sizeof(vblk), &vblk); + if (err) + goto fail2; + + for (i = 0; i < ARRAY_SIZE (vblk); i++) + { + struct grub_diskfilter_pv *pv; + grub_uint8_t *ptr; + if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC, + sizeof (vblk[i].magic)) != 0) + continue; + if (grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_CONSISTENT + && grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_STILL_ACTIVE) + continue; + if (vblk[i].type != ENTRY_DISK) + continue; + pv = grub_zalloc (sizeof (*pv)); + if (!pv) + goto fail2; + + pv->disk = 0; + ptr = vblk[i].dynamic; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (pv); + goto fail2; + } + pv->internal_id = grub_malloc (ptr[0] + 2); + if (!pv->internal_id) + { + grub_free (pv); + goto fail2; + } + grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1); + pv->internal_id[(grub_size_t) ptr[0] + 1] = 0; + + ptr += *ptr + 1; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (pv); + goto fail2; + } + /* ptr = name. */ + ptr += *ptr + 1; + if (ptr + *ptr + 1 + >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (pv); + goto fail2; + } + pv->id.uuidlen = *ptr; + pv->id.uuid = grub_malloc (pv->id.uuidlen + 1); + grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen); + pv->id.uuid[pv->id.uuidlen] = 0; + + pv->next = vg->pvs; + vg->pvs = pv; + } + } + + /* Then find LVs. */ + for (cursec = startsec + 0x12; cursec < endsec; cursec++) + { + struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_ldm_vblk)]; + unsigned i; + err = grub_disk_read (disk, cursec, 0, + sizeof(vblk), &vblk); + if (err) + goto fail2; + + for (i = 0; i < ARRAY_SIZE (vblk); i++) + { + struct grub_diskfilter_lv *lv; + grub_uint8_t *ptr; + if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC, + sizeof (vblk[i].magic)) != 0) + continue; + if (grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_CONSISTENT + && grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_STILL_ACTIVE) + continue; + if (vblk[i].type != ENTRY_VOLUME) + continue; + lv = grub_zalloc (sizeof (*lv)); + if (!lv) + goto fail2; + + lv->vg = vg; + lv->segment_count = 1; + lv->segment_alloc = 1; + lv->visible = 1; + lv->segments = grub_zalloc (sizeof (*lv->segments)); + if (!lv->segments) + goto fail2; + lv->segments->start_extent = 0; + lv->segments->type = GRUB_DISKFILTER_MIRROR; + lv->segments->node_count = 0; + lv->segments->node_alloc = 8; + lv->segments->nodes = grub_zalloc (sizeof (*lv->segments->nodes) + * lv->segments->node_alloc); + if (!lv->segments->nodes) + goto fail2; + ptr = vblk[i].dynamic; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (lv); + goto fail2; + } + lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); + if (!lv->internal_id) + { + grub_free (lv); + goto fail2; + } + grub_memcpy (lv->internal_id, ptr, ptr[0] + 1); + lv->internal_id[ptr[0] + 1] = 0; + + ptr += *ptr + 1; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (lv); + goto fail2; + } + lv->name = grub_malloc (*ptr + 1); + if (!lv->name) + { + grub_free (lv->internal_id); + grub_free (lv); + goto fail2; + } + grub_memcpy (lv->name, ptr + 1, *ptr); + lv->name[*ptr] = 0; + lv->fullname = grub_xasprintf ("ldm/%s/%s", + vg->uuid, lv->name); + if (!lv->fullname) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + ptr += *ptr + 1; + if (ptr + *ptr + 1 + >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + /* ptr = volume type. */ + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + /* ptr = flags. */ + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + + /* Skip state, type, unknown, volume number, zeros, flags. */ + ptr += 14 + 1 + 1 + 1 + 3 + 1; + /* ptr = number of children. */ + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + + /* Skip 2 more fields. */ + ptr += 8 + 8; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) + || ptr + *ptr + 1>= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv); + goto fail2; + } + lv->size = read_int (ptr + 1, *ptr); + lv->segments->extent_count = lv->size; + + lv->next = vg->lvs; + vg->lvs = lv; + } + } + + /* Now the components. */ + for (cursec = startsec + 0x12; cursec < endsec; cursec++) + { + struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_ldm_vblk)]; + unsigned i; + err = grub_disk_read (disk, cursec, 0, + sizeof(vblk), &vblk); + if (err) + goto fail2; + + for (i = 0; i < ARRAY_SIZE (vblk); i++) + { + struct grub_diskfilter_lv *comp; + struct grub_diskfilter_lv *lv; + grub_uint8_t type; + + grub_uint8_t *ptr; + if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC, + sizeof (vblk[i].magic)) != 0) + continue; + if (grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_CONSISTENT + && grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_STILL_ACTIVE) + continue; + if (vblk[i].type != ENTRY_COMPONENT) + continue; + comp = grub_zalloc (sizeof (*comp)); + if (!comp) + goto fail2; + comp->visible = 0; + comp->name = 0; + comp->fullname = 0; + + ptr = vblk[i].dynamic; + if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); + if (!comp->internal_id) + { + grub_free (comp); + goto fail2; + } + grub_memcpy (comp->internal_id, ptr, ptr[0] + 1); + comp->internal_id[ptr[0] + 1] = 0; + + ptr += *ptr + 1; + if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + /* ptr = name. */ + ptr += *ptr + 1; + if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + /* ptr = state. */ + ptr += *ptr + 1; + type = *ptr++; + /* skip zeros. */ + ptr += 4; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + + /* ptr = number of children. */ + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + ptr += 8 + 8; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + for (lv = vg->lvs; lv; lv = lv->next) + { + if (lv->internal_id[0] == ptr[0] + && grub_memcmp (lv->internal_id + 1, ptr + 1, ptr[0]) == 0) + break; + } + if (!lv) + { + grub_free (comp->internal_id); + grub_free (comp); + continue; + } + comp->size = lv->size; + if (type == SPANNED) + { + comp->segment_alloc = 8; + comp->segment_count = 0; + comp->segments = grub_malloc (sizeof (*comp->segments) + * comp->segment_alloc); + if (!comp->segments) + goto fail2; + } + else + { + comp->segment_alloc = 1; + comp->segment_count = 1; + comp->segments = grub_malloc (sizeof (*comp->segments)); + if (!comp->segments) + goto fail2; + comp->segments->start_extent = 0; + comp->segments->extent_count = lv->size; + comp->segments->layout = 0; + if (type == STRIPE) + comp->segments->type = GRUB_DISKFILTER_STRIPED; + else if (type == RAID5) + { + comp->segments->type = GRUB_DISKFILTER_RAID5; + comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK; + } + else + goto fail2; + ptr += *ptr + 1; + ptr++; + if (!(vblk[i].flags & 0x10)) + goto fail2; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) + || ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + comp->segments->stripe_size = read_int (ptr + 1, *ptr); + ptr += *ptr + 1; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + grub_free (comp->internal_id); + grub_free (comp); + goto fail2; + } + comp->segments->node_count = read_int (ptr + 1, *ptr); + comp->segments->node_alloc = comp->segments->node_count; + comp->segments->nodes = grub_zalloc (sizeof (*comp->segments->nodes) + * comp->segments->node_alloc); + if (!lv->segments->nodes) + goto fail2; + } + + if (lv->segments->node_alloc == lv->segments->node_count) + { + void *t; + lv->segments->node_alloc *= 2; + t = grub_realloc (lv->segments->nodes, + sizeof (*lv->segments->nodes) + * lv->segments->node_alloc); + if (!t) + goto fail2; + lv->segments->nodes = t; + } + lv->segments->nodes[lv->segments->node_count].pv = 0; + lv->segments->nodes[lv->segments->node_count].start = 0; + lv->segments->nodes[lv->segments->node_count++].lv = comp; + comp->next = vg->lvs; + vg->lvs = comp; + } + } + /* Partitions. */ + for (cursec = startsec + 0x12; cursec < endsec; cursec++) + { + struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_ldm_vblk)]; + unsigned i; + err = grub_disk_read (disk, cursec, 0, + sizeof(vblk), &vblk); + if (err) + goto fail2; + + for (i = 0; i < ARRAY_SIZE (vblk); i++) + { + struct grub_diskfilter_lv *comp; + struct grub_diskfilter_node part; + grub_disk_addr_t start, size; + + grub_uint8_t *ptr; + if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC, + sizeof (vblk[i].magic)) != 0) + continue; + if (grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_CONSISTENT + && grub_be_to_cpu16 (vblk[i].update_status) + != STATUS_STILL_ACTIVE) + continue; + if (vblk[i].type != ENTRY_PARTITION) + continue; + part.lv = 0; + part.pv = 0; + + ptr = vblk[i].dynamic; + if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + /* ID */ + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + /* ptr = name. */ + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + + /* skip zeros and logcommit id. */ + ptr += 4 + 8; + if (ptr + 16 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + part.start = read_int (ptr, 8); + start = read_int (ptr + 8, 8); + ptr += 16; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) + || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + size = read_int (ptr + 1, *ptr); + ptr += *ptr + 1; + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) + || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + + for (comp = vg->lvs; comp; comp = comp->next) + if (comp->internal_id[0] == ptr[0] + && grub_memcmp (ptr + 1, comp->internal_id + 1, + comp->internal_id[0]) == 0) + goto out; + continue; + out: + if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic) + || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + ptr += *ptr + 1; + struct grub_diskfilter_pv *pv; + for (pv = vg->pvs; pv; pv = pv->next) + if (pv->internal_id[0] == ptr[0] + && grub_memcmp (pv->internal_id + 1, ptr + 1, ptr[0]) == 0) + part.pv = pv; + + if (comp->segment_alloc == 1) + { + unsigned index; + ptr += *ptr + 1; + if (ptr + *ptr + 1 >= vblk[i].dynamic + + sizeof (vblk[i].dynamic)) + { + goto fail2; + } + index = read_int (ptr + 1, *ptr); + if (index < comp->segments->node_count) + comp->segments->nodes[index] = part; + } + else + { + if (comp->segment_alloc == comp->segment_count) + { + void *t; + comp->segment_alloc *= 2; + t = grub_realloc (comp->segments, + comp->segment_alloc + * sizeof (*comp->segments)); + if (!t) + goto fail2; + comp->segments = t; + } + comp->segments[comp->segment_count].start_extent = start; + comp->segments[comp->segment_count].extent_count = size; + comp->segments[comp->segment_count].type = GRUB_DISKFILTER_STRIPED; + comp->segments[comp->segment_count].node_count = 1; + comp->segments[comp->segment_count].node_alloc = 1; + comp->segments[comp->segment_count].nodes + = grub_malloc (sizeof (*comp->segments[comp->segment_count].nodes)); + if (!comp->segments[comp->segment_count].nodes) + goto fail2; + comp->segments[comp->segment_count].nodes[0] = part; + comp->segment_count++; + } + } + } + if (grub_diskfilter_vg_register (vg)) + goto fail2; + return vg; + fail2: + { + struct grub_diskfilter_lv *lv, *next_lv; + struct grub_diskfilter_pv *pv, *next_pv; + for (lv = vg->lvs; lv; lv = next_lv) + { + unsigned i; + for (i = 0; i < lv->segment_count; i++) + grub_free (lv->segments[i].nodes); + + next_lv = lv->next; + grub_free (lv->segments); + grub_free (lv->internal_id); + grub_free (lv->name); + grub_free (lv->fullname); + grub_free (lv); + } + for (pv = vg->pvs; pv; pv = next_pv) + { + next_pv = pv->next; + grub_free (pv->id.uuid); + grub_free (pv); + } + } + grub_free (vg->uuid); + grub_free (vg); + return NULL; +} + +static struct grub_diskfilter_vg * +grub_ldm_detect (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, + grub_disk_addr_t *start_sector) +{ + grub_err_t err; + struct grub_ldm_label label; + struct grub_diskfilter_vg *vg; + +#ifdef GRUB_UTIL + grub_util_info ("scanning %s for LDM", disk->name); +#endif + + { + int i; + for (i = 0; i < 3; i++) + { + grub_disk_addr_t sector; + switch (i) + { + case 0: + sector = LDM_LABEL_SECTOR; + break; + case 1: + /* LDM is never inside a partition. */ + if (disk->partition) + continue; + sector = grub_disk_get_size (disk); + if (sector == GRUB_DISK_SIZE_UNKNOWN) + continue; + sector--; + break; + /* FIXME: try the third copy. */ + case 2: + sector = gpt_ldm_sector (disk); + if (!sector) + continue; + break; + } + err = grub_disk_read (disk, sector, 0, + sizeof(label), &label); + if (err) + return NULL; + if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0 + && grub_be_to_cpu16 (label.ver_major) == 0x02 + && grub_be_to_cpu16 (label.ver_minor) >= 0x0b + && grub_be_to_cpu16 (label.ver_minor) <= 0x0c) + break; + } + + /* Return if we didn't find a label. */ + if (i == 3) + { +#ifdef GRUB_UTIL + grub_util_info ("no LDM signature found"); +#endif + return NULL; + } + } + + id->uuid = grub_malloc (LDM_GUID_STRLEN + 1); + if (!id->uuid) + return NULL; + grub_memcpy (id->uuid, label.disk_guid, LDM_GUID_STRLEN); + id->uuid[LDM_GUID_STRLEN] = 0; + id->uuidlen = grub_strlen ((char *) id->uuid); + *start_sector = grub_be_to_cpu64 (label.pv_start); + + { + grub_size_t s; + for (s = 0; s < LDM_GUID_STRLEN && label.group_guid[s]; s++); + vg = grub_diskfilter_get_vg_by_uuid (s, label.group_guid); + if (! vg) + vg = make_vg (disk, &label); + } + + if (!vg) + { + grub_free (id->uuid); + return NULL; + } + return vg; +} + +#ifdef GRUB_UTIL + +char * +grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start) +{ + struct grub_diskfilter_pv *pv = NULL; + struct grub_diskfilter_vg *vg = NULL; + struct grub_diskfilter_lv *res, *lv; + int i; + + pv = grub_diskfilter_get_pv_from_disk (disk, &vg); + + if (!pv) + return NULL; + + for (lv = vg->lvs; lv; lv = lv->next) + if (lv->segment_count == 1 && lv->segments->node_count == 1 + && lv->segments->type == GRUB_DISKFILTER_STRIPED + && lv->segments->nodes->pv == pv + && lv->segments->nodes->start + pv->start_sector == start) + { + res = lv; + break; + } + for (lv = vg->lvs; lv; lv = lv->next) + if (lv->segment_count == 1 && lv->segments->node_count == 1 + && lv->segments->type == GRUB_DISKFILTER_MIRROR + && lv->segments->nodes->lv == lv) + { + res = lv; + break; + } + if (res->fullname) + return grub_strdup (lv->fullname); + return NULL; +} + +int +grub_util_is_ldm (grub_disk_t disk) +{ + int i; + for (i = 0; i < 3; i++) + { + grub_disk_addr_t sector; + grub_err_t err; + struct grub_ldm_label label; + + switch (i) + { + case 0: + sector = LDM_LABEL_SECTOR; + break; + case 1: + /* LDM is never inside a partition. */ + if (disk->partition) + continue; + sector = grub_disk_get_size (disk); + if (sector == GRUB_DISK_SIZE_UNKNOWN) + continue; + sector--; + break; + /* FIXME: try the third copy. */ + case 2: + sector = gpt_ldm_sector (disk); + if (!sector) + continue; + break; + } + err = grub_disk_read (disk, sector, 0, sizeof(label), &label); + if (err) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + /* This check is more relaxed on purpose. */ + if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0) + return 1; + } + + return 0; +} + +grub_err_t +grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) +{ + struct grub_diskfilter_pv *pv = NULL; + struct grub_diskfilter_vg *vg; + struct grub_diskfilter_lv *lv; + unsigned i; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "GPT curently supports only PC-BIOS embedding"); + if (disk->partition) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM"); + pv = grub_diskfilter_get_pv_from_disk (disk, &vg); + if (!pv) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM"); + for (lv = vg->lvs; lv; lv = lv->next) + { + struct grub_diskfilter_lv *comp; + struct grub_ldm_partition *part; + + if (!lv->visible || !lv->fullname) + continue; + + if (lv->segment_count != 1) + continue; + if (lv->segments->type != GRUB_DISKFILTER_MIRROR + || lv->segments->node_count != 1 + || lv->segments->start_extent != 0 + || lv->segments->extent_count != lv->size) + continue; + + comp = lv->segments->nodes->lv; + if (!comp) + continue; + + if (comp->segment_count != 1 || comp->size != lv->size) + continue; + if (comp->segments->type != GRUB_DISKFILTER_STRIPED + || comp->segments->node_count != 1 + || comp->segments->start_extent != 0 + || comp->segments->extent_count != lv->size) + continue; + + /* How to implement proper check is to be discussed. */ +#if 1 + if (1) + continue; +#else + if (grub_strcmp (lv->name, "Volume5") != 0) + continue; +#endif + if (lv->size < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your LDM embed Partition is too small;" + " embedding won't be possible!"); + *nsectors = lv->size; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = (lv->segments->nodes->start + + comp->segments->nodes->start + + comp->segments->nodes->pv->start_sector + i); + return GRUB_ERR_NONE; + } + + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "This LDM no Embedding Partition;" + " embedding won't be possible!"); +} +#endif + +static struct grub_diskfilter grub_ldm_dev = { + .name = "ldm", + .detect = grub_ldm_detect, + .next = 0 +}; + +GRUB_MOD_INIT (ldm) +{ + grub_diskfilter_register (&grub_ldm_dev); +} + +GRUB_MOD_FINI (ldm) +{ + grub_diskfilter_unregister (&grub_ldm_dev); +} diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index ae4cb9a9c..dca83b7c6 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_loopback { char *devname; @@ -97,10 +99,6 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) if (newdev) { - char *newname = grub_strdup (args[1]); - if (! newname) - goto fail; - grub_file_close (newdev->file); newdev->file = file; @@ -135,9 +133,12 @@ fail: static int -grub_loopback_iterate (int (*hook) (const char *name)) +grub_loopback_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { struct grub_loopback *d; + if (pull != GRUB_DISK_PULL_NONE) + return 0; for (d = loopback_list; d; d = d->next) { if (hook (d->devname)) @@ -166,7 +167,7 @@ grub_loopback_open (const char *name, grub_disk_t disk) disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; disk->id = (unsigned long) dev; - disk->data = dev->file; + disk->data = dev; return 0; } @@ -175,7 +176,7 @@ static grub_err_t grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) { - grub_file_t file = (grub_file_t) disk->data; + grub_file_t file = ((struct grub_loopback *) disk->data)->file; grub_off_t pos; grub_file_seek (file, sector << GRUB_DISK_SECTOR_BITS); @@ -222,7 +223,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(loopback) { cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, 0, - N_("[-d|-p] DEVICENAME FILE."), + N_("[-d] DEVICENAME FILE."), N_("Make a device of a file."), options); grub_disk_dev_register (&grub_loopback_dev); } diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c new file mode 100644 index 000000000..a5c0d3418 --- /dev/null +++ b/grub-core/disk/luks.c @@ -0,0 +1,470 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2007,2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define MAX_PASSPHRASE 256 + +#define LUKS_KEY_ENABLED 0x00AC71F3 + +/* On disk LUKS header */ +struct grub_luks_phdr +{ + grub_uint8_t magic[6]; +#define LUKS_MAGIC "LUKS\xBA\xBE" + grub_uint16_t version; + char cipherName[32]; + char cipherMode[32]; + char hashSpec[32]; + grub_uint32_t payloadOffset; + grub_uint32_t keyBytes; + grub_uint8_t mkDigest[20]; + grub_uint8_t mkDigestSalt[32]; + grub_uint32_t mkDigestIterations; + char uuid[40]; + struct + { + grub_uint32_t active; + grub_uint32_t passwordIterations; + grub_uint8_t passwordSalt[32]; + grub_uint32_t keyMaterialOffset; + grub_uint32_t stripes; + } keyblock[8]; +} __attribute__ ((packed)); + +typedef struct grub_luks_phdr *grub_luks_phdr_t; + +gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, + grub_uint8_t * dst, grub_size_t blocksize, + grub_size_t blocknumbers); + +static grub_cryptodisk_t +configure_ciphers (grub_disk_t disk, const char *check_uuid, + int check_boot) +{ + grub_cryptodisk_t newdev; + const char *iptr; + struct grub_luks_phdr header; + char *optr; + char uuid[sizeof (header.uuid) + 1]; + char ciphername[sizeof (header.cipherName) + 1]; + char ciphermode[sizeof (header.cipherMode) + 1]; + char *cipheriv = NULL; + char hashspec[sizeof (header.hashSpec) + 1]; + grub_crypto_cipher_handle_t cipher = NULL, secondary_cipher = NULL; + grub_crypto_cipher_handle_t essiv_cipher = NULL; + const gcry_md_spec_t *hash = NULL, *essiv_hash = NULL; + const struct gcry_cipher_spec *ciph; + grub_cryptodisk_mode_t mode; + grub_cryptodisk_mode_iv_t mode_iv; + int benbi_log = 0; + grub_err_t err; + + if (check_boot) + return NULL; + + /* Read the LUKS header. */ + err = grub_disk_read (disk, 0, 0, sizeof (header), &header); + if (err) + { + if (err == GRUB_ERR_OUT_OF_RANGE) + grub_errno = GRUB_ERR_NONE; + return NULL; + } + + /* Look for LUKS magic sequence. */ + if (grub_memcmp (header.magic, LUKS_MAGIC, sizeof (header.magic)) + || grub_be_to_cpu16 (header.version) != 1) + return NULL; + + optr = uuid; + for (iptr = header.uuid; iptr < &header.uuid[ARRAY_SIZE (header.uuid)]; + iptr++) + { + if (*iptr != '-') + *optr++ = *iptr; + } + *optr = 0; + + if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) + { + grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid); + return NULL; + } + + /* Make sure that strings are null terminated. */ + grub_memcpy (ciphername, header.cipherName, sizeof (header.cipherName)); + ciphername[sizeof (header.cipherName)] = 0; + grub_memcpy (ciphermode, header.cipherMode, sizeof (header.cipherMode)); + ciphermode[sizeof (header.cipherMode)] = 0; + grub_memcpy (hashspec, header.hashSpec, sizeof (header.hashSpec)); + hashspec[sizeof (header.hashSpec)] = 0; + + ciph = grub_crypto_lookup_cipher_by_name (ciphername); + if (!ciph) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available", + ciphername); + return NULL; + } + + /* Configure the cipher used for the bulk data. */ + cipher = grub_crypto_cipher_open (ciph); + if (!cipher) + return NULL; + + if (grub_be_to_cpu32 (header.keyBytes) > 1024) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d", + grub_be_to_cpu32 (header.keyBytes)); + return NULL; + } + + /* Configure the cipher mode. */ + if (grub_strcmp (ciphermode, "ecb") == 0) + { + mode = GRUB_CRYPTODISK_MODE_ECB; + mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN; + cipheriv = NULL; + } + else if (grub_strcmp (ciphermode, "plain") == 0) + { + mode = GRUB_CRYPTODISK_MODE_CBC; + mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN; + cipheriv = NULL; + } + else if (grub_memcmp (ciphermode, "cbc-", sizeof ("cbc-") - 1) == 0) + { + mode = GRUB_CRYPTODISK_MODE_CBC; + cipheriv = ciphermode + sizeof ("cbc-") - 1; + } + else if (grub_memcmp (ciphermode, "pcbc-", sizeof ("pcbc-") - 1) == 0) + { + mode = GRUB_CRYPTODISK_MODE_PCBC; + cipheriv = ciphermode + sizeof ("pcbc-") - 1; + } + else if (grub_memcmp (ciphermode, "xts-", sizeof ("xts-") - 1) == 0) + { + mode = GRUB_CRYPTODISK_MODE_XTS; + cipheriv = ciphermode + sizeof ("xts-") - 1; + secondary_cipher = grub_crypto_cipher_open (ciph); + if (!secondary_cipher) + { + grub_crypto_cipher_close (cipher); + return NULL; + } + if (cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES) + { + grub_crypto_cipher_close (cipher); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported XTS block size: %d", + cipher->cipher->blocksize); + return NULL; + } + if (secondary_cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES) + { + grub_crypto_cipher_close (cipher); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported XTS block size: %d", + secondary_cipher->cipher->blocksize); + return NULL; + } + } + else if (grub_memcmp (ciphermode, "lrw-", sizeof ("lrw-") - 1) == 0) + { + mode = GRUB_CRYPTODISK_MODE_LRW; + cipheriv = ciphermode + sizeof ("lrw-") - 1; + if (cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES) + { + grub_crypto_cipher_close (cipher); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported LRW block size: %d", + cipher->cipher->blocksize); + return NULL; + } + } + else + { + grub_crypto_cipher_close (cipher); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown cipher mode: %s", + ciphermode); + return NULL; + } + + if (cipheriv == NULL); + else if (grub_memcmp (cipheriv, "plain", sizeof ("plain") - 1) == 0) + mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN; + else if (grub_memcmp (cipheriv, "plain64", sizeof ("plain64") - 1) == 0) + mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN64; + else if (grub_memcmp (cipheriv, "benbi", sizeof ("benbi") - 1) == 0) + { + if (cipher->cipher->blocksize & (cipher->cipher->blocksize - 1) + || cipher->cipher->blocksize == 0) + grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported benbi blocksize: %d", + cipher->cipher->blocksize); + for (benbi_log = 0; + (cipher->cipher->blocksize << benbi_log) < GRUB_DISK_SECTOR_SIZE; + benbi_log++); + mode_iv = GRUB_CRYPTODISK_MODE_IV_BENBI; + } + else if (grub_memcmp (cipheriv, "null", sizeof ("null") - 1) == 0) + mode_iv = GRUB_CRYPTODISK_MODE_IV_NULL; + else if (grub_memcmp (cipheriv, "essiv:", sizeof ("essiv:") - 1) == 0) + { + char *hash_str = cipheriv + 6; + + mode_iv = GRUB_CRYPTODISK_MODE_IV_ESSIV; + + /* Configure the hash and cipher used for ESSIV. */ + essiv_hash = grub_crypto_lookup_md_by_name (hash_str); + if (!essiv_hash) + { + grub_crypto_cipher_close (cipher); + grub_error (GRUB_ERR_FILE_NOT_FOUND, + "Couldn't load %s hash", hash_str); + return NULL; + } + essiv_cipher = grub_crypto_cipher_open (ciph); + if (!essiv_cipher) + { + grub_crypto_cipher_close (cipher); + return NULL; + } + } + else + { + grub_crypto_cipher_close (cipher); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown IV mode: %s", + cipheriv); + return NULL; + } + + /* Configure the hash used for the AF splitter and HMAC. */ + hash = grub_crypto_lookup_md_by_name (hashspec); + if (!hash) + { + grub_crypto_cipher_close (cipher); + grub_crypto_cipher_close (essiv_cipher); + grub_crypto_cipher_close (secondary_cipher); + grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load %s hash", + hashspec); + return NULL; + } + + newdev = grub_zalloc (sizeof (struct grub_cryptodisk)); + if (!newdev) + return NULL; + newdev->cipher = cipher; + newdev->offset = grub_be_to_cpu32 (header.payloadOffset); + newdev->source_disk = NULL; + newdev->benbi_log = benbi_log; + newdev->mode = mode; + newdev->mode_iv = mode_iv; + newdev->secondary_cipher = secondary_cipher; + newdev->essiv_cipher = essiv_cipher; + newdev->essiv_hash = essiv_hash; + newdev->hash = hash; + newdev->log_sector_size = 9; + newdev->total_length = grub_disk_get_size (disk) - newdev->offset; + grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid)); +#ifdef GRUB_UTIL + newdev->modname = "luks"; +#endif + COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= sizeof (uuid)); + return newdev; +} + +static grub_err_t +luks_recover_key (grub_disk_t source, + grub_cryptodisk_t dev) +{ + struct grub_luks_phdr header; + grub_size_t keysize; + grub_uint8_t *split_key = NULL; + char passphrase[MAX_PASSPHRASE] = ""; + grub_uint8_t candidate_digest[sizeof (header.mkDigest)]; + unsigned i; + grub_size_t length; + grub_err_t err; + grub_size_t max_stripes = 1; + char *tmp; + + err = grub_disk_read (source, 0, 0, sizeof (header), &header); + if (err) + return err; + + grub_puts_ (N_("Attempting to decrypt master key...")); + keysize = grub_be_to_cpu32 (header.keyBytes); + + for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) + if (grub_be_to_cpu32 (header.keyblock[i].active) == LUKS_KEY_ENABLED + && grub_be_to_cpu32 (header.keyblock[i].stripes) > max_stripes) + max_stripes = grub_be_to_cpu32 (header.keyblock[i].stripes); + + split_key = grub_malloc (keysize * max_stripes); + if (!split_key) + return grub_errno; + + /* Get the passphrase from the user. */ + tmp = NULL; + if (source->partition) + tmp = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition ? "," : "", tmp ? : "", + dev->uuid); + grub_free (tmp); + if (!grub_password_get (passphrase, MAX_PASSPHRASE)) + { + grub_free (split_key); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); + } + + /* Try to recover master key from each active keyslot. */ + for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) + { + gcry_err_code_t gcry_err; + grub_uint8_t candidate_key[keysize]; + grub_uint8_t digest[keysize]; + + /* Check if keyslot is enabled. */ + if (grub_be_to_cpu32 (header.keyblock[i].active) != LUKS_KEY_ENABLED) + continue; + + grub_dprintf ("luks", "Trying keyslot %d\n", i); + + /* Calculate the PBKDF2 of the user supplied passphrase. */ + gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, + grub_strlen (passphrase), + header.keyblock[i].passwordSalt, + sizeof (header.keyblock[i].passwordSalt), + grub_be_to_cpu32 (header.keyblock[i]. + passwordIterations), + digest, keysize); + + if (gcry_err) + { + grub_free (split_key); + return grub_crypto_gcry_error (gcry_err); + } + + grub_dprintf ("luks", "PBKDF2 done\n"); + + gcry_err = grub_cryptodisk_setkey (dev, digest, keysize); + if (gcry_err) + { + grub_free (split_key); + return grub_crypto_gcry_error (gcry_err); + } + + length = (keysize * grub_be_to_cpu32 (header.keyblock[i].stripes)); + + /* Read and decrypt the key material from the disk. */ + err = grub_disk_read (source, + grub_be_to_cpu32 (header.keyblock + [i].keyMaterialOffset), 0, + length, split_key); + if (err) + { + grub_free (split_key); + return err; + } + + gcry_err = grub_cryptodisk_decrypt (dev, split_key, length, 0); + if (gcry_err) + { + grub_free (split_key); + return grub_crypto_gcry_error (gcry_err); + } + + /* Merge the decrypted key material to get the candidate master key. */ + gcry_err = AF_merge (dev->hash, split_key, candidate_key, keysize, + grub_be_to_cpu32 (header.keyblock[i].stripes)); + if (gcry_err) + { + grub_free (split_key); + return grub_crypto_gcry_error (gcry_err); + } + + grub_dprintf ("luks", "candidate key recovered\n"); + + /* Calculate the PBKDF2 of the candidate master key. */ + gcry_err = grub_crypto_pbkdf2 (dev->hash, candidate_key, + grub_be_to_cpu32 (header.keyBytes), + header.mkDigestSalt, + sizeof (header.mkDigestSalt), + grub_be_to_cpu32 + (header.mkDigestIterations), + candidate_digest, + sizeof (candidate_digest)); + if (gcry_err) + { + grub_free (split_key); + return grub_crypto_gcry_error (gcry_err); + } + + /* Compare the calculated PBKDF2 to the digest stored + in the header to see if it's correct. */ + if (grub_memcmp (candidate_digest, header.mkDigest, + sizeof (header.mkDigest)) != 0) + { + grub_dprintf ("luks", "bad digest\n"); + continue; + } + + grub_printf_ (N_("Slot %d opened\n"), i); + + /* Set the master key. */ + gcry_err = grub_cryptodisk_setkey (dev, candidate_key, keysize); + if (gcry_err) + { + grub_free (split_key); + return grub_crypto_gcry_error (gcry_err); + } + + grub_free (split_key); + + return GRUB_ERR_NONE; + } + + return GRUB_ACCESS_DENIED; +} + +struct grub_cryptodisk_dev luks_crypto = { + .scan = configure_ciphers, + .recover_key = luks_recover_key +}; + +GRUB_MOD_INIT (luks) +{ + COMPILE_TIME_ASSERT (sizeof (((struct grub_luks_phdr *) 0)->uuid) + < GRUB_CRYPTODISK_MAX_UUID_LENGTH); + grub_cryptodisk_dev_register (&luks_crypto); +} + +GRUB_MOD_FINI (luks) +{ + grub_cryptodisk_dev_unregister (&luks_crypto); +} diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c index 94cf9a1aa..d7be3e8a5 100644 --- a/grub-core/disk/lvm.c +++ b/grub-core/disk/lvm.c @@ -1,7 +1,7 @@ /* lvm.c - module to read Logical Volumes. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009,2011 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 @@ -23,28 +23,31 @@ #include #include #include +#include +#include #ifdef GRUB_UTIL #include +#include #endif -static struct grub_lvm_vg *vg_list; -static int lv_count; +GRUB_MOD_LICENSE ("GPLv3+"); /* Go the string STR and return the number after STR. *P will point at the number. In case STR is not found, *P will be NULL and the return value will be 0. */ static int -grub_lvm_getvalue (char **p, char *str) +grub_lvm_getvalue (char **p, const char *str) { *p = grub_strstr (*p, str); if (! *p) return 0; *p += grub_strlen (str); - return grub_strtoul (*p, NULL, 10); + return grub_strtoul (*p, p, 10); } +#if 0 static int grub_lvm_checkvalue (char **p, char *str, char *tmpl) { @@ -57,9 +60,10 @@ grub_lvm_checkvalue (char **p, char *str, char *tmpl) return 0; return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"'); } +#endif static int -grub_lvm_check_flag (char *p, char *str, char *flag) +grub_lvm_check_flag (char *p, const char *str, const char *flag) { int len_str = grub_strlen (str), len_flag = grub_strlen (flag); while (1) @@ -91,175 +95,13 @@ grub_lvm_check_flag (char *p, char *str, char *flag) } } -static int -grub_lvm_iterate (int (*hook) (const char *name)) -{ - struct grub_lvm_vg *vg; - for (vg = vg_list; vg; vg = vg->next) - { - struct grub_lvm_lv *lv; - if (vg->lvs) - for (lv = vg->lvs; lv; lv = lv->next) - if (hook (lv->name)) - return 1; - } - - return 0; -} - -#ifdef GRUB_UTIL -static grub_disk_memberlist_t -grub_lvm_memberlist (grub_disk_t disk) -{ - struct grub_lvm_lv *lv = disk->data; - grub_disk_memberlist_t list = NULL, tmp; - struct grub_lvm_pv *pv; - - if (lv->vg->pvs) - for (pv = lv->vg->pvs; pv; pv = pv->next) - { - if (!pv->disk) - grub_util_error ("Couldn't find PV %s. Check your device.map", - pv->name); - tmp = grub_malloc (sizeof (*tmp)); - tmp->disk = pv->disk; - tmp->next = list; - list = tmp; - } - - return list; -} -#endif - -static grub_err_t -grub_lvm_open (const char *name, grub_disk_t disk) -{ - struct grub_lvm_vg *vg; - struct grub_lvm_lv *lv = NULL; - for (vg = vg_list; vg; vg = vg->next) - { - if (vg->lvs) - for (lv = vg->lvs; lv; lv = lv->next) - if (! grub_strcmp (lv->name, name)) - break; - - if (lv) - break; - } - - if (! lv) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name); - - disk->id = lv->number; - disk->data = lv; - disk->total_sectors = lv->size; - - return 0; -} - -static void -grub_lvm_close (grub_disk_t disk __attribute ((unused))) -{ - return; -} - -static grub_err_t -grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) -{ - grub_err_t err = 0; - struct grub_lvm_lv *lv = disk->data; - struct grub_lvm_vg *vg = lv->vg; - struct grub_lvm_segment *seg = lv->segments; - struct grub_lvm_pv *pv; - grub_uint64_t offset; - grub_uint64_t extent; - unsigned int i; - - extent = grub_divmod64 (sector, vg->extent_size, NULL); - - /* Find the right segment. */ - for (i = 0; i < lv->segment_count; i++) - { - if ((seg->start_extent <= extent) - && ((seg->start_extent + seg->extent_count) > extent)) - { - break; - } - - seg++; - } - - if (seg->stripe_count == 1) - { - /* This segment is linear, so that's easy. We just need to find - out the offset in the physical volume and read SIZE bytes - from that. */ - struct grub_lvm_stripe *stripe = seg->stripes; - grub_uint64_t seg_offset; /* Offset of the segment in PV device. */ - - pv = stripe->pv; - seg_offset = ((grub_uint64_t) stripe->start - * (grub_uint64_t) vg->extent_size) + pv->start; - - offset = sector - ((grub_uint64_t) seg->start_extent - * (grub_uint64_t) vg->extent_size) + seg_offset; - } - else - { - /* This is a striped segment. We have to find the right PV - similar to RAID0. */ - struct grub_lvm_stripe *stripe = seg->stripes; - grub_uint32_t a, b; - grub_uint64_t seg_offset; /* Offset of the segment in PV device. */ - unsigned int stripenr; - - offset = sector - ((grub_uint64_t) seg->start_extent - * (grub_uint64_t) vg->extent_size); - - a = grub_divmod64 (offset, seg->stripe_size, NULL); - grub_divmod64 (a, seg->stripe_count, &stripenr); - - a = grub_divmod64 (offset, seg->stripe_size * seg->stripe_count, NULL); - grub_divmod64 (offset, seg->stripe_size, &b); - offset = a * seg->stripe_size + b; - - stripe += stripenr; - pv = stripe->pv; - - seg_offset = ((grub_uint64_t) stripe->start - * (grub_uint64_t) vg->extent_size) + pv->start; - - offset += seg_offset; - } - - /* Check whether we actually know the physical volume we want to - read from. */ - if (pv->disk) - err = grub_disk_read (pv->disk, offset, 0, - size << GRUB_DISK_SECTOR_BITS, buf); - else - err = grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "physical volume %s not found", pv->name); - - return err; -} - -static grub_err_t -grub_lvm_write (grub_disk_t disk __attribute ((unused)), - grub_disk_addr_t sector __attribute ((unused)), - grub_size_t size __attribute ((unused)), - const char *buf __attribute ((unused))) -{ - return GRUB_ERR_NOT_IMPLEMENTED_YET; -} - -static int -grub_lvm_scan_device (const char *name) +static struct grub_diskfilter_vg * +grub_lvm_detect (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, + grub_disk_addr_t *start_sector) { grub_err_t err; - grub_disk_t disk; - grub_uint64_t da_offset, da_size, mda_offset, mda_size; + grub_uint64_t mda_offset, mda_size; char buf[GRUB_LVM_LABEL_SIZE]; char vg_id[GRUB_LVM_ID_STRLEN+1]; char pv_id[GRUB_LVM_ID_STRLEN+1]; @@ -270,20 +112,8 @@ grub_lvm_scan_device (const char *name) struct grub_lvm_mda_header *mdah; struct grub_lvm_raw_locn *rlocn; unsigned int i, j, vgname_len; - struct grub_lvm_vg *vg; - struct grub_lvm_pv *pv; - -#ifdef GRUB_UTIL - grub_util_info ("scanning %s for LVM", name); -#endif - - disk = grub_disk_open (name); - if (!disk) - { - if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_errno = GRUB_ERR_NONE; - return 0; - } + struct grub_diskfilter_vg *vg; + struct grub_diskfilter_pv *pv; /* Search for label. */ for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) @@ -303,7 +133,7 @@ grub_lvm_scan_device (const char *name) if (i == GRUB_LVM_LABEL_SCAN_SECTORS) { #ifdef GRUB_UTIL - grub_util_info ("no LVM signature found\n"); + grub_util_info ("no LVM signature found"); #endif goto fail; } @@ -319,8 +149,6 @@ grub_lvm_scan_device (const char *name) pv_id[j] = '\0'; dlocn = pvh->disk_areas_xl; - da_offset = grub_le_to_cpu64 (dlocn->offset); - da_size = grub_le_to_cpu64 (dlocn->size); dlocn++; /* Is it possible to have multiple data/metadata areas? I haven't @@ -371,10 +199,10 @@ grub_lvm_scan_device (const char *name) { /* Metadata is circular. Copy the wrap in place. */ grub_memcpy (metadatabuf + mda_size, - metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, - grub_le_to_cpu64 (rlocn->offset) + - grub_le_to_cpu64 (rlocn->size) - - grub_le_to_cpu64 (mdah->size)); + metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, + grub_le_to_cpu64 (rlocn->offset) + + grub_le_to_cpu64 (rlocn->size) - + grub_le_to_cpu64 (mdah->size)); } p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset); @@ -409,11 +237,7 @@ grub_lvm_scan_device (const char *name) grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN); vg_id[GRUB_LVM_ID_STRLEN] = '\0'; - for (vg = vg_list; vg; vg = vg->next) - { - if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN)) - break; - } + vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id); if (! vg) { @@ -423,7 +247,11 @@ grub_lvm_scan_device (const char *name) if (! vg) goto fail3; vg->name = vgname; - grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1); + vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN); + if (! vg->uuid) + goto fail3; + grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN); + vg->uuid_len = GRUB_LVM_ID_STRLEN; vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); if (p == NULL) @@ -452,7 +280,7 @@ grub_lvm_scan_device (const char *name) if (*p == '}') break; - pv = grub_malloc (sizeof (*pv)); + pv = grub_zalloc (sizeof (*pv)); q = p; while (*q != ' ') q++; @@ -467,10 +295,13 @@ grub_lvm_scan_device (const char *name) goto pvs_fail; p += sizeof("id = \"") - 1; - grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN); - pv->id[GRUB_LVM_ID_STRLEN] = '\0'; + pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN); + if (!pv->id.uuid) + goto pvs_fail; + grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN); + pv->id.uuidlen = GRUB_LVM_ID_STRLEN; - pv->start = grub_lvm_getvalue (&p, "pe_start = "); + pv->start_sector = grub_lvm_getvalue (&p, "pe_start = "); if (p == NULL) { #ifdef GRUB_UTIL @@ -504,15 +335,16 @@ grub_lvm_scan_device (const char *name) p = grub_strstr (p, "logical_volumes"); if (p) { - p += 18; + p += sizeof ("logical_volumes = ") - 1; /* And add all the lvs to the volume group. */ while (1) { int s; int skip_lv = 0; - struct grub_lvm_lv *lv; - struct grub_lvm_segment *seg; + struct grub_diskfilter_lv *lv; + struct grub_diskfilter_segment *seg; + int is_pvmove; while (grub_isspace (*p)) p++; @@ -520,26 +352,47 @@ grub_lvm_scan_device (const char *name) if (*p == '}') break; - lv = grub_malloc (sizeof (*lv)); + lv = grub_zalloc (sizeof (*lv)); q = p; while (*q != ' ') q++; s = q - p; - lv->name = grub_malloc (vgname_len + 1 + s + 1); - grub_memcpy (lv->name, vgname, vgname_len); - lv->name[vgname_len] = '-'; - grub_memcpy (lv->name + vgname_len + 1, p, s); - lv->name[vgname_len + 1 + s] = '\0'; + lv->name = grub_strndup (p, s); + if (!lv->name) + goto lvs_fail; + + { + const char *iptr; + char *optr; + lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len + + 1 + 2 * s + 1); + if (!lv->fullname) + goto lvs_fail; + + grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1); + optr = lv->fullname + sizeof ("lvm/") - 1; + for (iptr = vgname; iptr < vgname + vgname_len; iptr++) + { + *optr++ = *iptr; + if (*iptr == '-') + *optr++ = '-'; + } + *optr++ = '-'; + for (iptr = p; iptr < p + s; iptr++) + { + *optr++ = *iptr; + if (*iptr == '-') + *optr++ = '-'; + } + *optr++ = 0; + } lv->size = 0; - if (!grub_lvm_check_flag (p, "status", "VISIBLE")) - { - skip_lv = 1; - goto lv_parsed; - } + lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE"); + is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE"); lv->segment_count = grub_lvm_getvalue (&p, "segment_count = "); if (p == NULL) @@ -554,7 +407,6 @@ grub_lvm_scan_device (const char *name) for (i = 0; i < lv->segment_count; i++) { - struct grub_lvm_stripe *stripe; p = grub_strstr (p, "segment"); if (p == NULL) @@ -582,90 +434,238 @@ grub_lvm_scan_device (const char *name) goto lvs_segment_fail; } - if (grub_lvm_checkvalue (&p, "type = ", "snapshot")) - { - /* Found a snapshot, give up and move on. */ - skip_lv = 1; - break; - } - - seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = "); + p = grub_strstr (p, "type = \""); if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown stripe_count\n"); -#endif - goto lvs_segment_fail; - } + goto lvs_segment_fail; + p += sizeof("type = \"") - 1; lv->size += seg->extent_count * vg->extent_size; - if (seg->stripe_count != 1) - seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); + if (grub_memcmp (p, "striped\"", + sizeof ("striped\"") - 1) == 0) + { + struct grub_diskfilter_node *stripe; - seg->stripes = grub_malloc (sizeof (*stripe) - * seg->stripe_count); - stripe = seg->stripes; + seg->type = GRUB_DISKFILTER_STRIPED; + seg->node_count = grub_lvm_getvalue (&p, "stripe_count = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown stripe_count\n"); +#endif + goto lvs_segment_fail; + } - p = grub_strstr (p, "stripes = ["); - if (p == NULL) + if (seg->node_count != 1) + seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); + + seg->nodes = grub_zalloc (sizeof (*stripe) + * seg->node_count); + stripe = seg->nodes; + + p = grub_strstr (p, "stripes = ["); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown stripes\n"); +#endif + goto lvs_segment_fail2; + } + p += sizeof("stripes = [") - 1; + + for (j = 0; j < seg->node_count; j++) + { + p = grub_strchr (p, '"'); + if (p == NULL) + continue; + q = ++p; + while (*q != '"') + q++; + + s = q - p; + + stripe->name = grub_malloc (s + 1); + if (stripe->name == NULL) + goto lvs_segment_fail2; + + grub_memcpy (stripe->name, p, s); + stripe->name[s] = '\0'; + + p = q + 1; + + stripe->start = grub_lvm_getvalue (&p, ",") + * vg->extent_size; + if (p == NULL) + continue; + + stripe++; + } + } + else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1) + == 0) + { + seg->type = GRUB_DISKFILTER_MIRROR; + seg->node_count = grub_lvm_getvalue (&p, "mirror_count = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown mirror_count\n"); +#endif + goto lvs_segment_fail; + } + + seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) + * seg->node_count); + + p = grub_strstr (p, "mirrors = ["); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown mirrors\n"); +#endif + goto lvs_segment_fail2; + } + p += sizeof("mirrors = [") - 1; + + for (j = 0; j < seg->node_count; j++) + { + char *lvname; + + p = grub_strchr (p, '"'); + if (p == NULL) + continue; + q = ++p; + while (*q != '"') + q++; + + s = q - p; + + lvname = grub_malloc (s + 1); + if (lvname == NULL) + goto lvs_segment_fail2; + + grub_memcpy (lvname, p, s); + lvname[s] = '\0'; + seg->nodes[j].name = lvname; + p = q + 1; + } + /* Only first (original) is ok with in progress pvmove. */ + if (is_pvmove) + seg->node_count = 1; + } + else if (grub_memcmp (p, "raid", sizeof ("raid") - 1) + == 0 && (p[sizeof ("raid") - 1] >= '4' + && p[sizeof ("raid") - 1] <= '6') + && p[sizeof ("raidX") - 1] == '"') + { + switch (p[sizeof ("raid") - 1]) + { + case '4': + seg->type = GRUB_DISKFILTER_RAID4; + seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC; + break; + case '5': + seg->type = GRUB_DISKFILTER_RAID5; + seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC; + break; + case '6': + seg->type = GRUB_DISKFILTER_RAID6; + seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC + | GRUB_RAID_LAYOUT_MUL_FROM_POS); + break; + } + seg->node_count = grub_lvm_getvalue (&p, "device_count = "); + + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown device_count\n"); +#endif + goto lvs_segment_fail; + } + + seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown stripe_size\n"); +#endif + goto lvs_segment_fail; + } + + + seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) + * seg->node_count); + + p = grub_strstr (p, "raids = ["); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown mirrors\n"); +#endif + goto lvs_segment_fail2; + } + p += sizeof("raids = [") - 1; + + for (j = 0; j < seg->node_count; j++) + { + char *lvname; + + p = grub_strchr (p, '"'); + p = p ? grub_strchr (p + 1, '"') : 0; + p = p ? grub_strchr (p + 1, '"') : 0; + if (p == NULL) + continue; + q = ++p; + while (*q != '"') + q++; + + s = q - p; + + lvname = grub_malloc (s + 1); + if (lvname == NULL) + goto lvs_segment_fail2; + + grub_memcpy (lvname, p, s); + lvname[s] = '\0'; + seg->nodes[j].name = lvname; + p = q + 1; + } + if (seg->type == GRUB_DISKFILTER_RAID4) + { + char *tmp; + tmp = seg->nodes[0].name; + grub_memmove (seg->nodes, seg->nodes + 1, + sizeof (seg->nodes[0]) + * (seg->node_count - 1)); + seg->nodes[seg->node_count - 1].name = tmp; + } + } + else { #ifdef GRUB_UTIL - grub_util_info ("unknown stripes\n"); + char *p2; + p2 = grub_strchr (p, '"'); + if (p2) + *p2 = 0; + grub_util_info ("unknown LVM type %s\n", p); + if (p2) + *p2 ='"'; #endif - goto lvs_segment_fail2; - } - p += sizeof("stripes = [") - 1; - - for (j = 0; j < seg->stripe_count; j++) - { - char *pvname; - - p = grub_strchr (p, '"'); - if (p == NULL) - continue; - q = ++p; - while (*q != '"') - q++; - - s = q - p; - - pvname = grub_malloc (s + 1); - if (pvname == NULL) - goto lvs_segment_fail2; - - grub_memcpy (pvname, p, s); - pvname[s] = '\0'; - - if (vg->pvs) - for (pv = vg->pvs; pv; pv = pv->next) - { - if (! grub_strcmp (pvname, pv->name)) - { - stripe->pv = pv; - break; - } - } - - grub_free(pvname); - - stripe->start = grub_lvm_getvalue (&p, ","); - if (p == NULL) - continue; - - stripe++; + /* Found a non-supported type, give up and move on. */ + skip_lv = 1; + break; } seg++; continue; lvs_segment_fail2: - grub_free (seg->stripes); + grub_free (seg->nodes); lvs_segment_fail: goto fail4; } - lv_parsed: if (p != NULL) p = grub_strchr (p, '}'); if (p == NULL) @@ -679,7 +679,6 @@ grub_lvm_scan_device (const char *name) continue; } - lv->number = lv_count++; lv->vg = vg; lv->next = vg->lvs; vg->lvs = lv; @@ -692,30 +691,48 @@ grub_lvm_scan_device (const char *name) } } - vg->next = vg_list; - vg_list = vg; + /* Match lvs. */ + { + struct grub_diskfilter_lv *lv1; + struct grub_diskfilter_lv *lv2; + for (lv1 = vg->lvs; lv1; lv1 = lv1->next) + for (i = 0; i < lv1->segment_count; i++) + for (j = 0; j < lv1->segments[i].node_count; j++) + { + if (vg->pvs) + for (pv = vg->pvs; pv; pv = pv->next) + { + if (! grub_strcmp (pv->name, + lv1->segments[i].nodes[j].name)) + { + lv1->segments[i].nodes[j].pv = pv; + break; + } + } + if (lv1->segments[i].nodes[j].pv == NULL) + for (lv2 = vg->lvs; lv2; lv2 = lv2->next) + if (grub_strcmp (lv2->name, + lv1->segments[i].nodes[j].name) == 0) + lv1->segments[i].nodes[j].lv = lv2; + } + + } + if (grub_diskfilter_vg_register (vg)) + goto fail4; } else { grub_free (vgname); } - /* Match the device we are currently reading from with the right - PV. */ - if (vg->pvs) - for (pv = vg->pvs; pv; pv = pv->next) - { - if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN)) - { - /* This could happen to LVM on RAID, pv->disk points to the - raid device, we shouldn't change it. */ - if (! pv->disk) - pv->disk = grub_disk_open (name); - break; - } - } - - goto fail2; + id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN); + if (!id->uuid) + goto fail4; + grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN); + id->uuidlen = GRUB_LVM_ID_STRLEN; + grub_free (metadatabuf); + *start_sector = -1; + return vg; /* Failure path. */ fail4: @@ -723,46 +740,26 @@ grub_lvm_scan_device (const char *name) fail3: grub_free (vgname); - /* Normal exit path. */ fail2: grub_free (metadatabuf); fail: - grub_disk_close (disk); - if (grub_errno == GRUB_ERR_OUT_OF_RANGE) - grub_errno = GRUB_ERR_NONE; - return 0; + return NULL; } -static struct grub_disk_dev grub_lvm_dev = - { - .name = "lvm", - .id = GRUB_DISK_DEVICE_LVM_ID, - .iterate = grub_lvm_iterate, - .open = grub_lvm_open, - .close = grub_lvm_close, - .read = grub_lvm_read, - .write = grub_lvm_write, -#ifdef GRUB_UTIL - .memberlist = grub_lvm_memberlist, -#endif - .next = 0 - }; - -GRUB_MOD_INIT(lvm) -{ - grub_device_iterate (&grub_lvm_scan_device); - if (grub_errno) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - } - grub_disk_dev_register (&grub_lvm_dev); +static struct grub_diskfilter grub_lvm_dev = { + .name = "lvm", + .detect = grub_lvm_detect, + .next = 0 +}; + +GRUB_MOD_INIT (lvm) +{ + grub_diskfilter_register (&grub_lvm_dev); } -GRUB_MOD_FINI(lvm) +GRUB_MOD_FINI (lvm) { - grub_disk_dev_unregister (&grub_lvm_dev); - /* FIXME: free the lvm list. */ + grub_diskfilter_unregister (&grub_lvm_dev); } diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c index 4a0298347..fa4b97b77 100644 --- a/grub-core/disk/mdraid1x_linux.c +++ b/grub-core/disk/mdraid1x_linux.c @@ -22,7 +22,9 @@ #include #include #include -#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* Linux RAID on disk structures and constants, copied from include/linux/raid/md_p.h. */ @@ -101,16 +103,16 @@ struct grub_raid_super_1x #define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */ -static grub_err_t -grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, +static struct grub_diskfilter_vg * +grub_mdraid_detect (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, grub_disk_addr_t *start_sector) { - grub_disk_addr_t sector; + grub_disk_addr_t sector = 0; grub_uint64_t size; struct grub_raid_super_1x sb; grub_uint8_t minor_version; - /* The sector where the mdraid 0.90 superblock is stored, if available. */ size = grub_disk_get_size (disk); /* Check for an 1.x superblock. @@ -123,6 +125,9 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, for (minor_version = 0; minor_version < 3; ++minor_version) { + if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0) + continue; + switch (minor_version) { case 0: @@ -138,28 +143,38 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), &sb)) - return grub_errno; + return NULL; - if (sb.magic != SB_MAGIC) + if (grub_le_to_cpu32 (sb.magic) != SB_MAGIC + || grub_le_to_cpu64 (sb.super_offset) != sector) continue; { grub_uint64_t sb_size; struct grub_raid_super_1x *real_sb; + grub_uint32_t level; - if (sb.major_version != 1) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID version: %d", - sb.major_version); + if (grub_le_to_cpu32 (sb.major_version) != 1) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID version: %d", + grub_le_to_cpu32 (sb.major_version)); + return NULL; + } + + level = grub_le_to_cpu32 (sb.level); /* Multipath. */ - if ((int) sb.level == -4) - sb.level = 1; + if ((int) level == -4) + level = 1; - if (sb.level != 0 && sb.level != 1 && sb.level != 4 && - sb.level != 5 && sb.level != 6 && sb.level != 10) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "Unsupported RAID level: %d", sb.level); + if (level != 0 && level != 1 && level != 4 && + level != 5 && level != 6 && level != 10) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID level: %d", sb.level); + return NULL; + } /* 1.x superblocks don't have a fixed size on disk. So we have to read it again now that we now the max device count. */ @@ -167,54 +182,68 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, + 2 * grub_le_to_cpu32 (sb.max_dev); real_sb = grub_malloc (sb_size); if (! real_sb) - return grub_errno; + return NULL; if (grub_disk_read (disk, sector, 0, sb_size, real_sb)) { grub_free (real_sb); - return grub_errno; + return NULL; } - array->name = grub_strdup (real_sb->set_name); - if (! array->name) - { - grub_free (real_sb); - return grub_errno; - } + struct grub_diskfilter_vg *array; + char *uuid; - array->number = 0; - array->level = grub_le_to_cpu32 (real_sb->level); - array->layout = grub_le_to_cpu32 (real_sb->layout); - array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks); - array->disk_size = grub_le_to_cpu64 (real_sb->size); - array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize); - if (grub_le_to_cpu32 (real_sb->dev_number) < + if (grub_le_to_cpu32 (real_sb->dev_number) >= grub_le_to_cpu32 (real_sb->max_dev)) - array->index = grub_le_to_cpu16 - (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); - else - array->index = 0xffff; /* disk will be later not used! */ - array->uuid_len = 16; - array->uuid = grub_malloc (16); - if (!array->uuid) { - grub_free (real_sb); - return grub_errno; + grub_error (GRUB_ERR_OUT_OF_RANGE, + "spares aren't implemented"); + return NULL; } - grub_memcpy (array->uuid, real_sb->set_uuid, 16); - - *start_sector = real_sb->data_offset; + id->uuidlen = 0; + id->id = grub_le_to_cpu16 + (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); + + uuid = grub_malloc (16); + if (!uuid) + { + grub_free (real_sb); + return NULL; + } + + grub_memcpy (uuid, real_sb->set_uuid, 16); + + *start_sector = grub_le_to_cpu64 (real_sb->data_offset); + + if (grub_le_to_cpu32 (real_sb->dev_number) + >= grub_le_to_cpu32 (real_sb->raid_disks)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + "spares aren't implemented"); + return NULL; + } + + array = grub_diskfilter_make_raid (16, uuid, + grub_le_to_cpu32 (real_sb->raid_disks), + real_sb->set_name, + (real_sb->size) + ? grub_le_to_cpu64 (real_sb->size) + : grub_le_to_cpu64 (real_sb->data_size), + grub_le_to_cpu32 (real_sb->chunksize), + grub_le_to_cpu32 (real_sb->layout), + grub_le_to_cpu32 (real_sb->level)); grub_free (real_sb); - return 0; + return array; } } - return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid"); + grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid"); + return NULL; } -static struct grub_raid grub_mdraid_dev = { +static struct grub_diskfilter grub_mdraid_dev = { .name = "mdraid1x", .detect = grub_mdraid_detect, .next = 0 @@ -222,10 +251,10 @@ static struct grub_raid grub_mdraid_dev = { GRUB_MOD_INIT (mdraid1x) { - grub_raid_register (&grub_mdraid_dev); + grub_diskfilter_register (&grub_mdraid_dev); } GRUB_MOD_FINI (mdraid1x) { - grub_raid_unregister (&grub_mdraid_dev); + grub_diskfilter_unregister (&grub_mdraid_dev); } diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.c index 549d48355..1ca76fdfa 100644 --- a/grub-core/disk/mdraid_linux.c +++ b/grub-core/disk/mdraid_linux.c @@ -22,11 +22,13 @@ #include #include #include -#include +#include /* Linux RAID on disk structures and constants, copied from include/linux/raid/md_p.h. */ +GRUB_MOD_LICENSE ("GPLv3+"); + #define RESERVED_BYTES (64 * 1024) #define RESERVED_SECTORS (RESERVED_BYTES / 512) @@ -159,67 +161,94 @@ struct grub_raid_super_09 struct grub_raid_disk_09 this_disk; } __attribute__ ((packed)); -static grub_err_t -grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, +static struct grub_diskfilter_vg * +grub_mdraid_detect (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, grub_disk_addr_t *start_sector) { grub_disk_addr_t sector; grub_uint64_t size; struct grub_raid_super_09 sb; grub_uint32_t *uuid; + grub_uint32_t level; /* The sector where the mdraid 0.90 superblock is stored, if available. */ size = grub_disk_get_size (disk); + if (size == GRUB_DISK_SIZE_UNKNOWN) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid"); + return NULL; + } sector = NEW_SIZE_SECTORS (size); if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb)) - return grub_errno; + return NULL; /* Look whether there is a mdraid 0.90 superblock. */ - if (sb.md_magic != SB_MAGIC) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid"); + if (grub_le_to_cpu32 (sb.md_magic) != SB_MAGIC) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid"); + return NULL; + } - if (sb.major_version != 0 || sb.minor_version != 90) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID version: %d.%d", - sb.major_version, sb.minor_version); + if (grub_le_to_cpu32 (sb.major_version) != 0 + || grub_le_to_cpu32 (sb.minor_version) != 90) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID version: %d.%d", + grub_le_to_cpu32 (sb.major_version), + grub_le_to_cpu32 (sb.minor_version)); + return NULL; + } /* FIXME: Check the checksum. */ + level = grub_le_to_cpu32 (sb.level); /* Multipath. */ - if ((int) sb.level == -4) - sb.level = 1; + if ((int) level == -4) + level = 1; - if (sb.level != 0 && sb.level != 1 && sb.level != 4 && - sb.level != 5 && sb.level != 6 && sb.level != 10) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID level: %d", sb.level); + if (level != 0 && level != 1 && level != 4 && + level != 5 && level != 6 && level != 10) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID level: %d", level); + return NULL; + } + if (grub_le_to_cpu32 (sb.this_disk.number) == 0xffff + || grub_le_to_cpu32 (sb.this_disk.number) == 0xfffe) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + "spares aren't implemented"); + return NULL; + } - array->name = NULL; - array->number = sb.md_minor; - array->level = sb.level; - array->layout = sb.layout; - array->total_devs = sb.raid_disks; - array->disk_size = (sb.size) ? sb.size * 2 : sector; - array->chunk_size = sb.chunk_size >> 9; - array->index = sb.this_disk.number; - array->uuid_len = 16; - array->uuid = grub_malloc (16); - if (!array->uuid) - return grub_errno; + uuid = grub_malloc (16); + if (!uuid) + return NULL; - uuid = (grub_uint32_t *) array->uuid; - uuid[0] = sb.set_uuid0; - uuid[1] = sb.set_uuid1; - uuid[2] = sb.set_uuid2; - uuid[3] = sb.set_uuid3; + uuid[0] = grub_swap_bytes32 (sb.set_uuid0); + uuid[1] = grub_swap_bytes32 (sb.set_uuid1); + uuid[2] = grub_swap_bytes32 (sb.set_uuid2); + uuid[3] = grub_swap_bytes32 (sb.set_uuid3); *start_sector = 0; - return 0; + id->uuidlen = 0; + id->id = grub_le_to_cpu32 (sb.this_disk.number); + + char buf[32]; + grub_snprintf (buf, sizeof (buf), "md%d", grub_le_to_cpu32 (sb.md_minor)); + return grub_diskfilter_make_raid (16, (char *) uuid, + grub_le_to_cpu32 (sb.raid_disks), buf, + (sb.size) ? grub_le_to_cpu32 (sb.size) * 2 + : sector, + grub_le_to_cpu32 (sb.chunk_size) >> 9, + grub_le_to_cpu32 (sb.layout), + level); } -static struct grub_raid grub_mdraid_dev = { +static struct grub_diskfilter grub_mdraid_dev = { .name = "mdraid09", .detect = grub_mdraid_detect, .next = 0 @@ -227,10 +256,10 @@ static struct grub_raid grub_mdraid_dev = { GRUB_MOD_INIT (mdraid09) { - grub_raid_register (&grub_mdraid_dev); + grub_diskfilter_register (&grub_mdraid_dev); } GRUB_MOD_FINI (mdraid09) { - grub_raid_unregister (&grub_mdraid_dev); + grub_diskfilter_unregister (&grub_mdraid_dev); } diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c index e00280dd7..4de0971ae 100644 --- a/grub-core/disk/memdisk.c +++ b/grub-core/disk/memdisk.c @@ -24,12 +24,18 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static char *memdisk_addr; static grub_off_t memdisk_size = 0; static int -grub_memdisk_iterate (int (*hook) (const char *name)) +grub_memdisk_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { + if (pull != GRUB_DISK_PULL_NONE) + return 0; + return hook ("memdisk"); } @@ -80,30 +86,24 @@ static struct grub_disk_dev grub_memdisk_dev = GRUB_MOD_INIT(memdisk) { - auto int hook (struct grub_module_header *); - int hook (struct grub_module_header *header) - { - if (header->type == OBJ_TYPE_MEMDISK) - { - char *memdisk_orig_addr; - memdisk_orig_addr = (char *) header + sizeof (struct grub_module_header); + struct grub_module_header *header; + FOR_MODULES (header) + if (header->type == OBJ_TYPE_MEMDISK) + { + char *memdisk_orig_addr; + memdisk_orig_addr = (char *) header + sizeof (struct grub_module_header); - grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr); + grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr); - memdisk_size = header->size - sizeof (struct grub_module_header); - memdisk_addr = grub_malloc (memdisk_size); + memdisk_size = header->size - sizeof (struct grub_module_header); + memdisk_addr = grub_malloc (memdisk_size); - grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n"); - grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size); + grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n"); + grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size); - grub_disk_dev_register (&grub_memdisk_dev); - return 1; - } - - return 0; - } - - grub_module_iterate (hook); + grub_disk_dev_register (&grub_memdisk_dev); + break; + } } GRUB_MOD_FINI(memdisk) diff --git a/grub-core/disk/pata.c b/grub-core/disk/pata.c new file mode 100644 index 000000000..089059d10 --- /dev/null +++ b/grub-core/disk/pata.c @@ -0,0 +1,539 @@ +/* ata_pthru.c - ATA pass through for ata.mod. */ +/* + * 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 +#include +#include +#include +#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS +#include +#include +#else +#define GRUB_MACHINE_PCI_IO_BASE 0xb4000000 +#endif +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* At the moment, only two IDE ports are supported. */ +static const grub_port_t grub_pata_ioaddress[] = { GRUB_ATA_CH0_PORT1, + GRUB_ATA_CH1_PORT1 }; + +struct grub_pata_device +{ + /* IDE port to use. */ + int port; + + /* IO addresses on which the registers for this device can be + found. */ + grub_port_t ioaddress; + + /* Two devices can be connected to a single cable. Use this field + to select device 0 (commonly known as "master") or device 1 + (commonly known as "slave"). */ + int device; + + int present; + + struct grub_pata_device *next; +}; + +static struct grub_pata_device *grub_pata_devices; + +static inline void +grub_pata_regset (struct grub_pata_device *dev, int reg, int val) +{ + grub_outb (val, dev->ioaddress + reg); +} + +static inline grub_uint8_t +grub_pata_regget (struct grub_pata_device *dev, int reg) +{ + return grub_inb (dev->ioaddress + reg); +} + +/* Wait for !BSY. */ +static grub_err_t +grub_pata_wait_not_busy (struct grub_pata_device *dev, int milliseconds) +{ + /* ATA requires 400ns (after a write to CMD register) or + 1 PIO cycle (after a DRQ block transfer) before + first check of BSY. */ + grub_millisleep (1); + + int i = 1; + grub_uint8_t sts; + while ((sts = grub_pata_regget (dev, GRUB_ATA_REG_STATUS)) + & GRUB_ATA_STATUS_BUSY) + { + if (i >= milliseconds) + { + grub_dprintf ("pata", "timeout: %dms, status=0x%x\n", + milliseconds, sts); + return grub_error (GRUB_ERR_TIMEOUT, "PATA timeout"); + } + + grub_millisleep (1); + i++; + } + + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_pata_check_ready (struct grub_pata_device *dev, int spinup) +{ + if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY) + return grub_pata_wait_not_busy (dev, spinup ? GRUB_ATA_TOUT_SPINUP + : GRUB_ATA_TOUT_STD); + + return GRUB_ERR_NONE; +} + +static inline void +grub_pata_wait (void) +{ + grub_millisleep (50); +} + +static void +grub_pata_pio_read (struct grub_pata_device *dev, char *buf, grub_size_t size) +{ + unsigned int i; + + /* Read in the data, word by word. */ + for (i = 0; i < size / 2; i++) + grub_set_unaligned16 (buf + 2 * i, + grub_le_to_cpu16 (grub_inw(dev->ioaddress + + GRUB_ATA_REG_DATA))); + if (size & 1) + buf[size - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + + GRUB_ATA_REG_DATA)); +} + +static void +grub_pata_pio_write (struct grub_pata_device *dev, char *buf, grub_size_t size) +{ + unsigned int i; + + /* Write the data, word by word. */ + for (i = 0; i < size / 2; i++) + grub_outw(grub_cpu_to_le16 (grub_get_unaligned16 (buf + 2 * i)), dev->ioaddress + GRUB_ATA_REG_DATA); +} + +/* ATA pass through support, used by hdparm.mod. */ +static grub_err_t +grub_pata_readwrite (struct grub_ata *disk, + struct grub_disk_ata_pass_through_parms *parms, + int spinup) +{ + struct grub_pata_device *dev = (struct grub_pata_device *) disk->data; + grub_size_t nread = 0; + int i; + + if (! (parms->cmdsize == 0 || parms->cmdsize == 12)) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "ATAPI non-12 byte commands not supported"); + + grub_dprintf ("pata", "pata_pass_through: cmd=0x%x, features=0x%x, sectors=0x%x\n", + parms->taskfile.cmd, + parms->taskfile.features, + parms->taskfile.sectors); + grub_dprintf ("pata", "lba_high=0x%x, lba_mid=0x%x, lba_low=0x%x, size=%" + PRIuGRUB_SIZE "\n", + parms->taskfile.lba_high, + parms->taskfile.lba_mid, + parms->taskfile.lba_low, parms->size); + + /* Set registers. */ + grub_pata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) + | (parms->taskfile.disk & 0xef)); + if (grub_pata_check_ready (dev, spinup)) + return grub_errno; + + for (i = GRUB_ATA_REG_SECTORS; i <= GRUB_ATA_REG_LBAHIGH; i++) + grub_pata_regset (dev, i, + parms->taskfile.raw[7 + (i - GRUB_ATA_REG_SECTORS)]); + for (i = GRUB_ATA_REG_FEATURES; i <= GRUB_ATA_REG_LBAHIGH; i++) + grub_pata_regset (dev, i, parms->taskfile.raw[i - GRUB_ATA_REG_FEATURES]); + + /* Start command. */ + grub_pata_regset (dev, GRUB_ATA_REG_CMD, parms->taskfile.cmd); + + /* Wait for !BSY. */ + if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) + return grub_errno; + + /* Check status. */ + grub_int8_t sts = grub_pata_regget (dev, GRUB_ATA_REG_STATUS); + grub_dprintf ("pata", "status=0x%x\n", sts); + + if (parms->cmdsize) + { + grub_uint8_t irs; + /* Wait for !BSY. */ + if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) + return grub_errno; + + irs = grub_pata_regget (dev, GRUB_ATAPI_REG_IREASON); + /* OK if DRQ is asserted and interrupt reason is as expected. */ + if (!((sts & GRUB_ATA_STATUS_DRQ) + && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_CMD_OUT)) + return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error"); + /* Write the packet. */ + grub_pata_pio_write (dev, parms->cmd, parms->cmdsize); + } + + /* Transfer data. */ + while (nread < parms->size + && ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) + == GRUB_ATA_STATUS_DRQ) + && (!parms->cmdsize + || ((grub_pata_regget (dev, GRUB_ATAPI_REG_IREASON) + & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_DATA_IN))) + { + unsigned cnt; + + /* Wait for !BSY. */ + if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) + return grub_errno; + + if (parms->cmdsize) + { + cnt = grub_pata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8 + | grub_pata_regget (dev, GRUB_ATAPI_REG_CNTLOW); + grub_dprintf("pata", "DRQ count=%u\n", cnt); + + /* Count of last transfer may be uneven. */ + if (! (0 < cnt && cnt <= parms->size - nread + && (! (cnt & 1) || cnt == parms->size - nread))) + return grub_error (GRUB_ERR_READ_ERROR, + "invalid ATAPI transfer count"); + } + else + cnt = GRUB_DISK_SECTOR_SIZE; + if (cnt > parms->size - nread) + cnt = parms->size - nread; + + if (parms->write) + grub_pata_pio_write (dev, (char *) parms->buffer + nread, cnt); + else + grub_pata_pio_read (dev, (char *) parms->buffer + nread, cnt); + + nread += cnt; + } + if (parms->write) + { + /* Check for write error. */ + if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) + return grub_errno; + + if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS) + & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) + return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error"); + } + parms->size = nread; + + /* Wait for !BSY. */ + if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) + return grub_errno; + + /* Return registers. */ + for (i = GRUB_ATA_REG_ERROR; i <= GRUB_ATA_REG_STATUS; i++) + parms->taskfile.raw[i - GRUB_ATA_REG_FEATURES] = grub_pata_regget (dev, i); + + grub_dprintf ("pata", "status=0x%x, error=0x%x, sectors=0x%x\n", + parms->taskfile.status, + parms->taskfile.error, + parms->taskfile.sectors); + + if (parms->taskfile.status + & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) + return grub_error (GRUB_ERR_READ_ERROR, "PATA passthrough failed"); + + return GRUB_ERR_NONE; +} + +static grub_err_t +check_device (struct grub_pata_device *dev) +{ + grub_pata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); + grub_pata_wait (); + + /* Try to detect if the port is in use by writing to it, + waiting for a while and reading it again. If the value + was preserved, there is a device connected. */ + grub_pata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A); + grub_pata_wait (); + grub_uint8_t sec = grub_pata_regget (dev, GRUB_ATA_REG_SECTORS); + grub_dprintf ("ata", "sectors=0x%x\n", sec); + if (sec != 0x5A) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected"); + + /* The above test may detect a second (slave) device + connected to a SATA controller which supports only one + (master) device. It is not safe to use the status register + READY bit to check for controller channel existence. Some + ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */ + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_pata_device_initialize (int port, int device, int addr) +{ + struct grub_pata_device *dev; + struct grub_pata_device **devp; + grub_err_t err; + + grub_dprintf ("pata", "detecting device %d,%d (0x%x)\n", + port, device, addr); + + dev = grub_malloc (sizeof(*dev)); + if (! dev) + return grub_errno; + + /* Setup the device information. */ + dev->port = port; + dev->device = device; + dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE; + dev->present = 1; + dev->next = NULL; + + /* Register the device. */ + for (devp = &grub_pata_devices; *devp; devp = &(*devp)->next); + *devp = dev; + + err = check_device (dev); + if (err) + grub_print_error (); + + return 0; +} + +#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS +static int NESTED_FUNC_ATTR +grub_pata_pciinit (grub_pci_device_t dev, + grub_pci_id_t pciid) +{ + static int compat_use[2] = { 0 }; + grub_pci_address_t addr; + grub_uint32_t class; + grub_uint32_t bar1; + grub_uint32_t bar2; + int rega; + int i; + static int controller = 0; + int cs5536 = 0; + int nports = 2; + + /* Read class. */ + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + class = grub_pci_read (addr); + + /* AMD CS5536 Southbridge. */ + if (pciid == GRUB_CS5536_PCIID) + { + cs5536 = 1; + nports = 1; + } + + /* Check if this class ID matches that of a PCI IDE Controller. */ + if (!cs5536 && (class >> 16 != 0x0101)) + return 0; + + for (i = 0; i < nports; i++) + { + /* Set to 0 when the channel operated in compatibility mode. */ + int compat; + + /* We don't support non-compatibility mode for CS5536. */ + if (cs5536) + compat = 0; + else + compat = (class >> (8 + 2 * i)) & 1; + + rega = 0; + + /* If the channel is in compatibility mode, just assign the + default registers. */ + if (compat == 0 && !compat_use[i]) + { + rega = grub_pata_ioaddress[i]; + compat_use[i] = 1; + } + else if (compat) + { + /* Read the BARs, which either contain a mmapped IO address + or the IO port address. */ + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES + + sizeof (grub_uint64_t) * i); + bar1 = grub_pci_read (addr); + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES + + sizeof (grub_uint64_t) * i + + sizeof (grub_uint32_t)); + bar2 = grub_pci_read (addr); + + /* Check if the BARs describe an IO region. */ + if ((bar1 & 1) && (bar2 & 1)) + { + rega = bar1 & ~3; + } + } + + grub_dprintf ("pata", + "PCI dev (%d,%d,%d) compat=%d rega=0x%x\n", + grub_pci_get_bus (dev), grub_pci_get_device (dev), + grub_pci_get_function (dev), compat, rega); + + if (rega) + { + grub_errno = GRUB_ERR_NONE; + grub_pata_device_initialize (controller * 2 + i, 0, rega); + + /* Most errors raised by grub_ata_device_initialize() are harmless. + They just indicate this particular drive is not responding, most + likely because it doesn't exist. We might want to ignore specific + error types here, instead of printing them. */ + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + grub_pata_device_initialize (controller * 2 + i, 1, rega); + + /* Likewise. */ + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + } + } + + controller++; + + return 0; +} + +static grub_err_t +grub_pata_initialize (void) +{ + grub_pci_iterate (grub_pata_pciinit); + return 0; +} +#else +static grub_err_t +grub_pata_initialize (void) +{ + int i; + for (i = 0; i < 2; i++) + { + grub_pata_device_initialize (i, 0, grub_pata_ioaddress[i]); + grub_pata_device_initialize (i, 1, grub_pata_ioaddress[i]); + } + return 0; +} +#endif + +static grub_err_t +grub_pata_open (int id, int devnum, struct grub_ata *ata) +{ + struct grub_pata_device *dev; + struct grub_pata_device *devfnd = 0; + grub_err_t err; + + if (id != GRUB_SCSI_SUBSYSTEM_PATA) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a PATA device"); + + for (dev = grub_pata_devices; dev; dev = dev->next) + { + if (dev->port * 2 + dev->device == devnum) + { + devfnd = dev; + break; + } + } + + grub_dprintf ("pata", "opening PATA dev `ata%d'\n", devnum); + + if (! devfnd) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such PATA device"); + + err = check_device (devfnd); + if (err) + return err; + + ata->data = devfnd; + ata->dma = 0; + ata->maxbuffer = 256 * 512; + ata->present = &devfnd->present; + + return GRUB_ERR_NONE; +} + +static int +grub_pata_iterate (int (*hook) (int id, int bus), + grub_disk_pull_t pull) +{ + struct grub_pata_device *dev; + + if (pull != GRUB_DISK_PULL_NONE) + return 0; + + for (dev = grub_pata_devices; dev; dev = dev->next) + if (hook (GRUB_SCSI_SUBSYSTEM_PATA, dev->port * 2 + dev->device)) + return 1; + + return 0; +} + + +static struct grub_ata_dev grub_pata_dev = + { + .iterate = grub_pata_iterate, + .open = grub_pata_open, + .readwrite = grub_pata_readwrite, + }; + + + + +GRUB_MOD_INIT(ata_pthru) +{ + /* To prevent two drivers operating on the same disks. */ + grub_disk_firmware_is_tainted = 1; + if (grub_disk_firmware_fini) + { + grub_disk_firmware_fini (); + grub_disk_firmware_fini = NULL; + } + + /* ATA initialization. */ + grub_pata_initialize (); + + grub_ata_dev_register (&grub_pata_dev); +} + +GRUB_MOD_FINI(ata_pthru) +{ + grub_ata_dev_unregister (&grub_pata_dev); +} diff --git a/grub-core/disk/raid.c b/grub-core/disk/raid.c deleted file mode 100644 index 2fd6aa9de..000000000 --- a/grub-core/disk/raid.c +++ /dev/null @@ -1,723 +0,0 @@ -/* raid.c - module to read RAID arrays. */ -/* - * 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 - -/* Linked list of RAID arrays. */ -static struct grub_raid_array *array_list; -grub_raid5_recover_func_t grub_raid5_recover_func; -grub_raid6_recover_func_t grub_raid6_recover_func; - - -static char -grub_is_array_readable (struct grub_raid_array *array) -{ - switch (array->level) - { - case 0: - if (array->nr_devs == array->total_devs) - return 1; - break; - - case 1: - if (array->nr_devs >= 1) - return 1; - break; - - case 4: - case 5: - case 6: - case 10: - { - unsigned int n; - - if (array->level == 10) - { - n = array->layout & 0xFF; - if (n == 1) - n = (array->layout >> 8) & 0xFF; - - n--; - } - else - n = array->level / 3; - - if (array->nr_devs >= array->total_devs - n) - return 1; - - break; - } - } - - return 0; -} - -static int -grub_raid_iterate (int (*hook) (const char *name)) -{ - struct grub_raid_array *array; - - for (array = array_list; array != NULL; array = array->next) - { - if (grub_is_array_readable (array)) - if (hook (array->name)) - return 1; - } - - return 0; -} - -#ifdef GRUB_UTIL -static grub_disk_memberlist_t -grub_raid_memberlist (grub_disk_t disk) -{ - struct grub_raid_array *array = disk->data; - grub_disk_memberlist_t list = NULL, tmp; - unsigned int i; - - for (i = 0; i < array->total_devs; i++) - if (array->device[i]) - { - tmp = grub_malloc (sizeof (*tmp)); - tmp->disk = array->device[i]; - tmp->next = list; - list = tmp; - } - - return list; -} -#endif - -static grub_err_t -grub_raid_open (const char *name, grub_disk_t disk) -{ - struct grub_raid_array *array; - unsigned n; - - for (array = array_list; array != NULL; array = array->next) - { - if (!grub_strcmp (array->name, name)) - if (grub_is_array_readable (array)) - break; - } - - if (!array) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", - name); - - disk->id = array->number; - disk->data = array; - - grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name, - array->total_devs, (unsigned long long) array->disk_size); - - switch (array->level) - { - case 1: - disk->total_sectors = array->disk_size; - break; - - case 10: - n = array->layout & 0xFF; - if (n == 1) - n = (array->layout >> 8) & 0xFF; - - disk->total_sectors = grub_divmod64 (array->total_devs * - array->disk_size, - n, 0); - break; - - case 0: - case 4: - case 5: - case 6: - n = array->level / 3; - - disk->total_sectors = (array->total_devs - n) * array->disk_size; - break; - } - - grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name, - array->level, (unsigned long long) disk->total_sectors); - - return 0; -} - -static void -grub_raid_close (grub_disk_t disk __attribute ((unused))) -{ - return; -} - -void -grub_raid_block_xor (char *buf1, const char *buf2, int size) -{ - grub_size_t *p1; - const grub_size_t *p2; - - p1 = (grub_size_t *) buf1; - p2 = (const grub_size_t *) buf2; - size /= GRUB_CPU_SIZEOF_VOID_P; - - while (size) - { - *(p1++) ^= *(p2++); - size--; - } -} - -static grub_err_t -grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) -{ - struct grub_raid_array *array = disk->data; - grub_err_t err = 0; - - switch (array->level) - { - case 0: - case 1: - case 10: - { - grub_disk_addr_t read_sector, far_ofs; - grub_uint32_t disknr, b, near, far, ofs; - - read_sector = grub_divmod64 (sector, array->chunk_size, &b); - far = ofs = near = 1; - far_ofs = 0; - - if (array->level == 1) - near = array->total_devs; - else if (array->level == 10) - { - near = array->layout & 0xFF; - far = (array->layout >> 8) & 0xFF; - if (array->layout >> 16) - { - ofs = far; - far_ofs = 1; - } - else - far_ofs = grub_divmod64 (array->disk_size, - far * array->chunk_size, 0); - - far_ofs *= array->chunk_size; - } - - read_sector = grub_divmod64 (read_sector * near, array->total_devs, - &disknr); - - ofs *= array->chunk_size; - read_sector *= ofs; - - while (1) - { - grub_size_t read_size; - unsigned int i, j; - - read_size = array->chunk_size - b; - if (read_size > size) - read_size = size; - - for (i = 0; i < near; i++) - { - unsigned int k; - - k = disknr; - for (j = 0; j < far; j++) - { - if (array->device[k]) - { - if (grub_errno == GRUB_ERR_READ_ERROR) - grub_errno = GRUB_ERR_NONE; - - err = grub_disk_read (array->device[k], - array->start_sector[k] + - read_sector + j * far_ofs + b, - 0, - read_size << GRUB_DISK_SECTOR_BITS, - buf); - if (! err) - break; - else if (err != GRUB_ERR_READ_ERROR) - return err; - } - else - err = grub_error (GRUB_ERR_READ_ERROR, - "disk missing"); - - k++; - if (k == array->total_devs) - k = 0; - } - - if (! err) - break; - - disknr++; - if (disknr == array->total_devs) - { - disknr = 0; - read_sector += ofs; - } - } - - if (err) - return err; - - buf += read_size << GRUB_DISK_SECTOR_BITS; - size -= read_size; - if (! size) - break; - - b = 0; - disknr += (near - i); - while (disknr >= array->total_devs) - { - disknr -= array->total_devs; - read_sector += ofs; - } - } - break; - } - - case 4: - case 5: - case 6: - { - grub_disk_addr_t read_sector; - grub_uint32_t b, p, n, disknr, e; - - /* n = 1 for level 4 and 5, 2 for level 6. */ - n = array->level / 3; - - /* Find the first sector to read. */ - read_sector = grub_divmod64 (sector, array->chunk_size, &b); - read_sector = grub_divmod64 (read_sector, array->total_devs - n, - &disknr); - if (array->level >= 5) - { - grub_divmod64 (read_sector, array->total_devs, &p); - - if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)) - p = array->total_devs - 1 - p; - - if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) - { - disknr += p + n; - } - else - { - grub_uint32_t q; - - q = p + (n - 1); - if (q >= array->total_devs) - q -= array->total_devs; - - if (disknr >= p) - disknr += n; - else if (disknr >= q) - disknr += q + 1; - } - - if (disknr >= array->total_devs) - disknr -= array->total_devs; - } - else - p = array->total_devs - n; - - read_sector *= array->chunk_size; - - while (1) - { - grub_size_t read_size; - int next_level; - - read_size = array->chunk_size - b; - if (read_size > size) - read_size = size; - - e = 0; - if (array->device[disknr]) - { - /* Reset read error. */ - if (grub_errno == GRUB_ERR_READ_ERROR) - grub_errno = GRUB_ERR_NONE; - - err = grub_disk_read (array->device[disknr], - array->start_sector[disknr] + - read_sector + b, 0, - read_size << GRUB_DISK_SECTOR_BITS, - buf); - - if ((err) && (err != GRUB_ERR_READ_ERROR)) - break; - e++; - } - else - err = GRUB_ERR_READ_ERROR; - - if (err) - { - if (array->nr_devs < array->total_devs - n + e) - break; - - grub_errno = GRUB_ERR_NONE; - if (array->level == 6) - { - err = ((grub_raid6_recover_func) ? - (*grub_raid6_recover_func) (array, disknr, p, - buf, read_sector + b, - read_size) : - grub_error (GRUB_ERR_BAD_DEVICE, - "raid6rec is not loaded")); - } - else - { - err = ((grub_raid5_recover_func) ? - (*grub_raid5_recover_func) (array, disknr, - buf, read_sector + b, - read_size) : - grub_error (GRUB_ERR_BAD_DEVICE, - "raid5rec is not loaded")); - } - - if (err) - break; - } - - buf += read_size << GRUB_DISK_SECTOR_BITS; - size -= read_size; - if (! size) - break; - - b = 0; - disknr++; - - if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) - { - if (disknr == array->total_devs) - disknr = 0; - - next_level = (disknr == p); - } - else - { - if (disknr == p) - disknr += n; - - next_level = (disknr >= array->total_devs); - } - - if (next_level) - { - read_sector += array->chunk_size; - - if (array->level >= 5) - { - if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK) - p = (p == array->total_devs - 1) ? 0 : p + 1; - else - p = (p == 0) ? array->total_devs - 1 : p - 1; - - if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) - { - disknr = p + n; - if (disknr >= array->total_devs) - disknr -= array->total_devs; - } - else - { - disknr -= array->total_devs; - if (disknr == p) - disknr += n; - } - } - else - disknr = 0; - } - } - } - break; - } - - return err; -} - -static grub_err_t -grub_raid_write (grub_disk_t disk __attribute ((unused)), - grub_disk_addr_t sector __attribute ((unused)), - grub_size_t size __attribute ((unused)), - const char *buf __attribute ((unused))) -{ - return GRUB_ERR_NOT_IMPLEMENTED_YET; -} - -static grub_err_t -insert_array (grub_disk_t disk, struct grub_raid_array *new_array, - grub_disk_addr_t start_sector, const char *scanner_name) -{ - struct grub_raid_array *array = 0, *p; - - /* See whether the device is part of an array we have already seen a - device from. */ - for (p = array_list; p != NULL; p = p->next) - if ((p->uuid_len == new_array->uuid_len) && - (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len))) - { - grub_free (new_array->uuid); - array = p; - - /* Do some checks before adding the device to the array. */ - - /* FIXME: Check whether the update time of the superblocks are - the same. */ - - if (array->total_devs == array->nr_devs) - /* We found more members of the array than the array - actually has according to its superblock. This shouldn't - happen normally. */ - grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?", - array->total_devs); - - if (array->device[new_array->index] != NULL) - /* We found multiple devices with the same number. Again, - this shouldn't happen. */ - grub_dprintf ("raid", "Found two disks with the number %d?!?", - new_array->number); - - if (new_array->disk_size < array->disk_size) - array->disk_size = new_array->disk_size; - break; - } - - /* Add an array to the list if we didn't find any. */ - if (!array) - { - array = grub_malloc (sizeof (*array)); - if (!array) - { - grub_free (new_array->uuid); - return grub_errno; - } - - *array = *new_array; - array->nr_devs = 0; - grub_memset (&array->device, 0, sizeof (array->device)); - grub_memset (&array->start_sector, 0, sizeof (array->start_sector)); - - if (! array->name) - { - for (p = array_list; p != NULL; p = p->next) - { - if (! p->name && p->number == array->number) - break; - } - } - - if (array->name || p) - { - /* The number is already in use, so we need to find a new one. - (Or, in the case of named arrays, the array doesn't have its - own number, but we need one that doesn't clash for use as a key - in the disk cache. */ - int i = array->name ? 0x40000000 : 0; - - while (1) - { - for (p = array_list; p != NULL; p = p->next) - { - if (p->number == i) - break; - } - - if (! p) - { - /* We found an unused number. */ - array->number = i; - break; - } - - i++; - } - } - - /* mdraid 1.x superblocks have only a name stored not a number. - Use it directly as GRUB device. */ - if (! array->name) - { - array->name = grub_xasprintf ("md%d", array->number); - if (! array->name) - { - grub_free (array->uuid); - grub_free (array); - - return grub_errno; - } - } - else - { - /* Strip off the homehost if present. */ - char *colon = grub_strchr (array->name, ':'); - char *new_name = grub_xasprintf ("md/%s", - colon ? colon + 1 : array->name); - - if (! new_name) - { - grub_free (array->uuid); - grub_free (array); - - return grub_errno; - } - - grub_free (array->name); - array->name = new_name; - } - - grub_dprintf ("raid", "Found array %s (%s)\n", array->name, - scanner_name); - - /* Add our new array to the list. */ - array->next = array_list; - array_list = array; - - /* RAID 1 doesn't use a chunksize but code assumes one so set - one. */ - if (array->level == 1) - array->chunk_size = 64; - } - - /* Add the device to the array. */ - array->device[new_array->index] = disk; - array->start_sector[new_array->index] = start_sector; - array->nr_devs++; - - return 0; -} - -static grub_raid_t grub_raid_list; - -static void -free_array (void) -{ - struct grub_raid_array *array; - - array = array_list; - while (array) - { - struct grub_raid_array *p; - int i; - - p = array; - array = array->next; - - for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++) - if (p->device[i]) - grub_disk_close (p->device[i]); - - grub_free (p->uuid); - grub_free (p->name); - grub_free (p); - } - - array_list = 0; -} - -void -grub_raid_register (grub_raid_t raid) -{ - auto int hook (const char *name); - int hook (const char *name) - { - grub_disk_t disk; - struct grub_raid_array array; - grub_disk_addr_t start_sector; - - grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); - - disk = grub_disk_open (name); - if (!disk) - return 0; - - if ((disk->total_sectors != GRUB_ULONG_MAX) && - (! grub_raid_list->detect (disk, &array, &start_sector)) && - (! insert_array (disk, &array, start_sector, grub_raid_list->name))) - return 0; - - /* This error usually means it's not raid, no need to display - it. */ - if (grub_errno != GRUB_ERR_OUT_OF_RANGE) - grub_print_error (); - - grub_errno = GRUB_ERR_NONE; - - grub_disk_close (disk); - - return 0; - } - - raid->next = grub_raid_list; - grub_raid_list = raid; - grub_device_iterate (&hook); -} - -void -grub_raid_unregister (grub_raid_t raid) -{ - grub_raid_t *p, q; - - for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next) - if (q == raid) - { - *p = q->next; - break; - } -} - -static struct grub_disk_dev grub_raid_dev = - { - .name = "raid", - .id = GRUB_DISK_DEVICE_RAID_ID, - .iterate = grub_raid_iterate, - .open = grub_raid_open, - .close = grub_raid_close, - .read = grub_raid_read, - .write = grub_raid_write, -#ifdef GRUB_UTIL - .memberlist = grub_raid_memberlist, -#endif - .next = 0 - }; - - -GRUB_MOD_INIT(raid) -{ - grub_disk_dev_register (&grub_raid_dev); -} - -GRUB_MOD_FINI(raid) -{ - grub_disk_dev_unregister (&grub_raid_dev); - free_array (); -} diff --git a/grub-core/disk/raid5_recover.c b/grub-core/disk/raid5_recover.c index 31cef88b1..62d76d1df 100644 --- a/grub-core/disk/raid5_recover.c +++ b/grub-core/disk/raid5_recover.c @@ -22,10 +22,13 @@ #include #include #include -#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_err_t -grub_raid5_recover (struct grub_raid_array *array, int disknr, +grub_raid5_recover (struct grub_diskfilter_segment *array, int disknr, char *buf, grub_disk_addr_t sector, int size) { char *buf2; @@ -38,14 +41,15 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr, grub_memset (buf, 0, size); - for (i = 0; i < (int) array->total_devs; i++) + for (i = 0; i < (int) array->node_count; i++) { grub_err_t err; if (i == disknr) continue; - err = grub_disk_read (array->device[i], sector, 0, size, buf2); + err = grub_diskfilter_read_node (&array->nodes[i], sector, + size >> GRUB_DISK_SECTOR_BITS, buf2); if (err) { @@ -53,7 +57,7 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr, return err; } - grub_raid_block_xor (buf, buf2, size); + grub_crypto_xor (buf, buf, buf2, size); } grub_free (buf2); diff --git a/grub-core/disk/raid6_recover.c b/grub-core/disk/raid6_recover.c index 550968ceb..779a39eaa 100644 --- a/grub-core/disk/raid6_recover.c +++ b/grub-core/disk/raid6_recover.c @@ -22,73 +22,49 @@ #include #include #include -#include +#include +#include -static grub_uint8_t raid6_table1[256][256]; -static grub_uint8_t raid6_table2[256][256]; +GRUB_MOD_LICENSE ("GPLv3+"); + +/* x**y. */ +static grub_uint8_t powx[255 * 2]; +/* Such an s that x**s = y */ +static int powx_inv[256]; +static const grub_uint8_t poly = 0x1d; static void -grub_raid_block_mul (grub_uint8_t mul, char *buf, int size) +grub_raid_block_mulx (int mul, char *buf, int size) { int i; grub_uint8_t *p; p = (grub_uint8_t *) buf; for (i = 0; i < size; i++, p++) - *p = raid6_table1[mul][*p]; + if (*p) + *p = powx[mul + powx_inv[*p]]; } static void grub_raid6_init_table (void) { - int i, j; + int i; - for (i = 0; i < 256; i++) - raid6_table1[i][1] = raid6_table1[1][i] = i; - - for (i = 2; i < 256; i++) - for (j = i; j < 256; j++) - { - int n; - grub_uint8_t c; - - n = i >> 1; - - c = raid6_table1[n][j]; - c = (c << 1) ^ ((c & 0x80) ? 0x1d : 0); - if (i & 1) - c ^= j; - - raid6_table1[j][i] = raid6_table1[i][j] = c; - } - - raid6_table2[0][0] = 1; - for (i = 1; i < 256; i++) - raid6_table2[i][i] = raid6_table1[raid6_table2[i - 1][i - 1]][2]; - - for (i = 0; i < 254; i++) - for (j = 0; j < 254; j++) - { - grub_uint8_t c, n; - int k; - - if (i == j) - continue; - - k = i - j; - if (k < 0) - k += 255; - - c = n = raid6_table2[k][k] ^ 1; - for (k = 0; k < 253; k++) - c = raid6_table1[c][n]; - - raid6_table2[i][j] = raid6_table1[raid6_table2[255 - j][255 - j]][c]; - } + grub_uint8_t cur = 1; + for (i = 0; i < 255; i++) + { + powx[i] = cur; + powx[i + 255] = cur; + powx_inv[cur] = i; + if (cur & 0x80) + cur = (cur << 1) ^ poly; + else + cur <<= 1; + } } static grub_err_t -grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, +grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p, char *buf, grub_disk_addr_t sector, int size) { int i, q, pos; @@ -105,25 +81,30 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, goto quit; q = p + 1; - if (q == (int) array->total_devs) + if (q == (int) array->node_count) q = 0; pos = q + 1; - if (pos == (int) array->total_devs) + if (pos == (int) array->node_count) pos = 0; - for (i = 0; i < (int) array->total_devs - 2; i++) + for (i = 0; i < (int) array->node_count - 2; i++) { + int c; + if (array->layout & GRUB_RAID_LAYOUT_MUL_FROM_POS) + c = pos; + else + c = i; if (pos == disknr) - bad1 = i; + bad1 = c; else { - if ((array->device[pos]) && - (! grub_disk_read (array->device[pos], sector, 0, size, buf))) + if (! grub_diskfilter_read_node (&array->nodes[pos], sector, + size >> GRUB_DISK_SECTOR_BITS, buf)) { - grub_raid_block_xor (pbuf, buf, size); - grub_raid_block_mul (raid6_table2[i][i], buf, size); - grub_raid_block_xor (qbuf, buf, size); + grub_crypto_xor (pbuf, pbuf, buf, size); + grub_raid_block_mulx (c, buf, size); + grub_crypto_xor (qbuf, qbuf, buf, size); } else { @@ -131,13 +112,13 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, if (bad2 >= 0) goto quit; - bad2 = i; + bad2 = c; grub_errno = GRUB_ERR_NONE; } } pos++; - if (pos == (int) array->total_devs) + if (pos == (int) array->node_count) pos = 0; } @@ -148,55 +129,46 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, if (bad2 < 0) { /* One bad device */ - if ((array->device[p]) && - (! grub_disk_read (array->device[p], sector, 0, size, buf))) + if ((! grub_diskfilter_read_node (&array->nodes[p], sector, + size >> GRUB_DISK_SECTOR_BITS, buf))) { - grub_raid_block_xor (buf, pbuf, size); - goto quit; - } - - if (! array->device[q]) - { - grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore"); + grub_crypto_xor (buf, buf, pbuf, size); goto quit; } grub_errno = GRUB_ERR_NONE; - if (grub_disk_read (array->device[q], sector, 0, size, buf)) + if (grub_diskfilter_read_node (&array->nodes[q], sector, + size >> GRUB_DISK_SECTOR_BITS, buf)) goto quit; - grub_raid_block_xor (buf, qbuf, size); - grub_raid_block_mul (raid6_table2[255 - bad1][255 - bad1], buf, + grub_crypto_xor (buf, buf, qbuf, size); + grub_raid_block_mulx (255 - bad1, buf, size); } else { /* Two bad devices */ - grub_uint8_t c; + int c; - if ((! array->device[p]) || (! array->device[q])) - { - grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore"); - goto quit; - } - - if (grub_disk_read (array->device[p], sector, 0, size, buf)) + if (grub_diskfilter_read_node (&array->nodes[p], sector, + size >> GRUB_DISK_SECTOR_BITS, buf)) goto quit; - grub_raid_block_xor (pbuf, buf, size); + grub_crypto_xor (pbuf, pbuf, buf, size); - if (grub_disk_read (array->device[q], sector, 0, size, buf)) + if (grub_diskfilter_read_node (&array->nodes[q], sector, + size >> GRUB_DISK_SECTOR_BITS, buf)) goto quit; - grub_raid_block_xor (qbuf, buf, size); + grub_crypto_xor (qbuf, qbuf, buf, size); - c = raid6_table2[bad2][bad1]; - grub_raid_block_mul (c, qbuf, size); + c = (255 - bad1 + (255 - powx_inv[(powx[bad2 - bad1 + 255] ^ 1)])) % 255; + grub_raid_block_mulx (c, qbuf, size); - c = raid6_table1[raid6_table2[bad2][bad2]][c]; - grub_raid_block_mul (c, pbuf, size); + c = (bad2 + c) % 255; + grub_raid_block_mulx (c, pbuf, size); - grub_raid_block_xor (pbuf, qbuf, size); + grub_crypto_xor (pbuf, pbuf, qbuf, size); grub_memcpy (buf, pbuf, size); } diff --git a/grub-core/disk/scsi.c b/grub-core/disk/scsi.c index 902ab12c3..508bc27f6 100644 --- a/grub-core/disk/scsi.c +++ b/grub-core/disk/scsi.c @@ -27,9 +27,17 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_scsi_dev_t grub_scsi_dev_list; +const char grub_scsi_names[GRUB_SCSI_NUM_SUBSYSTEMS][5] = { + [GRUB_SCSI_SUBSYSTEM_USBMS] = "usb", + [GRUB_SCSI_SUBSYSTEM_PATA] = "ata", + [GRUB_SCSI_SUBSYSTEM_AHCI] = "ahci" +}; + void grub_scsi_dev_register (grub_scsi_dev_t dev) { @@ -145,14 +153,14 @@ grub_scsi_inquiry (grub_scsi_t scsi) /* Read the capacity and block size of SCSI. */ static grub_err_t -grub_scsi_read_capacity (grub_scsi_t scsi) +grub_scsi_read_capacity10 (grub_scsi_t scsi) { - struct grub_scsi_read_capacity rc; - struct grub_scsi_read_capacity_data rcd; + struct grub_scsi_read_capacity10 rc; + struct grub_scsi_read_capacity10_data rcd; grub_err_t err; grub_err_t err_sense; - rc.opcode = grub_scsi_cmd_read_capacity; + rc.opcode = grub_scsi_cmd_read_capacity10; rc.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; rc.logical_block_addr = 0; rc.reserved1 = 0; @@ -174,7 +182,42 @@ grub_scsi_read_capacity (grub_scsi_t scsi) if (err) return err; - scsi->size = grub_be_to_cpu32 (rcd.size); + scsi->last_block = grub_be_to_cpu32 (rcd.last_block); + scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize); + + return GRUB_ERR_NONE; +} + +/* Read the capacity and block size of SCSI. */ +static grub_err_t +grub_scsi_read_capacity16 (grub_scsi_t scsi) +{ + struct grub_scsi_read_capacity16 rc; + struct grub_scsi_read_capacity16_data rcd; + grub_err_t err; + grub_err_t err_sense; + + rc.opcode = grub_scsi_cmd_read_capacity16; + rc.lun = (scsi->lun << GRUB_SCSI_LUN_SHIFT) | 0x10; + rc.logical_block_addr = 0; + rc.alloc_len = grub_cpu_to_be32 (sizeof (rcd)); + rc.PMI = 0; + rc.control = 0; + + err = scsi->dev->read (scsi, sizeof (rc), (char *) &rc, + sizeof (rcd), (char *) &rcd); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense = grub_scsi_request_sense (scsi); + if (err_sense != GRUB_ERR_NONE) + grub_errno = err; +/* err_sense is ignored for now and Request Sense Data also... */ + + if (err) + return err; + + scsi->last_block = grub_be_to_cpu64 (rcd.last_block); scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize); return GRUB_ERR_NONE; @@ -245,12 +288,43 @@ grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector, return err; } -#if 0 +/* Send a SCSI request for DISK: read SIZE sectors starting with + sector SECTOR to BUF. */ +static grub_err_t +grub_scsi_read16 (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_scsi_t scsi; + struct grub_scsi_read16 rd; + grub_err_t err; + grub_err_t err_sense; + + scsi = disk->data; + + rd.opcode = grub_scsi_cmd_read16; + rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; + rd.lba = grub_cpu_to_be64 (sector); + rd.size = grub_cpu_to_be32 (size); + rd.reserved = 0; + rd.control = 0; + + err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense = grub_scsi_request_sense (scsi); + if (err_sense != GRUB_ERR_NONE) + grub_errno = err; + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; +} + /* Send a SCSI request for DISK: write the data stored in BUF to SIZE sectors starting with SECTOR. */ static grub_err_t grub_scsi_write10 (grub_disk_t disk, grub_disk_addr_t sector, - grub_size_t size, char *buf) + grub_size_t size, const char *buf) { grub_scsi_t scsi; struct grub_scsi_write10 wr; @@ -279,6 +353,8 @@ grub_scsi_write10 (grub_disk_t disk, grub_disk_addr_t sector, return err; } +#if 0 + /* Send a SCSI request for DISK: write the data stored in BUF to SIZE sectors starting with SECTOR. */ static grub_err_t @@ -312,15 +388,49 @@ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector, } #endif +/* Send a SCSI request for DISK: write the data stored in BUF to SIZE + sectors starting with SECTOR. */ +static grub_err_t +grub_scsi_write16 (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + grub_scsi_t scsi; + struct grub_scsi_write16 wr; + grub_err_t err; + grub_err_t err_sense; + + scsi = disk->data; + + wr.opcode = grub_scsi_cmd_write16; + wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; + wr.lba = grub_cpu_to_be64 (sector); + wr.size = grub_cpu_to_be32 (size); + wr.reserved = 0; + wr.control = 0; + + err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense = grub_scsi_request_sense (scsi); + if (err_sense != GRUB_ERR_NONE) + grub_errno = err; + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; +} + + static int -grub_scsi_iterate (int (*hook) (const char *name)) +grub_scsi_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { grub_scsi_dev_t p; - auto int scsi_iterate (int bus, int luns); + auto int NESTED_FUNC_ATTR scsi_iterate (int id, int bus, int luns); - int scsi_iterate (int bus, int luns) + int NESTED_FUNC_ATTR scsi_iterate (int id, int bus, int luns) { int i; @@ -329,7 +439,7 @@ grub_scsi_iterate (int (*hook) (const char *name)) { char *sname; int ret; - sname = grub_xasprintf ("%s%d", p->name, bus); + sname = grub_xasprintf ("%s%d", grub_scsi_names[id], bus); if (!sname) return 1; ret = hook (sname); @@ -343,7 +453,7 @@ grub_scsi_iterate (int (*hook) (const char *name)) { char *sname; int ret; - sname = grub_xasprintf ("%s%d%c", p->name, bus, 'a' + i); + sname = grub_xasprintf ("%s%d%c", grub_scsi_names[id], bus, 'a' + i); if (!sname) return 1; ret = hook (sname); @@ -355,7 +465,7 @@ grub_scsi_iterate (int (*hook) (const char *name)) } for (p = grub_scsi_dev_list; p; p = p->next) - if (p->iterate && (p->iterate) (scsi_iterate)) + if (p->iterate && (p->iterate) (scsi_iterate, pull)) return 1; return 0; @@ -370,6 +480,7 @@ grub_scsi_open (const char *name, grub_disk_t disk) int lun, bus; grub_uint64_t maxtime; const char *nameend; + unsigned id; nameend = name + grub_strlen (name) - 1; /* Try to detect a LUN ('a'-'z'), otherwise just use the first @@ -394,15 +505,25 @@ grub_scsi_open (const char *name, grub_disk_t disk) if (! scsi) return grub_errno; + for (id = 0; id < ARRAY_SIZE (grub_scsi_names); id++) + if (grub_strncmp (grub_scsi_names[id], name, nameend - name) == 0) + break; + + if (id == ARRAY_SIZE (grub_scsi_names)) + { + grub_free (scsi); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk"); + } + for (p = grub_scsi_dev_list; p; p = p->next) { - if (grub_strncmp (p->name, name, nameend - name) != 0) - continue; + if (p->open (id, bus, scsi)) + { + grub_errno = GRUB_ERR_NONE; + continue; + } - if (p->open (bus, scsi)) - continue; - - disk->id = grub_make_scsi_id (p->id, bus, lun); + disk->id = grub_make_scsi_id (id, bus, lun); disk->data = scsi; scsi->dev = p; scsi->lun = lun; @@ -455,30 +576,45 @@ grub_scsi_open (const char *name, grub_disk_t disk) grub_errno = GRUB_ERR_NONE; /* Read capacity of media */ - err = grub_scsi_read_capacity (scsi); + err = grub_scsi_read_capacity10 (scsi); if (err) { grub_free (scsi); - grub_dprintf ("scsi", "READ CAPACITY failed\n"); + grub_dprintf ("scsi", "READ CAPACITY10 failed\n"); return err; } - /* SCSI blocks can be something else than 512, although GRUB - wants 512 byte blocks. */ - disk->total_sectors = ((grub_uint64_t)scsi->size - * (grub_uint64_t)scsi->blocksize) - >> GRUB_DISK_SECTOR_BITS; + if (scsi->last_block == 0xffffffff) + { + err = grub_scsi_read_capacity16 (scsi); + if (err) + { + grub_free (scsi); + grub_dprintf ("scsi", "READ CAPACITY16 failed\n"); + return err; + } + } - grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n", - scsi->size, scsi->blocksize); - grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n", + disk->total_sectors = scsi->last_block + 1; + if (scsi->blocksize & (scsi->blocksize - 1) || !scsi->blocksize) + { + grub_free (scsi); + return grub_error (GRUB_ERR_IO, "invalid sector size %d", + scsi->blocksize); + } + for (disk->log_sector_size = 0; + (1U << disk->log_sector_size) < scsi->blocksize; + disk->log_sector_size++); + + grub_dprintf ("scsi", "last_block=%" PRIuGRUB_UINT64_T ", blocksize=%u\n", + scsi->last_block, scsi->blocksize); + grub_dprintf ("scsi", "Disk total sectors = %llu\n", (unsigned long long) disk->total_sectors); return GRUB_ERR_NONE; } grub_free (scsi); - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk"); } @@ -501,36 +637,42 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector, scsi = disk->data; - /* SCSI sectors are variable in size. GRUB uses 512 byte - sectors. */ - if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE) + while (size) { - unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS; - if (! (spb != 0 && (scsi->blocksize & GRUB_DISK_SECTOR_SIZE) == 0)) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported SCSI block size"); + /* PATA doesn't support more than 32K reads. + Not sure about AHCI and USB. If it's confirmed that either of + them can do bigger reads reliably this value can be moved to 'scsi' + structure. */ + grub_size_t len = 32768 >> disk->log_sector_size; + grub_err_t err; + if (len > size) + len = size; + /* Depending on the type, select a read function. */ + switch (scsi->devtype) + { + case grub_scsi_devtype_direct: + if (sector >> 32) + err = grub_scsi_read16 (disk, sector, len, buf); + else + err = grub_scsi_read10 (disk, sector, len, buf); + if (err) + return err; + break; - grub_uint32_t sector_mod = 0; - sector = grub_divmod64 (sector, spb, §or_mod); - - if (! (sector_mod == 0 && size % spb == 0)) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unaligned SCSI read not supported"); - - size /= spb; + case grub_scsi_devtype_cdrom: + if (sector >> 32) + err = grub_scsi_read16 (disk, sector, len, buf); + else + err = grub_scsi_read12 (disk, sector, len, buf); + if (err) + return err; + break; + } + size -= len; + sector += len; + buf += len << disk->log_sector_size; } - /* Depending on the type, select a read function. */ - switch (scsi->devtype) - { - case grub_scsi_devtype_direct: - return grub_scsi_read10 (disk, sector, size, buf); - - case grub_scsi_devtype_cdrom: - return grub_scsi_read12 (disk, sector, size, buf); - } - - /* XXX: Never reached. */ return GRUB_ERR_NONE; #if 0 /* Workaround - it works - but very slowly, from some reason @@ -571,13 +713,41 @@ grub_scsi_write (grub_disk_t disk __attribute((unused)), grub_size_t size __attribute((unused)), const char *buf __attribute((unused))) { -#if 0 - /* XXX: Not tested yet! */ + grub_scsi_t scsi; - /* XXX: This should depend on the device type? */ - return grub_scsi_write10 (disk, sector, size, buf); -#endif - return GRUB_ERR_NOT_IMPLEMENTED_YET; + scsi = disk->data; + + if (scsi->devtype == grub_scsi_devtype_cdrom) + return grub_error (GRUB_ERR_IO, "no CD burning"); + + while (size) + { + /* PATA doesn't support more than 32K reads. + Not sure about AHCI and USB. If it's confirmed that either of + them can do bigger reads reliably this value can be moved to 'scsi' + structure. */ + grub_size_t len = 32768 >> disk->log_sector_size; + grub_err_t err; + if (len > size) + len = size; + /* Depending on the type, select a read function. */ + switch (scsi->devtype) + { + case grub_scsi_devtype_direct: + if (sector >> 32) + err = grub_scsi_write16 (disk, sector, len, buf); + else + err = grub_scsi_write10 (disk, sector, len, buf); + if (err) + return err; + break; + } + size -= len; + sector += len; + buf += len << disk->log_sector_size; + } + + return GRUB_ERR_NONE; } diff --git a/grub-core/disk/usbms.c b/grub-core/disk/usbms.c index 2bff40117..52cc33e93 100644 --- a/grub-core/disk/usbms.c +++ b/grub-core/disk/usbms.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_USBMS_DIRECTION_BIT 7 /* Length of CBI command should be always 12 bytes */ @@ -109,7 +111,11 @@ grub_usbms_cbi_reset (grub_usb_device_t dev, int interface) static grub_err_t grub_usbms_bo_reset (grub_usb_device_t dev, int interface) { - return grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0); + grub_usb_err_t u; + u = grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0); + if (u) + return grub_error (GRUB_ERR_IO, "USB error %d", u); + return GRUB_ERR_NONE; } static grub_err_t @@ -259,16 +265,20 @@ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno) static int -grub_usbms_iterate (int (*hook) (int bus, int luns)) +grub_usbms_iterate (int NESTED_FUNC_ATTR (*hook) (int id, int bus, int luns), + grub_disk_pull_t pull) { unsigned i; + if (pull != GRUB_DISK_PULL_NONE) + return 0; + grub_usb_poll_devices (); for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++) if (grub_usbms_devices[i]) { - if (hook (i, grub_usbms_devices[i]->luns)) + if (hook (GRUB_SCSI_SUBSYSTEM_USBMS, i, grub_usbms_devices[i]->luns)) return 1; } @@ -584,14 +594,18 @@ grub_usbms_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, static grub_err_t grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, - grub_size_t size, char *buf) + grub_size_t size, const char *buf) { - return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 1); + return grub_usbms_transfer (scsi, cmdsize, cmd, size, (char *) buf, 1); } static grub_err_t -grub_usbms_open (int devnum, struct grub_scsi *scsi) +grub_usbms_open (int id, int devnum, struct grub_scsi *scsi) { + if (id != GRUB_SCSI_SUBSYSTEM_USBMS) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "not USB Mass Storage device"); + grub_usb_poll_devices (); if (!grub_usbms_devices[devnum]) @@ -606,15 +620,13 @@ grub_usbms_open (int devnum, struct grub_scsi *scsi) static struct grub_scsi_dev grub_usbms_dev = { - .name = "usb", - .id = GRUB_SCSI_SUBSYSTEM_USBMS, .iterate = grub_usbms_iterate, .open = grub_usbms_open, .read = grub_usbms_read, .write = grub_usbms_write }; -struct grub_usb_attach_desc attach_hook = +static struct grub_usb_attach_desc attach_hook = { .class = GRUB_USB_CLASS_MASS_STORAGE, .hook = grub_usbms_attach diff --git a/grub-core/efiemu/i386/coredetect.c b/grub-core/efiemu/i386/coredetect.c index 975c4aa5d..c3782fda9 100644 --- a/grub-core/efiemu/i386/coredetect.c +++ b/grub-core/efiemu/i386/coredetect.c @@ -26,7 +26,7 @@ #define bit_LM (1 << 29) -char * +const char * grub_efiemu_get_default_core_name (void) { diff --git a/grub-core/efiemu/i386/pc/cfgtables.c b/grub-core/efiemu/i386/pc/cfgtables.c index 9287d3a94..7b6a40c87 100644 --- a/grub-core/efiemu/i386/pc/cfgtables.c +++ b/grub-core/efiemu/i386/pc/cfgtables.c @@ -24,7 +24,7 @@ #include grub_err_t -grub_machine_efiemu_init_tables () +grub_machine_efiemu_init_tables (void) { grub_uint8_t *ptr; void *table; diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c index ee78afe7d..f2c038110 100644 --- a/grub-core/efiemu/main.c +++ b/grub-core/efiemu/main.c @@ -32,6 +32,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* System table. Two version depending on mode */ grub_efi_system_table32_t *grub_efiemu_system_table32 = 0; grub_efi_system_table64_t *grub_efiemu_system_table64 = 0; @@ -147,7 +149,8 @@ grub_efiemu_register_configuration_table (grub_efi_guid_t guid, if (! get_table && ! data) return grub_error (GRUB_ERR_BAD_ARGUMENT, "you must set at least get_table or data"); - if ((err = grub_efiemu_unregister_configuration_table (guid))) + err = grub_efiemu_unregister_configuration_table (guid); + if (err) return err; tbl = (struct grub_efiemu_configuration_table *) grub_malloc (sizeof (*tbl)); @@ -191,7 +194,7 @@ grub_efiemu_load_file (const char *filename) file = grub_file_open (filename); if (! file) - return 0; + return grub_errno; err = grub_efiemu_mm_init (); if (err) @@ -224,7 +227,7 @@ grub_efiemu_autocore (void) { const char *prefix; char *filename; - char *suffix; + const char *suffix; grub_err_t err; if (grub_efiemu_sizeof_uintn_t () != 0) @@ -266,11 +269,13 @@ grub_efiemu_prepare (void) if (prepared) return GRUB_ERR_NONE; + err = grub_efiemu_autocore (); + if (err) + return err; + grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n", 8 * grub_efiemu_sizeof_uintn_t ()); - err = grub_efiemu_autocore (); - /* Create NVRAM. */ grub_efiemu_pnvram (); diff --git a/grub-core/efiemu/mm.c b/grub-core/efiemu/mm.c index 3c1dc2946..f9596f124 100644 --- a/grub-core/efiemu/mm.c +++ b/grub-core/efiemu/mm.c @@ -201,10 +201,10 @@ efiemu_alloc_requests (void) - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); if (align_overhead == GRUB_EFIEMU_PAGESIZE) align_overhead = 0; - curptr = ((grub_uint8_t *)curptr) + align_overhead; + curptr = ((grub_uint8_t *) curptr) + align_overhead; /* Add the region to memory map */ - grub_efiemu_add_to_mmap (PTR_TO_UINT64 (typestart), + grub_efiemu_add_to_mmap ((grub_addr_t) typestart, curptr - typestart, reqorder[i]); } @@ -404,7 +404,8 @@ grub_efiemu_mmap_fill (void) GRUB_EFI_ACPI_MEMORY_NVS); default: - grub_printf ("Unknown memory type %d. Assuming unusable\n", type); + grub_dprintf ("efiemu", + "Unknown memory type %d. Assuming unusable\n", type); case GRUB_MEMORY_RESERVED: return grub_efiemu_add_to_mmap (addr, size, GRUB_EFI_UNUSABLE_MEMORY); diff --git a/grub-core/efiemu/prepare.c b/grub-core/efiemu/prepare.c index 171e092c9..5c3146490 100644 --- a/grub-core/efiemu/prepare.c +++ b/grub-core/efiemu/prepare.c @@ -97,10 +97,9 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, grub_memcpy (&(conftables[i].vendor_guid), &(cur->guid), sizeof (cur->guid)); if (cur->get_table) - conftables[i].vendor_table - = PTR_TO_UINT64 (cur->get_table (cur->data)); + conftables[i].vendor_table = (grub_addr_t) cur->get_table (cur->data); else - conftables[i].vendor_table = PTR_TO_UINT64 (cur->data); + conftables[i].vendor_table = (grub_addr_t) cur->data; } err = SUFFIX (grub_efiemu_crc) (); diff --git a/grub-core/efiemu/runtime/efiemu.c b/grub-core/efiemu/runtime/efiemu.c index 73893414a..2c71fbed0 100644 --- a/grub-core/efiemu/runtime/efiemu.c +++ b/grub-core/efiemu/runtime/efiemu.c @@ -21,6 +21,12 @@ As it emulates only runtime serviceit isn't able to chainload EFI bootloader on non-EFI system (TODO) */ +#ifdef __i386__ +#include +#else +#include +#endif + #include #include #include @@ -369,16 +375,16 @@ grub_efi_status_t EFI_FUNC switch (cur_relloc->size) { case 8: - *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint64_t *) (grub_addr_t) cur_relloc->addr) += corr; break; case 4: - *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint32_t *) (grub_addr_t) cur_relloc->addr) += corr; break; case 2: - *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint16_t *) (grub_addr_t) cur_relloc->addr) += corr; break; case 1: - *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint8_t *) (grub_addr_t) cur_relloc->addr) += corr; break; } } diff --git a/grub-core/efiemu/symbols.c b/grub-core/efiemu/symbols.c index 4fc546b59..7137fcbd9 100644 --- a/grub-core/efiemu/symbols.c +++ b/grub-core/efiemu/symbols.c @@ -169,7 +169,7 @@ grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle, else ptv_rels[ptv_written].plustype = 0; - ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr); + ptv_rels[ptv_written].addr = (grub_addr_t) addr; ptv_rels[ptv_written].size = size; ptv_written++; @@ -179,10 +179,10 @@ grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle, /* Compute the value */ if (minus_handle) - value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle)); + value -= (grub_addr_t) grub_efiemu_mm_obtain_request (minus_handle); if (plus_handle) - value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle)); + value += (grub_addr_t) grub_efiemu_mm_obtain_request (plus_handle); /* Write the value */ switch (size) @@ -248,16 +248,16 @@ grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, switch (cur_relloc->size) { case 8: - *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint64_t *) (grub_addr_t) cur_relloc->addr) += corr; break; case 4: - *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint32_t *) (grub_addr_t) cur_relloc->addr) += corr; break; case 2: - *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint16_t *) (grub_addr_t) cur_relloc->addr) += corr; break; case 1: - *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr; + *((grub_uint8_t *) (grub_addr_t) cur_relloc->addr) += corr; break; } } diff --git a/grub-core/font/font.c b/grub-core/font/font.c index b5ec43bb2..8d74534ef 100644 --- a/grub-core/font/font.c +++ b/grub-core/font/font.c @@ -30,6 +30,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #ifdef USE_ASCII_FAILBACK #include "ascii.h" #endif @@ -248,8 +250,7 @@ open_section (grub_file_t file, struct font_file_section *section) } else if (retval < 0) { - grub_error (GRUB_ERR_BAD_FONT, - "font format error: can't read section name"); + /* Read error. */ return 1; } @@ -263,8 +264,7 @@ open_section (grub_file_t file, struct font_file_section *section) } else if (retval < 0) { - grub_error (GRUB_ERR_BAD_FONT, - "font format error: can't read section length"); + /* Read error. */ return 1; } @@ -314,10 +314,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct return 1; font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); if (!font->bmp_idx) - { - grub_free (font->char_index); - return 1; - } + return 1; grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); @@ -492,7 +489,7 @@ grub_font_load (const char *filename) #endif /* Allocate the font object. */ - font = (grub_font_t) grub_malloc (sizeof (struct grub_font)); + font = (grub_font_t) grub_zalloc (sizeof (struct grub_font)); if (!font) goto fail; @@ -609,7 +606,7 @@ grub_font_load (const char *filename) if (!font->name) { - grub_printf ("Note: Font has no name.\n"); + grub_dprintf ("font", "Font has no name.\n"); font->name = grub_strdup ("Unknown"); } @@ -638,6 +635,11 @@ grub_font_load (const char *filename) return 0; fail: + if (file) + grub_file_close (file); + if (font) + font->file = 0; + free_font (font); return 1; } @@ -797,6 +799,7 @@ free_font (grub_font_t font) grub_free (font->name); grub_free (font->family); grub_free (font->char_index); + grub_free (font->bmp_idx); grub_free (font); } } diff --git a/grub-core/font/font_cmd.c b/grub-core/font/font_cmd.c index 8b00dd8b9..b38eccd6d 100644 --- a/grub-core/font/font_cmd.c +++ b/grub-core/font/font_cmd.c @@ -33,7 +33,11 @@ loadfont_command (grub_command_t cmd __attribute__ ((unused)), while (argc--) if (grub_font_load (*args++) != 0) - return GRUB_ERR_BAD_FONT; + { + if (!grub_errno) + return grub_error (GRUB_ERR_BAD_FONT, "invalid font"); + return grub_errno; + } return GRUB_ERR_NONE; } @@ -45,7 +49,7 @@ lsfonts_command (grub_command_t cmd __attribute__ ((unused)), { struct grub_font_node *node; - grub_printf ("Loaded fonts:\n"); + grub_puts_ (N_("Loaded fonts:")); for (node = grub_font_list; node; node = node->next) { grub_font_t font = node->value; diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index 3dc80752d..7c7813729 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -25,6 +25,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* The affs bootblock. */ struct grub_affs_bblock @@ -50,12 +53,20 @@ struct grub_affs_rblock grub_uint32_t hashtable[1]; } __attribute__ ((packed)); +struct grub_affs_time +{ + grub_int32_t day; + grub_uint32_t min; + grub_uint32_t hz; +} __attribute__ ((packed)); + /* The second part of a file header block. */ struct grub_affs_file { grub_uint8_t unused1[12]; grub_uint32_t size; - grub_uint8_t unused2[104]; + grub_uint8_t unused2[92]; + struct grub_affs_time mtime; grub_uint8_t namelen; grub_uint8_t name[30]; grub_uint8_t unused3[33]; @@ -75,19 +86,19 @@ struct grub_affs_file #define GRUB_AFFS_BLOCKPTR_OFFSET 24 #define GRUB_AFFS_SYMLINK_OFFSET 24 -#define GRUB_AFFS_SYMLINK_SIZE(blocksize) ((blocksize) - 225) - -#define GRUB_AFFS_FILETYPE_DIR -3 -#define GRUB_AFFS_FILETYPE_REG 2 +#define GRUB_AFFS_FILETYPE_REG 0xfffffffd +#define GRUB_AFFS_FILETYPE_DIR 2 #define GRUB_AFFS_FILETYPE_SYMLINK 3 struct grub_fshelp_node { struct grub_affs_data *data; - int block; - int size; - int parent; + grub_uint32_t block; + struct grub_fshelp_node *parent; + struct grub_affs_file di; + grub_uint32_t *block_cache; + grub_uint32_t last_block_cache; }; /* Information about a "mounted" affs filesystem. */ @@ -110,32 +121,46 @@ static grub_dl_t my_mod; static grub_disk_addr_t grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { - int links; + grub_uint32_t target, curblock; grub_uint32_t pos; - int block = node->block; struct grub_affs_file file; struct grub_affs_data *data = node->data; - grub_uint32_t mod; + grub_uint64_t mod; + if (!node->block_cache) + { + node->block_cache = grub_malloc ((((grub_be_to_cpu32 (node->di.size) + + 511) >> 9) / data->htsize + 1) + * sizeof (node->block_cache[0])); + if (!node->block_cache) + return -1; + node->last_block_cache = 0; + node->block_cache[0] = node->block; + } + + /* Files are at most 2G on AFFS, so no need for 64-bit division. */ + target = (grub_uint32_t) fileblock / data->htsize; + mod = (grub_uint32_t) fileblock % data->htsize; /* Find the block that points to the fileblock we are looking up by following the chain until the right table is reached. */ - for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--) + for (curblock = node->last_block_cache + 1; curblock <= target; curblock++) { - grub_disk_read (data->disk, block + data->blocksize - 1, + grub_disk_read (data->disk, + node->block_cache[curblock - 1] + data->blocksize - 1, data->blocksize * (GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION), sizeof (file), &file); if (grub_errno) return 0; - block = grub_be_to_cpu32 (file.extension); + node->block_cache[curblock] = grub_be_to_cpu32 (file.extension); + node->last_block_cache = curblock; } /* Translate the fileblock to the block within the right table. */ - fileblock = mod; - grub_disk_read (data->disk, block, + grub_disk_read (data->disk, node->block_cache[target], GRUB_AFFS_BLOCKPTR_OFFSET - + (data->htsize - fileblock - 1) * sizeof (pos), + + (data->htsize - mod - 1) * sizeof (pos), sizeof (pos), &pos); if (grub_errno) return 0; @@ -143,21 +168,6 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) return grub_be_to_cpu32 (pos); } - -/* Read LEN bytes from the file described by DATA starting with byte - POS. Return the amount of read bytes in READ. */ -static grub_ssize_t -grub_affs_read_file (grub_fshelp_node_t node, - void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, - unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) -{ - return grub_fshelp_read_file (node->data->disk, node, read_hook, - pos, len, buf, grub_affs_read_block, - node->size, 0); -} - - static struct grub_affs_data * grub_affs_mount (grub_disk_t disk) { @@ -166,10 +176,9 @@ grub_affs_mount (grub_disk_t disk) struct grub_affs_rblock *rblock; int checksum = 0; - int checksumr = 0; int blocksize = 0; - data = grub_malloc (sizeof (struct grub_affs_data)); + data = grub_zalloc (sizeof (struct grub_affs_data)); if (!data) return 0; @@ -193,12 +202,6 @@ grub_affs_mount (grub_disk_t disk) goto fail; } - /* Read the bootblock. */ - grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock), - &data->bblock); - if (grub_errno) - goto fail; - /* No sane person uses more than 8KB for a block. At least I hope for that person because in that case this won't work. */ rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE * 16); @@ -208,7 +211,7 @@ grub_affs_mount (grub_disk_t disk) rblock = (struct grub_affs_rblock *) rootblock; /* Read the rootblock. */ - grub_disk_read (disk, (disk->total_sectors >> 1) + blocksize, 0, + grub_disk_read (disk, grub_be_to_cpu32 (data->bblock.rootblock), 0, GRUB_DISK_SECTOR_SIZE * 16, rootblock); if (grub_errno) goto fail; @@ -216,8 +219,6 @@ grub_affs_mount (grub_disk_t disk) /* The filesystem blocksize is not stored anywhere in the filesystem itself. One way to determine it is reading blocks for the rootblock until the checksum is correct. */ - checksumr = grub_be_to_cpu32 (rblock->checksum); - rblock->checksum = 0; for (blocksize = 0; blocksize < 8; blocksize++) { grub_uint32_t *currblock = rootblock + GRUB_DISK_SECTOR_SIZE * blocksize; @@ -226,10 +227,10 @@ grub_affs_mount (grub_disk_t disk) for (i = 0; i < GRUB_DISK_SECTOR_SIZE / sizeof (*currblock); i++) checksum += grub_be_to_cpu32 (currblock[i]); - if (checksumr == -checksum) + if (checksum == 0) break; } - if (-checksum != checksumr) + if (checksum != 0) { grub_error (GRUB_ERR_BAD_FS, "AFFS blocksize couldn't be determined"); goto fail; @@ -240,7 +241,9 @@ grub_affs_mount (grub_disk_t disk) data->disk = disk; data->htsize = grub_be_to_cpu32 (rblock->htsize); data->diropen.data = data; - data->diropen.block = (disk->total_sectors >> 1); + data->diropen.block = grub_be_to_cpu32 (data->bblock.rootblock); + data->diropen.parent = NULL; + grub_memcpy (&data->diropen.di, rootblock, sizeof (data->diropen.di)); grub_free (rootblock); @@ -261,18 +264,21 @@ grub_affs_read_symlink (grub_fshelp_node_t node) { struct grub_affs_data *data = node->data; char *symlink; + const grub_size_t symlink_size = (data->blocksize * GRUB_DISK_SECTOR_SIZE + - 225); - symlink = grub_malloc (GRUB_AFFS_SYMLINK_SIZE (data->blocksize)); + symlink = grub_malloc (symlink_size + 1); if (!symlink) return 0; grub_disk_read (data->disk, node->block, GRUB_AFFS_SYMLINK_OFFSET, - GRUB_AFFS_SYMLINK_SIZE (data->blocksize), symlink); + symlink_size, symlink); if (grub_errno) { grub_free (symlink); return 0; } + symlink[symlink_size] = 1; grub_dprintf ("affs", "Symlink: `%s'\n", symlink); return symlink; } @@ -291,25 +297,43 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, struct grub_affs_data *data = dir->data; grub_uint32_t *hashtable; - auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, int block, - int size, int type); + auto int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block, + const struct grub_affs_file *fil); - int NESTED_FUNC_ATTR grub_affs_create_node (const char *name, int block, - int size, int type) + int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block, + const struct grub_affs_file *fil) { - node = grub_malloc (sizeof (*node)); + int type; + grub_uint8_t name_u8[sizeof (fil->name) * GRUB_MAX_UTF8_PER_LATIN1 + 1]; + grub_size_t len; + + node = grub_zalloc (sizeof (*node)); if (!node) { grub_free (hashtable); return 1; } - node->data = data; - node->size = size; - node->block = block; - node->parent = grub_be_to_cpu32 (file.parent); + if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG) + type = GRUB_FSHELP_REG; + else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR) + type = GRUB_FSHELP_DIR; + else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + else + type = GRUB_FSHELP_UNKNOWN; - if (hook (name, type, node)) + node->data = data; + node->block = block; + node->di = *fil; + node->parent = dir; + + len = fil->namelen; + if (len > sizeof (fil->name)) + len = sizeof (fil->name); + *grub_latin1_to_utf8 (name_u8, fil->name, len) = '\0'; + + if (hook ((char *) name_u8, type, node)) { grub_free (hashtable); return 1; @@ -317,7 +341,25 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, return 0; } - hashtable = grub_malloc (data->htsize * sizeof (*hashtable)); + /* Create the directory entries for `.' and `..'. */ + node = grub_zalloc (sizeof (*node)); + if (!node) + return 1; + + *node = *dir; + if (hook (".", GRUB_FSHELP_DIR, node)) + return 1; + if (dir->parent) + { + node = grub_zalloc (sizeof (*node)); + if (!node) + return 1; + *node = *dir->parent; + if (hook ("..", GRUB_FSHELP_DIR, node)) + return 1; + } + + hashtable = grub_zalloc (data->htsize * sizeof (*hashtable)); if (!hashtable) return 1; @@ -326,17 +368,9 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, if (grub_errno) goto fail; - /* Create the directory entries for `.' and `..'. */ - if (grub_affs_create_node (".", dir->block, dir->size, GRUB_FSHELP_DIR)) - return 1; - if (grub_affs_create_node ("..", dir->parent ? dir->parent : dir->block, - dir->size, GRUB_FSHELP_DIR)) - return 1; - for (i = 0; i < data->htsize; i++) { - enum grub_fshelp_filetype type; - grub_uint64_t next; + grub_uint32_t next; if (!hashtable[i]) continue; @@ -354,19 +388,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, if (grub_errno) goto fail; - file.name[file.namelen] = '\0'; - - if ((int) grub_be_to_cpu32 (file.type) == GRUB_AFFS_FILETYPE_DIR) - type = GRUB_FSHELP_REG; - else if (grub_be_to_cpu32 (file.type) == GRUB_AFFS_FILETYPE_REG) - type = GRUB_FSHELP_DIR; - else if (grub_be_to_cpu32 (file.type) == GRUB_AFFS_FILETYPE_SYMLINK) - type = GRUB_FSHELP_SYMLINK; - else - type = GRUB_FSHELP_UNKNOWN; - - if (grub_affs_create_node ((char *) (file.name), next, - grub_be_to_cpu32 (file.size), type)) + if (grub_affs_create_node (next, &file)) return 1; next = grub_be_to_cpu32 (file.next); @@ -401,7 +423,7 @@ grub_affs_open (struct grub_file *file, const char *name) if (grub_errno) goto fail; - file->size = fdiro->size; + file->size = grub_be_to_cpu32 (fdiro->di.size); data->diropen = *fdiro; grub_free (fdiro); @@ -420,10 +442,13 @@ grub_affs_open (struct grub_file *file, const char *name) return grub_errno; } - static grub_err_t grub_affs_close (grub_file_t file) { + struct grub_affs_data *data = + (struct grub_affs_data *) file->data; + + grub_free (data->diropen.block_cache); grub_free (file->data); grub_dl_unref (my_mod); @@ -431,7 +456,6 @@ grub_affs_close (grub_file_t file) return GRUB_ERR_NONE; } - /* Read LEN bytes data from FILE into BUF. */ static grub_ssize_t grub_affs_read (grub_file_t file, char *buf, grub_size_t len) @@ -439,13 +463,12 @@ grub_affs_read (grub_file_t file, char *buf, grub_size_t len) struct grub_affs_data *data = (struct grub_affs_data *) file->data; - int size = grub_affs_read_file (&data->diropen, file->read_hook, - file->offset, len, buf); - - return size; + return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen, + file->read_hook, + file->offset, len, buf, grub_affs_read_block, + grub_be_to_cpu32 (data->diropen.di.size), 0); } - static grub_err_t grub_affs_dir (grub_device_t device, const char *path, int (*hook) (const char *filename, @@ -465,6 +488,11 @@ grub_affs_dir (grub_device_t device, const char *path, struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; + info.mtime = grub_be_to_cpu32 (node->di.mtime.day) * 86400 + + grub_be_to_cpu32 (node->di.mtime.min) * 60 + + grub_be_to_cpu32 (node->di.mtime.hz) / 50 + + 8 * 365 * 86400 + 86400 * 2; grub_free (node); return hook (filename, &info); } @@ -505,16 +533,22 @@ grub_affs_label (grub_device_t device, char **label) data = grub_affs_mount (disk); if (data) { + grub_size_t len; /* The rootblock maps quite well on a file header block, it's something we can use here. */ - grub_disk_read (data->disk, disk->total_sectors >> 1, + grub_disk_read (data->disk, grub_be_to_cpu32 (data->bblock.rootblock), data->blocksize * (GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION), sizeof (file), &file); if (grub_errno) return 0; - *label = grub_strndup ((char *) (file.name), file.namelen); + len = file.namelen; + if (len > sizeof (file.name)) + len = sizeof (file.name); + *label = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1); + if (*label) + *grub_latin1_to_utf8 ((grub_uint8_t *) *label, file.name, len) = '\0'; } else *label = 0; @@ -535,6 +569,9 @@ static struct grub_fs grub_affs_fs = .read = grub_affs_read, .close = grub_affs_close, .label = grub_affs_label, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, +#endif .next = 0 }; diff --git a/grub-core/fs/afs.c b/grub-core/fs/afs.c index cd61f4db9..00a5e3113 100644 --- a/grub-core/fs/afs.c +++ b/grub-core/fs/afs.c @@ -1,718 +1,3 @@ -/* afs.c - The native AtheOS file-system. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ +#define MODE_AFS 1 +#include "bfs.c" -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef MODE_BIGENDIAN -#define GRUB_AFS_FSNAME_SUFFIX "_be" -#else -#define GRUB_AFS_FSNAME_SUFFIX "" -#endif - -#ifdef MODE_BFS -#define GRUB_AFS_FSNAME "befs" GRUB_AFS_FSNAME_SUFFIX -#else -#define GRUB_AFS_FSNAME "afs" GRUB_AFS_FSNAME_SUFFIX -#endif - -#define GRUB_AFS_DIRECT_BLOCK_COUNT 12 -#define GRUB_AFS_BLOCKS_PER_DI_RUN 4 - -#ifdef MODE_BFS -#define GRUB_AFS_SBLOCK_SECTOR 1 -#define GRUB_AFS_SBLOCK_MAGIC1 0x42465331 /* BFS1. */ -#else -#define GRUB_AFS_SBLOCK_SECTOR 2 -#define GRUB_AFS_SBLOCK_MAGIC1 0x41465331 /* AFS1. */ -#endif - -#define GRUB_AFS_SBLOCK_MAGIC2 0xdd121031 -#define GRUB_AFS_SBLOCK_MAGIC3 0x15b6830e - -#define GRUB_AFS_INODE_MAGIC 0x64358428 - -#ifdef MODE_BFS -#define GRUB_AFS_BTREE_MAGIC 0x69f6c2e8 -#else -#define GRUB_AFS_BTREE_MAGIC 0x65768995 -#endif - -#define GRUB_AFS_BNODE_SIZE 1024 - -#define GRUB_AFS_S_IFMT 00170000 -#define GRUB_AFS_S_IFLNK 0120000 - -#define GRUB_AFS_S_IFREG 0100000 -#define GRUB_AFS_S_IFDIR 0040000 -#define GRUB_AFS_S_IFIFO 0010000 - -#define GRUB_AFS_NULL_VAL ((grub_afs_bvalue_t)-1) - -#ifdef MODE_BIGENDIAN -#define grub_afs_to_cpu16(x) grub_be_to_cpu16 (x) -#define grub_afs_to_cpu32(x) grub_be_to_cpu32 (x) -#define grub_afs_to_cpu64(x) grub_be_to_cpu64 (x) -#else -#define grub_afs_to_cpu16(x) grub_le_to_cpu16 (x) -#define grub_afs_to_cpu32(x) grub_le_to_cpu32 (x) -#define grub_afs_to_cpu64(x) grub_le_to_cpu64 (x) -#endif - -#ifdef MODE_BFS -#define B_KEY_INDEX_ALIGN 8 -#else -#define B_KEY_INDEX_ALIGN 4 -#endif - -#define B_KEY_INDEX_OFFSET(node) ((grub_uint16_t *) \ - ((char *) (node) \ - + ALIGN_UP (sizeof (struct grub_afs_bnode) \ - + node->key_size, \ - B_KEY_INDEX_ALIGN))) - -#define B_KEY_VALUE_OFFSET(node) ((grub_afs_bvalue_t *) \ - ((char *) B_KEY_INDEX_OFFSET (node) + \ - node->key_count * 2)) - -typedef grub_uint64_t grub_afs_off_t; -typedef grub_uint64_t grub_afs_bigtime; -typedef grub_uint64_t grub_afs_bvalue_t; - -struct grub_afs_blockrun -{ - grub_uint32_t group; - grub_uint16_t start; - grub_uint16_t len; -} __attribute__ ((packed)); - -struct grub_afs_datastream -{ - struct grub_afs_blockrun direct[GRUB_AFS_DIRECT_BLOCK_COUNT]; - grub_afs_off_t max_direct_range; - struct grub_afs_blockrun indirect; - grub_afs_off_t max_indirect_range; - struct grub_afs_blockrun double_indirect; - grub_afs_off_t max_double_indirect_range; - grub_afs_off_t size; -} __attribute__ ((packed)); - -struct grub_afs_bnode -{ - grub_afs_bvalue_t left; - grub_afs_bvalue_t right; - grub_afs_bvalue_t overflow; -#ifdef MODE_BFS - grub_uint16_t key_count; - grub_uint16_t key_size; -#else - grub_uint32_t key_count; - grub_uint32_t key_size; -#endif - char key_data[0]; -} __attribute__ ((packed)); - -#ifdef MODE_BFS -struct grub_afs_btree -{ - grub_uint32_t magic; - grub_uint32_t unused1; - grub_uint32_t tree_depth; - grub_uint32_t unused2; - grub_afs_bvalue_t root; - grub_uint32_t unused3[4]; -} __attribute__ ((packed)); -#else -struct grub_afs_btree -{ - grub_uint32_t magic; - grub_afs_bvalue_t root; - grub_uint32_t tree_depth; - grub_afs_bvalue_t last_node; - grub_afs_bvalue_t first_free; -} __attribute__ ((packed)); -#endif - -/* Beware that following structure describes AtheFS and if you write code - which uses currently unused fields check it with both AtheFS and BeFS. - */ -struct grub_afs_sblock -{ - char name[32]; - grub_uint32_t magic1; - grub_uint32_t byte_order; - grub_uint32_t block_size; - grub_uint32_t block_shift; - grub_afs_off_t num_blocks; - grub_afs_off_t used_blocks; - grub_uint32_t inode_size; - grub_uint32_t magic2; - grub_uint32_t block_per_group; /* Number of blocks per allocation - group. (Max 65536) */ - grub_uint32_t alloc_group_shift; /* Number of bits to shift a group - number to get a byte address. */ - grub_uint32_t alloc_group_count; - grub_uint32_t flags; - struct grub_afs_blockrun log_block; - grub_afs_off_t log_start; - grub_uint32_t valid_log_blocks; - grub_uint32_t log_size; - grub_uint32_t magic3; - struct grub_afs_blockrun root_dir; /* Root dir inode. */ - struct grub_afs_blockrun deleted_files; /* Directory containing files - scheduled for deletion. */ - struct grub_afs_blockrun index_dir; /* Directory of index files. */ - grub_uint32_t boot_loader_size; - grub_uint32_t pad[7]; -} __attribute__ ((packed)); - -struct grub_afs_inode -{ - grub_uint32_t magic1; - struct grub_afs_blockrun inode_num; - grub_uint32_t uid; - grub_uint32_t gid; - grub_uint32_t mode; - grub_uint32_t flags; -#ifndef MODE_BFS - grub_uint32_t link_count; -#endif - grub_afs_bigtime create_time; - grub_afs_bigtime modified_time; - struct grub_afs_blockrun parent; - struct grub_afs_blockrun attrib_dir; - grub_uint32_t index_type; /* Key data-key only used for index files. */ - grub_uint32_t inode_size; - grub_uint32_t unused; - struct grub_afs_datastream stream; - grub_uint32_t pad[4]; - grub_uint32_t small_data[1]; -} __attribute__ ((packed)); - -struct grub_fshelp_node -{ - struct grub_afs_data *data; - struct grub_afs_inode inode; -}; - -struct grub_afs_data -{ - grub_disk_t disk; - struct grub_afs_sblock sblock; - struct grub_afs_inode *inode; - struct grub_fshelp_node diropen; -}; - -static grub_dl_t my_mod; - -static grub_afs_off_t -grub_afs_run_to_num (struct grub_afs_sblock *sb, - struct grub_afs_blockrun *run) -{ - return ((grub_afs_off_t) grub_afs_to_cpu32 (run->group) - * sb->block_per_group + grub_afs_to_cpu16 (run->start)); -} - -static grub_err_t -grub_afs_read_inode (struct grub_afs_data *data, - grub_uint32_t ino, struct grub_afs_inode *inode) -{ - return grub_disk_read (data->disk, - ino * - (data->sblock.block_size >> GRUB_DISK_SECTOR_BITS), - 0, sizeof (struct grub_afs_inode), - inode); -} - -static grub_disk_addr_t -grub_afs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) -{ - struct grub_afs_sblock *sb = &node->data->sblock; - struct grub_afs_datastream *ds = &node->inode.stream; - - if (fileblock < grub_afs_to_cpu64 (ds->max_direct_range)) - { - int i; - - for (i = 0; i < GRUB_AFS_DIRECT_BLOCK_COUNT; i++) - { - if (fileblock < grub_afs_to_cpu16 (ds->direct[i].len)) - return grub_afs_run_to_num (sb, &ds->direct[i]) + fileblock; - fileblock -= grub_afs_to_cpu16 (ds->direct[i].len); - } - } - else if (fileblock < grub_afs_to_cpu64 (ds->max_indirect_range)) - { - int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun); - struct grub_afs_blockrun indir[ptrs_per_blk]; - grub_afs_off_t blk = grub_afs_run_to_num (sb, &ds->indirect); - int i; - - fileblock -= grub_afs_to_cpu64 (ds->max_direct_range); - for (i = 0; i < ds->indirect.len; i++, blk++) - { - int j; - - if (grub_disk_read (node->data->disk, - blk * (sb->block_size >> GRUB_DISK_SECTOR_BITS), - 0, sizeof (indir), - indir)) - return 0; - - for (j = 0; j < ptrs_per_blk; j++) - { - if (fileblock < grub_afs_to_cpu16 (indir[j].len)) - return grub_afs_run_to_num (sb, &indir[j]) + fileblock; - - fileblock -= grub_afs_to_cpu16 (indir[j].len); - } - } - } - else - { - int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun); - struct grub_afs_blockrun indir[ptrs_per_blk]; - - /* ([idblk][idptr]) ([dblk][dptr]) [blk] */ - int cur_pos = fileblock - grub_afs_to_cpu64 (ds->max_indirect_range); - - int dptr_size = GRUB_AFS_BLOCKS_PER_DI_RUN; - int dblk_size = dptr_size * ptrs_per_blk; - int idptr_size = dblk_size * GRUB_AFS_BLOCKS_PER_DI_RUN; - int idblk_size = idptr_size * ptrs_per_blk; - - int off = cur_pos % GRUB_AFS_BLOCKS_PER_DI_RUN; - int dptr = (cur_pos / dptr_size) % ptrs_per_blk; - int dblk = (cur_pos / dblk_size) % GRUB_AFS_BLOCKS_PER_DI_RUN; - int idptr = (cur_pos / idptr_size) % ptrs_per_blk; - int idblk = (cur_pos / idblk_size); - - if (grub_disk_read (node->data->disk, - (grub_afs_run_to_num (sb, &ds->double_indirect) - + idblk) * - (sb->block_size >> GRUB_DISK_SECTOR_BITS), - 0, sizeof (indir), - indir)) - return 0; - - if (grub_disk_read (node->data->disk, - (grub_afs_run_to_num (sb, &indir[idptr]) + dblk) * - (sb->block_size >> GRUB_DISK_SECTOR_BITS), - 0, sizeof (indir), - indir)) - return 0; - - return grub_afs_run_to_num (sb, &indir[dptr]) + off; - } - - return 0; -} - -static grub_ssize_t -grub_afs_read_file (grub_fshelp_node_t node, - void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, - unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) -{ - return grub_fshelp_read_file (node->data->disk, node, read_hook, - pos, len, buf, grub_afs_read_block, - grub_afs_to_cpu64 (node->inode.stream.size), - node->data->sblock.block_shift - - GRUB_DISK_SECTOR_BITS); -} - -static char * -grub_afs_read_symlink (grub_fshelp_node_t node) -{ - char *ret; - grub_afs_off_t size = grub_afs_to_cpu64 (node->inode.stream.size); - - if (size == 0) - { - size = sizeof (node->inode.stream); - ret = grub_zalloc (size + 1); - if (! ret) - return 0; - grub_memcpy (ret, (char *) &(node->inode.stream), - sizeof (node->inode.stream)); - return ret; - } - ret = grub_zalloc (size + 1); - if (! ret) - return 0; - grub_afs_read_file (node, 0, 0, size, ret); - return ret; -} - -static int -grub_afs_iterate_dir (grub_fshelp_node_t dir, - int NESTED_FUNC_ATTR - (*hook) (const char *filename, - enum grub_fshelp_filetype filetype, - grub_fshelp_node_t node)) -{ - struct grub_afs_btree head; - char node_data [GRUB_AFS_BNODE_SIZE]; - struct grub_afs_bnode *node = (struct grub_afs_bnode *) node_data; - int i; - - if ((dir->inode.stream.size == 0) - || ((grub_afs_to_cpu32 (dir->inode.mode) & GRUB_AFS_S_IFMT) - != GRUB_AFS_S_IFDIR)) - return 0; - - grub_afs_read_file (dir, 0, 0, sizeof (head), (char *) &head); - if (grub_errno) - return 0; - - grub_afs_read_file (dir, 0, grub_afs_to_cpu64 (head.root), - GRUB_AFS_BNODE_SIZE, (char *) node); - if (grub_errno) - return 0; - - for (i = 0; i < (int) grub_afs_to_cpu32 (head.tree_depth) - 1; i++) - { - grub_afs_bvalue_t blk; - - blk = grub_afs_to_cpu64(B_KEY_VALUE_OFFSET (node) [0]); - grub_afs_read_file (dir, 0, blk, GRUB_AFS_BNODE_SIZE, (char *) node); - if (grub_errno) - return 0; - } - - if (node->key_count) - { - grub_uint32_t cur_key = 0; - - while (1) - { - int key_start, key_size; - grub_uint16_t *index; - - index = B_KEY_INDEX_OFFSET (node); - - key_start = (cur_key > 0) - ? grub_afs_to_cpu16 (index[cur_key - 1]) : 0; - key_size = grub_afs_to_cpu16 (index[cur_key]) - key_start; - if (key_size > 0) - { - char filename [key_size + 1]; - struct grub_fshelp_node *fdiro; - int mode, type; - - fdiro = grub_malloc (sizeof (struct grub_fshelp_node)); - if (! fdiro) - return 0; - - fdiro->data = dir->data; - if (grub_afs_read_inode (dir->data, - grub_afs_to_cpu64 - (B_KEY_VALUE_OFFSET (node) [cur_key]), - &fdiro->inode)) - return 0; - - grub_memcpy (filename, &node->key_data[key_start], key_size); - filename [key_size] = 0; - - mode = (grub_afs_to_cpu32 (fdiro->inode.mode) & GRUB_AFS_S_IFMT); - if (mode == GRUB_AFS_S_IFDIR) - type = GRUB_FSHELP_DIR; - else if (mode == GRUB_AFS_S_IFREG) - type = GRUB_FSHELP_REG; - else if (mode == GRUB_AFS_S_IFLNK) - type = GRUB_FSHELP_SYMLINK; - else - type = GRUB_FSHELP_UNKNOWN; - - if (hook (filename, type, fdiro)) - return 1; - } - - cur_key++; - if (cur_key >= grub_afs_to_cpu32 (node->key_count)) - { - if (node->right == GRUB_AFS_NULL_VAL) - break; - - grub_afs_read_file (dir, 0, grub_afs_to_cpu64 (node->right), - GRUB_AFS_BNODE_SIZE, (char *) node); - if (grub_errno) - return 0; - - cur_key = 0; - } - } - } - - return 0; -} - -static int -grub_afs_validate_sblock (struct grub_afs_sblock *sb) -{ - if (grub_afs_to_cpu32 (sb->magic1) == GRUB_AFS_SBLOCK_MAGIC1) - { - sb->magic2 = grub_afs_to_cpu32 (sb->magic2); - sb->magic3 = grub_afs_to_cpu32 (sb->magic3); - sb->block_shift = grub_afs_to_cpu32 (sb->block_shift); - sb->block_size = grub_afs_to_cpu32 (sb->block_size); - sb->used_blocks = grub_afs_to_cpu64 (sb->used_blocks); - sb->num_blocks = grub_afs_to_cpu64 (sb->num_blocks); - sb->inode_size = grub_afs_to_cpu32 (sb->inode_size); - sb->alloc_group_count = grub_afs_to_cpu32 (sb->alloc_group_count); - sb->alloc_group_shift = grub_afs_to_cpu32 (sb->alloc_group_shift); - sb->block_per_group = grub_afs_to_cpu32 (sb->block_per_group); - sb->alloc_group_count = grub_afs_to_cpu32 (sb->alloc_group_count); - sb->log_size = grub_afs_to_cpu32 (sb->log_size); - } - else - return 0; - - if ((sb->magic2 != GRUB_AFS_SBLOCK_MAGIC2) || - (sb->magic3 != GRUB_AFS_SBLOCK_MAGIC3)) - return 0; - -#ifdef MODE_BFS - sb->block_per_group = 1 << (sb->alloc_group_shift); -#endif - - if (((grub_uint32_t) (1 << sb->block_shift) != sb->block_size) - || (sb->used_blocks > sb->num_blocks ) - || (sb->inode_size != sb->block_size) - || (0 == sb->block_size) -#ifndef MODE_BFS - || ((grub_uint32_t) (1 << sb->alloc_group_shift) != - sb->block_per_group * sb->block_size) - || (sb->alloc_group_count * sb->block_per_group < sb->num_blocks) - || (grub_afs_to_cpu16 (sb->log_block.len) != sb->log_size) - || (grub_afs_to_cpu32 (sb->valid_log_blocks) > sb->log_size) -#endif - ) - return 0; - - return 1; -} - -static struct grub_afs_data * -grub_afs_mount (grub_disk_t disk) -{ - struct grub_afs_data *data = 0; - - data = grub_malloc (sizeof (struct grub_afs_data)); - if (!data) - return 0; - - /* Read the superblock. */ - if (grub_disk_read (disk, GRUB_AFS_SBLOCK_SECTOR, 0, - sizeof (struct grub_afs_sblock), &data->sblock)) - goto fail; - - if (! grub_afs_validate_sblock (&data->sblock)) - goto fail; - - data->diropen.data = data; - data->inode = &data->diropen.inode; - data->disk = disk; - - if (grub_afs_read_inode (data, - grub_afs_run_to_num (&data->sblock, - &data->sblock.root_dir), - data->inode)) - goto fail; - - return data; - -fail: - grub_error (GRUB_ERR_BAD_FS, "not an " GRUB_AFS_FSNAME " filesystem"); - - grub_free (data); - return 0; -} - -static grub_err_t -grub_afs_open (struct grub_file *file, const char *name) -{ - struct grub_afs_data *data; - struct grub_fshelp_node *fdiro = 0; - - grub_dl_ref (my_mod); - - data = grub_afs_mount (file->device->disk); - if (! data) - goto fail; - - grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_afs_iterate_dir, - grub_afs_read_symlink, GRUB_FSHELP_REG); - if (grub_errno) - goto fail; - - grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_afs_inode)); - grub_free (fdiro); - - file->size = grub_afs_to_cpu64 (data->inode->stream.size); - file->data = data; - file->offset = 0; - - return 0; - -fail: - grub_free (data); - - grub_dl_unref (my_mod); - - return grub_errno; -} - -static grub_ssize_t -grub_afs_read (grub_file_t file, char *buf, grub_size_t len) -{ - struct grub_afs_data *data = (struct grub_afs_data *) file->data; - - return grub_afs_read_file (&data->diropen, file->read_hook, - file->offset, len, buf); -} - -static grub_err_t -grub_afs_close (grub_file_t file) -{ - grub_free (file->data); - - grub_dl_unref (my_mod); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_afs_dir (grub_device_t device, const char *path, - int (*hook) (const char *filename, - const struct grub_dirhook_info *info)) -{ - struct grub_afs_data *data = 0; - struct grub_fshelp_node *fdiro = 0; - - auto int NESTED_FUNC_ATTR iterate (const char *filename, - enum grub_fshelp_filetype filetype, - grub_fshelp_node_t node); - - int NESTED_FUNC_ATTR iterate (const char *filename, - enum grub_fshelp_filetype filetype, - grub_fshelp_node_t node) - { - struct grub_dirhook_info info; - grub_memset (&info, 0, sizeof (info)); - info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); - info.mtimeset = 1; -#ifdef MODE_BFS - info.mtime = grub_afs_to_cpu64 (node->inode.modified_time) >> 16; -#else - info.mtime = grub_divmod64 (grub_afs_to_cpu64 (node->inode.modified_time), - 1000000, 0); -#endif - grub_free (node); - return hook (filename, &info); - } - - grub_dl_ref (my_mod); - - data = grub_afs_mount (device->disk); - if (! data) - goto fail; - - grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_afs_iterate_dir, - grub_afs_read_symlink, GRUB_FSHELP_DIR); - if (grub_errno) - goto fail; - - grub_afs_iterate_dir (fdiro, iterate); - - if (fdiro != &data->diropen) - grub_free (fdiro); - - fail: - grub_free (data); - - grub_dl_unref (my_mod); - - return grub_errno; -} - -static grub_err_t -grub_afs_label (grub_device_t device, char **label) -{ - struct grub_afs_data *data; - grub_disk_t disk = device->disk; - - grub_dl_ref (my_mod); - - data = grub_afs_mount (disk); - if (data) - *label = grub_strndup (data->sblock.name, sizeof (data->sblock.name)); - else - *label = NULL; - - grub_dl_unref (my_mod); - - grub_free (data); - - return grub_errno; -} - - -static struct grub_fs grub_afs_fs = { - .name = GRUB_AFS_FSNAME, - .dir = grub_afs_dir, - .open = grub_afs_open, - .read = grub_afs_read, - .close = grub_afs_close, - .label = grub_afs_label, - .next = 0 -}; - -#if defined (MODE_BIGENDIAN) && defined (MODE_BFS) -GRUB_MOD_INIT (befs_be) -#elif defined (MODE_BFS) -GRUB_MOD_INIT (befs) -#elif defined (MODE_BIGENDIAN) -GRUB_MOD_INIT (afs_be) -#else -GRUB_MOD_INIT (afs) -#endif -{ - grub_fs_register (&grub_afs_fs); - my_mod = mod; -} - -#if defined (MODE_BIGENDIAN) && defined (MODE_BFS) -GRUB_MOD_FINI (befs_be) -#elif defined (MODE_BFS) -GRUB_MOD_FINI (befs) -#elif defined (MODE_BIGENDIAN) -GRUB_MOD_FINI (afs_be) -#else -GRUB_MOD_FINI (afs) -#endif -{ - grub_fs_unregister (&grub_afs_fs); -} diff --git a/grub-core/fs/befs.c b/grub-core/fs/befs.c deleted file mode 100644 index c54d8e1cc..000000000 --- a/grub-core/fs/befs.c +++ /dev/null @@ -1,3 +0,0 @@ -/* befs.c - The native BeOS/Haiku file-system. */ -#define MODE_BFS 1 -#include "afs.c" diff --git a/grub-core/fs/befs_be.c b/grub-core/fs/befs_be.c deleted file mode 100644 index f6e8179f4..000000000 --- a/grub-core/fs/befs_be.c +++ /dev/null @@ -1,4 +0,0 @@ -/* befs.c - The native BeOS/Haiku file-system. */ -#define MODE_BFS 1 -#define MODE_BIGENDIAN 1 -#include "afs.c" diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c new file mode 100644 index 000000000..fe8f991c4 --- /dev/null +++ b/grub-core/fs/bfs.c @@ -0,0 +1,1050 @@ +/* bfs.c - The Bee File System. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 book "Practical File System Design by Dominic Giampaolo + with corrections and completitions based on Haiku code. +*/ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef MODE_AFS +#define BTREE_ALIGN 4 +#define SUPERBLOCK 2 +#else +#define BTREE_ALIGN 8 +#define SUPERBLOCK 1 +#endif + +#define grub_bfs_to_cpu16 grub_le_to_cpu16 +#define grub_bfs_to_cpu32 grub_le_to_cpu32 +#define grub_bfs_to_cpu64 grub_le_to_cpu64 + +#ifdef MODE_AFS +#define grub_bfs_to_cpu_treehead grub_bfs_to_cpu32 +#else +#define grub_bfs_to_cpu_treehead grub_bfs_to_cpu16 +#endif + +#ifdef MODE_AFS +#define SUPER_BLOCK_MAGIC1 0x41465331 +#else +#define SUPER_BLOCK_MAGIC1 0x42465331 +#endif +#define SUPER_BLOCK_MAGIC2 0xdd121031 +#define SUPER_BLOCK_MAGIC3 0x15b6830e +#define POINTER_INVALID 0xffffffffffffffffULL + +#define ATTR_TYPE 0160000 +#define ATTR_REG 0100000 +#define ATTR_DIR 0040000 +#define ATTR_LNK 0120000 + +#define DOUBLE_INDIRECT_SHIFT 2 + +#define LOG_EXTENT_SIZE 3 +struct grub_bfs_extent +{ + grub_uint32_t ag; + grub_uint16_t start; + grub_uint16_t len; +} __attribute__ ((packed)); + +struct grub_bfs_superblock +{ + char label[32]; + grub_uint32_t magic1; + grub_uint32_t unused1; + grub_uint32_t bsize; + grub_uint32_t log2_bsize; + grub_uint8_t unused[20]; + grub_uint32_t magic2; + grub_uint32_t unused2; + grub_uint32_t log2_ag_size; + grub_uint8_t unused3[32]; + grub_uint32_t magic3; + struct grub_bfs_extent root_dir; +} __attribute__ ((packed)); + +struct grub_bfs_inode +{ + grub_uint8_t unused[20]; + grub_uint32_t mode; + grub_uint32_t flags; +#ifdef MODE_AFS + grub_uint8_t unused2[12]; +#else + grub_uint8_t unused2[8]; +#endif + grub_uint64_t mtime; + grub_uint8_t unused3[8]; + struct grub_bfs_extent attr; + grub_uint8_t unused4[12]; + + union + { + struct + { + struct grub_bfs_extent direct[12]; + grub_uint64_t max_direct_range; + struct grub_bfs_extent indirect; + grub_uint64_t max_indirect_range; + struct grub_bfs_extent double_indirect; + grub_uint64_t max_double_indirect_range; + grub_uint64_t size; + grub_uint32_t pad[4]; + } __attribute__ ((packed)); + char inplace_link[144]; + } __attribute__ ((packed)); + grub_uint8_t small_data[0]; +} __attribute__ ((packed)); + +enum +{ + LONG_SYMLINK = 0x40 +}; + +struct grub_bfs_small_data_element_header +{ + grub_uint32_t type; + grub_uint16_t name_len; + grub_uint16_t value_len; +} __attribute__ ((packed)); + +struct grub_bfs_btree_header +{ + grub_uint32_t magic; +#ifdef MODE_AFS + grub_uint64_t root; + grub_uint32_t level; + grub_uint32_t node_size; + grub_uint32_t unused; +#else + grub_uint32_t node_size; + grub_uint32_t level; + grub_uint32_t unused; + grub_uint64_t root; +#endif + grub_uint32_t unused2[2]; +} __attribute__ ((packed)); + +struct grub_bfs_btree_node +{ + grub_uint64_t unused; + grub_uint64_t right; + grub_uint64_t overflow; +#ifdef MODE_AFS + grub_uint32_t count_keys; + grub_uint32_t total_key_len; +#else + grub_uint16_t count_keys; + grub_uint16_t total_key_len; +#endif +} __attribute__ ((packed)); + +struct grub_bfs_data +{ + struct grub_bfs_superblock sb; + struct grub_bfs_inode ino[0]; +}; + +static grub_err_t +read_extent (grub_disk_t disk, + const struct grub_bfs_superblock *sb, + const struct grub_bfs_extent *in, + grub_off_t off, grub_off_t byteoff, void *buf, grub_size_t len) +{ +#ifdef MODE_AFS + return grub_disk_read (disk, ((grub_bfs_to_cpu32 (in->ag) + << (grub_bfs_to_cpu32 (sb->log2_ag_size) + - GRUB_DISK_SECTOR_BITS)) + + ((grub_bfs_to_cpu16 (in->start) + off) + << (grub_bfs_to_cpu32 (sb->log2_bsize) + - GRUB_DISK_SECTOR_BITS))), + byteoff, len, buf); +#else + return grub_disk_read (disk, (((grub_bfs_to_cpu32 (in->ag) + << grub_bfs_to_cpu32 (sb->log2_ag_size)) + + grub_bfs_to_cpu16 (in->start) + off) + << (grub_bfs_to_cpu32 (sb->log2_bsize) + - GRUB_DISK_SECTOR_BITS)), + byteoff, len, buf); +#endif +} + +#ifdef MODE_AFS +#define RANGE_SHIFT grub_bfs_to_cpu32 (sb->log2_bsize) +#else +#define RANGE_SHIFT 0 +#endif + +static grub_err_t +read_bfs_file (grub_disk_t disk, + const struct grub_bfs_superblock *sb, + const struct grub_bfs_inode *ino, + grub_off_t off, void *buf, grub_size_t len, + void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, + unsigned offset, + unsigned length)) +{ + if (len == 0) + return GRUB_ERR_NONE; + + if (off + len > grub_bfs_to_cpu64 (ino->size)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "attempt to read past the end of file"); + + if (off < (grub_bfs_to_cpu64 (ino->max_direct_range) << RANGE_SHIFT)) + { + unsigned i; + grub_uint64_t pos = 0; + for (i = 0; i < ARRAY_SIZE (ino->direct); i++) + { + grub_uint64_t newpos; + newpos = pos + (grub_bfs_to_cpu16 (ino->direct[i].len) + << grub_bfs_to_cpu32 (sb->log2_bsize)); + if (newpos > off) + { + grub_size_t read_size; + grub_err_t err; + read_size = newpos - off; + if (read_size > len) + read_size = len; + disk->read_hook = read_hook; + err = read_extent (disk, sb, &ino->direct[i], 0, off - pos, + buf, read_size); + disk->read_hook = 0; + if (err) + return err; + off += read_size; + len -= read_size; + buf = (char *) buf + read_size; + if (len == 0) + return GRUB_ERR_NONE; + } + pos = newpos; + } + } + + if (off < (grub_bfs_to_cpu64 (ino->max_direct_range) << RANGE_SHIFT)) + return grub_error (GRUB_ERR_BAD_FS, "incorrect direct blocks"); + + if (off < (grub_bfs_to_cpu64 (ino->max_indirect_range) << RANGE_SHIFT)) + { + unsigned i; + struct grub_bfs_extent *entries; + grub_size_t nentries; + grub_err_t err; + grub_uint64_t pos = (grub_bfs_to_cpu64 (ino->max_direct_range) + << RANGE_SHIFT); + nentries = (grub_bfs_to_cpu16 (ino->indirect.len) + << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE)); + entries = grub_malloc (nentries << LOG_EXTENT_SIZE); + if (!entries) + return grub_errno; + err = read_extent (disk, sb, &ino->indirect, 0, 0, + entries, nentries << LOG_EXTENT_SIZE); + for (i = 0; i < nentries; i++) + { + grub_uint64_t newpos; + newpos = pos + (grub_bfs_to_cpu16 (entries[i].len) + << grub_bfs_to_cpu32 (sb->log2_bsize)); + if (newpos > off) + { + grub_size_t read_size; + read_size = newpos - off; + if (read_size > len) + read_size = len; + disk->read_hook = read_hook; + err = read_extent (disk, sb, &entries[i], 0, off - pos, + buf, read_size); + disk->read_hook = 0; + if (err) + { + grub_free (entries); + return err; + } + off += read_size; + len -= read_size; + buf = (char *) buf + read_size; + if (len == 0) + { + grub_free (entries); + return GRUB_ERR_NONE; + } + } + pos = newpos; + } + grub_free (entries); + } + + if (off < (grub_bfs_to_cpu64 (ino->max_indirect_range) << RANGE_SHIFT)) + return grub_error (GRUB_ERR_BAD_FS, "incorrect indirect blocks"); + + { + struct grub_bfs_extent *l1_entries, *l2_entries; + grub_size_t nl1_entries, nl2_entries; + grub_off_t last_l1n = ~0ULL; + grub_err_t err; + nl1_entries = (grub_bfs_to_cpu16 (ino->double_indirect.len) + << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE)); + l1_entries = grub_malloc (nl1_entries << LOG_EXTENT_SIZE); + if (!l1_entries) + return grub_errno; + nl2_entries = 0; + l2_entries = grub_malloc (1 << (DOUBLE_INDIRECT_SHIFT + + grub_bfs_to_cpu32 (sb->log2_bsize))); + if (!l2_entries) + { + grub_free (l1_entries); + return grub_errno; + } + err = read_extent (disk, sb, &ino->double_indirect, 0, 0, + l1_entries, nl1_entries << LOG_EXTENT_SIZE); + if (err) + { + grub_free (l1_entries); + grub_free (l2_entries); + return err; + } + + while (len > 0) + { + grub_off_t boff, l2n, l1n; + grub_size_t read_size; + grub_off_t double_indirect_offset; + double_indirect_offset = off + - grub_bfs_to_cpu64 (ino->max_indirect_range); + boff = (double_indirect_offset + & ((1 << (grub_bfs_to_cpu32 (sb->log2_bsize) + + DOUBLE_INDIRECT_SHIFT)) - 1)); + l2n = ((double_indirect_offset >> (grub_bfs_to_cpu32 (sb->log2_bsize) + + DOUBLE_INDIRECT_SHIFT)) + & ((1 << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE + + DOUBLE_INDIRECT_SHIFT)) - 1)); + l1n = + (double_indirect_offset >> + (2 * grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE + + 2 * DOUBLE_INDIRECT_SHIFT)); + if (l1n > nl1_entries) + { + grub_free (l1_entries); + grub_free (l2_entries); + return grub_error (GRUB_ERR_BAD_FS, + "incorrect double-indirect block"); + } + if (l1n != last_l1n) + { + nl2_entries = (grub_bfs_to_cpu16 (l1_entries[l1n].len) + << (grub_bfs_to_cpu32 (sb->log2_bsize) + - LOG_EXTENT_SIZE)); + if (nl2_entries > (1U << (grub_bfs_to_cpu32 (sb->log2_bsize) + - LOG_EXTENT_SIZE + + DOUBLE_INDIRECT_SHIFT))) + nl2_entries = (1 << (grub_bfs_to_cpu32 (sb->log2_bsize) + - LOG_EXTENT_SIZE + + DOUBLE_INDIRECT_SHIFT)); + err = read_extent (disk, sb, &l1_entries[l1n], 0, 0, + l2_entries, nl2_entries << LOG_EXTENT_SIZE); + if (err) + { + grub_free (l1_entries); + grub_free (l2_entries); + return err; + } + last_l1n = l1n; + } + if (l2n > nl2_entries) + { + grub_free (l1_entries); + grub_free (l2_entries); + return grub_error (GRUB_ERR_BAD_FS, + "incorrect double-indirect block"); + } + + read_size = (1 << (grub_bfs_to_cpu32 (sb->log2_bsize) + + DOUBLE_INDIRECT_SHIFT)) - boff; + if (read_size > len) + read_size = len; + disk->read_hook = read_hook; + err = read_extent (disk, sb, &l2_entries[l2n], 0, boff, + buf, read_size); + disk->read_hook = 0; + if (err) + { + grub_free (l1_entries); + grub_free (l2_entries); + return err; + } + off += read_size; + len -= read_size; + buf = (char *) buf + read_size; + } + return GRUB_ERR_NONE; + } +} + +static int +iterate_in_b_tree (grub_disk_t disk, + const struct grub_bfs_superblock *sb, + const struct grub_bfs_inode *ino, + int (*hook) (const char *name, grub_uint64_t value)) +{ + struct grub_bfs_btree_header head; + grub_err_t err; + int level; + grub_uint64_t node_off; + + err = read_bfs_file (disk, sb, ino, 0, &head, sizeof (head), 0); + if (err) + return 0; + node_off = grub_bfs_to_cpu64 (head.root); + + level = grub_bfs_to_cpu32 (head.level) - 1; + while (level--) + { + struct grub_bfs_btree_node node; + grub_uint64_t key_value; + err = read_bfs_file (disk, sb, ino, node_off, &node, sizeof (node), 0); + if (err) + return 0; + err = read_bfs_file (disk, sb, ino, node_off + + ALIGN_UP (sizeof (node) + + grub_bfs_to_cpu_treehead (node. + total_key_len), + BTREE_ALIGN) + + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint16_t), &key_value, + sizeof (grub_uint64_t), 0); + if (err) + return 0; + + node_off = grub_bfs_to_cpu64 (key_value); + } + + while (1) + { + struct grub_bfs_btree_node node; + err = read_bfs_file (disk, sb, ino, node_off, &node, sizeof (node), 0); + if (err) + return 0; + { + char key_data[grub_bfs_to_cpu_treehead (node.total_key_len) + 1]; + grub_uint16_t keylen_idx[grub_bfs_to_cpu_treehead (node.count_keys)]; + grub_uint64_t key_values[grub_bfs_to_cpu_treehead (node.count_keys)]; + unsigned i; + grub_uint16_t start = 0, end = 0; + + err = + read_bfs_file (disk, sb, ino, node_off + sizeof (node), key_data, + grub_bfs_to_cpu_treehead (node.total_key_len), 0); + if (err) + return 0; + key_data[grub_bfs_to_cpu_treehead (node.total_key_len)] = 0; + err = read_bfs_file (disk, sb, ino, node_off + + ALIGN_UP (sizeof (node) + + grub_bfs_to_cpu_treehead + (node.total_key_len), BTREE_ALIGN), + keylen_idx, + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint16_t), 0); + if (err) + return 0; + err = read_bfs_file (disk, sb, ino, node_off + + ALIGN_UP (sizeof (node) + + grub_bfs_to_cpu_treehead + (node.total_key_len), + BTREE_ALIGN) + + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint16_t), key_values, + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint64_t), 0); + if (err) + return 0; + + for (i = 0; i < grub_bfs_to_cpu_treehead (node.count_keys); i++) + { + char c; + start = end; + end = grub_bfs_to_cpu16 (keylen_idx[i]); + if (grub_bfs_to_cpu_treehead (node.total_key_len) <= end) + end = grub_bfs_to_cpu_treehead (node.total_key_len); + c = key_data[end]; + key_data[end] = 0; + if (hook (key_data + start, grub_bfs_to_cpu64 (key_values[i]))) + return 1; + key_data[end] = c; + } + node_off = grub_bfs_to_cpu64 (node.right); + if (node_off == POINTER_INVALID) + return 0; + } + } +} + +static grub_err_t +find_in_b_tree (grub_disk_t disk, + const struct grub_bfs_superblock *sb, + const struct grub_bfs_inode *ino, const char *name, + grub_uint64_t * res) +{ + struct grub_bfs_btree_header head; + grub_err_t err; + int level; + grub_uint64_t node_off; + + err = read_bfs_file (disk, sb, ino, 0, &head, sizeof (head), 0); + if (err) + return err; + node_off = grub_bfs_to_cpu64 (head.root); + + level = grub_bfs_to_cpu32 (head.level) - 1; + while (1) + { + struct grub_bfs_btree_node node; + err = read_bfs_file (disk, sb, ino, node_off, &node, sizeof (node), 0); + if (err) + return err; + if (node.count_keys == 0) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", + name); + { + char key_data[grub_bfs_to_cpu_treehead (node.total_key_len) + 1]; + grub_uint16_t keylen_idx[grub_bfs_to_cpu_treehead (node.count_keys)]; + grub_uint64_t key_values[grub_bfs_to_cpu_treehead (node.count_keys)]; + unsigned i; + grub_uint16_t start = 0, end = 0; + err = + read_bfs_file (disk, sb, ino, node_off + sizeof (node), key_data, + grub_bfs_to_cpu_treehead (node.total_key_len), 0); + if (err) + return err; + key_data[grub_bfs_to_cpu_treehead (node.total_key_len)] = 0; + err = read_bfs_file (disk, sb, ino, node_off + + + ALIGN_UP (sizeof (node) + + grub_bfs_to_cpu_treehead (node. + total_key_len), + BTREE_ALIGN), keylen_idx, + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint16_t), 0); + if (err) + return err; + err = read_bfs_file (disk, sb, ino, node_off + + ALIGN_UP (sizeof (node) + + grub_bfs_to_cpu_treehead + (node.total_key_len), + BTREE_ALIGN) + + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint16_t), key_values, + grub_bfs_to_cpu_treehead (node.count_keys) * + sizeof (grub_uint64_t), 0); + if (err) + return err; + + for (i = 0; i < grub_bfs_to_cpu_treehead (node.count_keys); i++) + { + int cmp; + char c; + start = end; + end = grub_bfs_to_cpu16 (keylen_idx[i]); + if (grub_bfs_to_cpu_treehead (node.total_key_len) <= end) + end = grub_bfs_to_cpu_treehead (node.total_key_len); + c = key_data[end]; + key_data[end] = 0; + cmp = grub_strcmp (key_data + start, name); + key_data[end] = c; + if (cmp == 0 && level == 0) + { + *res = grub_bfs_to_cpu64 (key_values[i]); + return GRUB_ERR_NONE; + } + if (cmp >= 0 && level != 0) + { + node_off = grub_bfs_to_cpu64 (key_values[i]); + break; + } + } + if (i < grub_bfs_to_cpu_treehead (node.count_keys)) + { + level--; + continue; + } + if (node.overflow != POINTER_INVALID) + { + node_off = grub_bfs_to_cpu64 (node.overflow); + /* This level-- isn't specified but is needed. */ + level--; + continue; + } + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", + name); + } + } +} + +static grub_err_t +hop_level (grub_disk_t disk, + const struct grub_bfs_superblock *sb, + struct grub_bfs_inode *ino, const char *name) +{ + grub_err_t err; + grub_uint64_t res; + + if (((grub_bfs_to_cpu32 (ino->mode) & ATTR_TYPE) != ATTR_DIR)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + + err = find_in_b_tree (disk, sb, ino, name, &res); + if (err) + return err; + + return grub_disk_read (disk, res + << (grub_bfs_to_cpu32 (sb->log2_bsize) + - GRUB_DISK_SECTOR_BITS), 0, + grub_bfs_to_cpu32 (sb->bsize), (char *) ino); +} + +static grub_err_t +find_file (const char *path, grub_disk_t disk, + const struct grub_bfs_superblock *sb, struct grub_bfs_inode *ino) +{ + char *ptr, *ptr2; + char *alloc = NULL; + grub_err_t err; + union + { + struct grub_bfs_inode ino; + grub_uint8_t raw[grub_bfs_to_cpu32 (sb->bsize)]; + } old_ino; + unsigned symlinks_max = 32; + + err = read_extent (disk, sb, &sb->root_dir, 0, 0, ino, + grub_bfs_to_cpu32 (sb->bsize)); + if (err) + return err; + + ptr = (char *) path; + while (1) + { + while (*ptr == '/') + ptr++; + if (*ptr == 0) + { + grub_free (alloc); + return GRUB_ERR_NONE; + } + ptr2 = grub_strchr (ptr, '/'); + grub_memcpy (&old_ino, ino, grub_bfs_to_cpu32 (sb->bsize)); + if (ptr2) + { + char component[ptr2 - ptr + 1]; + grub_memcpy (component, ptr, ptr2 - ptr); + component[ptr2 - ptr] = 0; + err = hop_level (disk, sb, ino, component); + } + else + err = hop_level (disk, sb, ino, ptr); + if (err) + return err; + + if (((grub_bfs_to_cpu32 (ino->mode) & ATTR_TYPE) == ATTR_LNK)) + { + char *old_alloc = alloc; + if (--symlinks_max == 0) + { + grub_free (alloc); + return grub_error (GRUB_ERR_SYMLINK_LOOP, + "too deep nesting of symlinks"); + } + +#ifndef MODE_AFS + if (grub_bfs_to_cpu32 (ino->flags) & LONG_SYMLINK) +#endif + { + grub_size_t symsize = grub_bfs_to_cpu64 (ino->size); + alloc = grub_malloc ((ptr2 ? grub_strlen (ptr2) : 0) + + symsize + 1); + if (!alloc) + { + grub_free (alloc); + return grub_errno; + } + grub_free (old_alloc); + err = read_bfs_file (disk, sb, ino, 0, alloc, symsize, 0); + if (err) + { + grub_free (alloc); + return err; + } + alloc[symsize] = 0; + } +#ifndef MODE_AFS + else + { + alloc = grub_malloc ((ptr2 ? grub_strlen (ptr2) : 0) + + sizeof (ino->inplace_link) + 1); + if (!alloc) + { + grub_free (alloc); + return grub_errno; + } + grub_free (old_alloc); + grub_memcpy (alloc, ino->inplace_link, + sizeof (ino->inplace_link)); + alloc[sizeof (ino->inplace_link)] = 0; + } +#endif + if (alloc[0] == '/') + { + err = read_extent (disk, sb, &sb->root_dir, 0, 0, ino, + grub_bfs_to_cpu32 (sb->bsize)); + if (err) + { + grub_free (alloc); + return err; + } + } + else + grub_memcpy (ino, &old_ino, grub_bfs_to_cpu32 (sb->bsize)); + ptr = alloc + grub_strlen (alloc); + if (ptr2) + ptr = grub_stpcpy (ptr, ptr2); + *ptr = 0; + ptr = ptr2 = alloc; + continue; + } + + if (!ptr2) + { + grub_free (alloc); + return GRUB_ERR_NONE; + } + ptr = ptr2 + 1; + } +} + +static grub_err_t +mount (grub_disk_t disk, struct grub_bfs_superblock *sb) +{ + grub_err_t err; + err = grub_disk_read (disk, SUPERBLOCK, 0, sizeof (*sb), sb); + if (err == GRUB_ERR_OUT_OF_RANGE) + return grub_error (GRUB_ERR_BAD_FS, +#ifdef MODE_AFS + "not an AFS filesystem" +#else + "not a BFS filesystem" +#endif + ); + if (err) + return err; + if (grub_bfs_to_cpu32 (sb->magic1) != SUPER_BLOCK_MAGIC1 + || grub_bfs_to_cpu32 (sb->magic2) != SUPER_BLOCK_MAGIC2 + || grub_bfs_to_cpu32 (sb->magic3) != SUPER_BLOCK_MAGIC3 + || (grub_bfs_to_cpu32 (sb->bsize) + != (1U << grub_bfs_to_cpu32 (sb->log2_bsize)))) + return grub_error (GRUB_ERR_BAD_FS, +#ifdef MODE_AFS + "not an AFS filesystem" +#else + "not a BFS filesystem" +#endif + ); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bfs_dir (grub_device_t device, const char *path, + int (*hook_in) (const char *filename, + const struct grub_dirhook_info * info)) +{ + struct grub_bfs_superblock sb; + grub_err_t err; + auto int hook (const char *name, grub_uint64_t value); + + int hook (const char *name, grub_uint64_t value) + { + grub_err_t err2; + union + { + struct grub_bfs_inode ino; + grub_uint8_t raw[grub_bfs_to_cpu32 (sb.bsize)]; + } ino; + struct grub_dirhook_info info; + + err2 = grub_disk_read (device->disk, value + << (grub_bfs_to_cpu32 (sb.log2_bsize) + - GRUB_DISK_SECTOR_BITS), 0, + grub_bfs_to_cpu32 (sb.bsize), (char *) ino.raw); + if (err2) + { + grub_print_error (); + return 0; + } + + info.mtimeset = 1; +#ifdef MODE_AFS + info.mtime = + grub_divmod64 (grub_bfs_to_cpu64 (ino.ino.mtime), 1000000, 0); +#else + info.mtime = grub_bfs_to_cpu64 (ino.ino.mtime) >> 16; +#endif + info.dir = ((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) == ATTR_DIR); + return hook_in (name, &info); + } + err = mount (device->disk, &sb); + if (err) + return err; + + { + union + { + struct grub_bfs_inode ino; + grub_uint8_t raw[grub_bfs_to_cpu32 (sb.bsize)]; + } ino; + err = find_file (path, device->disk, &sb, &ino.ino); + if (err) + return err; + if (((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) != ATTR_DIR)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + iterate_in_b_tree (device->disk, &sb, &ino.ino, hook); + } + + return grub_errno; +} + +static grub_err_t +grub_bfs_open (struct grub_file *file, const char *name) +{ + struct grub_bfs_superblock sb; + grub_err_t err; + + err = mount (file->device->disk, &sb); + if (err) + return err; + + { + union + { + struct grub_bfs_inode ino; + grub_uint8_t raw[grub_bfs_to_cpu32 (sb.bsize)]; + } ino; + struct grub_bfs_data *data; + err = find_file (name, file->device->disk, &sb, &ino.ino); + if (err) + return err; + if (((grub_bfs_to_cpu32 (ino.ino.mode) & ATTR_TYPE) != ATTR_REG)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file"); + + data = grub_zalloc (sizeof (struct grub_bfs_data) + + grub_bfs_to_cpu32 (sb.bsize)); + if (!data) + return grub_errno; + data->sb = sb; + grub_memcpy (&data->ino, &ino, grub_bfs_to_cpu32 (sb.bsize)); + file->data = data; + file->size = grub_bfs_to_cpu64 (ino.ino.size); + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bfs_close (grub_file_t file) +{ + grub_free (file->data); + + return GRUB_ERR_NONE; +} + +static grub_ssize_t +grub_bfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + grub_err_t err; + struct grub_bfs_data *data = file->data; + + err = read_bfs_file (file->device->disk, &data->sb, + data->ino, file->offset, buf, len, file->read_hook); + if (err) + return -1; + return len; +} + +static grub_err_t +grub_bfs_label (grub_device_t device, char **label) +{ + struct grub_bfs_superblock sb; + grub_err_t err; + + *label = 0; + + err = mount (device->disk, &sb); + if (err) + return err; + + *label = grub_strndup (sb.label, sizeof (sb.label)); + return GRUB_ERR_NONE; +} + +#ifndef MODE_AFS +static grub_ssize_t +read_bfs_attr (grub_disk_t disk, + const struct grub_bfs_superblock *sb, + const struct grub_bfs_inode *ino, + const char *name, void *buf, grub_size_t len) +{ + grub_uint8_t *ptr = (grub_uint8_t *) ino->small_data; + grub_uint8_t *end = ((grub_uint8_t *) ino + grub_bfs_to_cpu32 (sb->bsize)); + + while (ptr + sizeof (struct grub_bfs_small_data_element_header) < end) + { + struct grub_bfs_small_data_element_header *el; + char *el_name; + grub_uint8_t *data; + el = (struct grub_bfs_small_data_element_header *) ptr; + if (el->name_len == 0) + break; + el_name = (char *) (el + 1); + data = (grub_uint8_t *) el_name + grub_bfs_to_cpu16 (el->name_len) + 3; + ptr = data + grub_bfs_to_cpu16 (el->value_len) + 1; + if (grub_memcmp (name, el_name, grub_bfs_to_cpu16 (el->name_len)) == 0 + && name[el->name_len] == 0) + { + grub_size_t copy; + copy = len; + if (grub_bfs_to_cpu16 (el->value_len) > copy) + copy = grub_bfs_to_cpu16 (el->value_len); + grub_memcpy (buf, data, copy); + return copy; + } + } + + if (ino->attr.len != 0) + { + union + { + struct grub_bfs_inode ino; + grub_uint8_t raw[grub_bfs_to_cpu32 (sb->bsize)]; + } ino2; + grub_size_t read; + grub_err_t err; + grub_uint64_t res; + + err = read_extent (disk, sb, &ino->attr, 0, 0, ino2.raw, + grub_bfs_to_cpu32 (sb->bsize)); + if (err) + return -1; + + err = find_in_b_tree (disk, sb, &ino2.ino, name, &res); + if (err) + return -1; + grub_disk_read (disk, res + << (grub_bfs_to_cpu32 (sb->log2_bsize) + - GRUB_DISK_SECTOR_BITS), 0, + grub_bfs_to_cpu32 (sb->bsize), (char *) &ino2); + read = grub_bfs_to_cpu64 (ino2.ino.size); + if (read > len) + read = len; + + err = read_bfs_file (disk, sb, &ino2.ino, 0, buf, read, 0); + if (err) + return -1; + return read; + } + return -1; +} + +static grub_err_t +grub_bfs_uuid (grub_device_t device, char **uuid) +{ + struct grub_bfs_superblock sb; + grub_err_t err; + + *uuid = 0; + + err = mount (device->disk, &sb); + if (err) + return err; + + { + union + { + struct grub_bfs_inode ino; + grub_uint8_t raw[grub_bfs_to_cpu32 (sb.bsize)]; + } ino; + grub_uint64_t vid; + + err = read_extent (device->disk, &sb, &sb.root_dir, 0, 0, + &ino, grub_bfs_to_cpu32 (sb.bsize)); + if (err) + return err; + if (read_bfs_attr (device->disk, &sb, &ino.ino, "be:volume_id", + &vid, sizeof (vid)) == sizeof (vid)) + *uuid = + grub_xasprintf ("%016" PRIxGRUB_UINT64_T, grub_bfs_to_cpu64 (vid)); + } + return GRUB_ERR_NONE; +} +#endif + +static struct grub_fs grub_bfs_fs = { +#ifdef MODE_AFS + .name = "afs", +#else + .name = "bfs", +#endif + .dir = grub_bfs_dir, + .open = grub_bfs_open, + .read = grub_bfs_read, + .close = grub_bfs_close, + .label = grub_bfs_label, +#ifndef MODE_AFS + .uuid = grub_bfs_uuid, +#endif +#ifdef GRUB_UTIL + .reserved_first_sector = 1, +#endif +}; + +#ifdef MODE_AFS +GRUB_MOD_INIT (afs) +#else +GRUB_MOD_INIT (bfs) +#endif +{ + COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE == + sizeof (struct grub_bfs_extent)); + grub_fs_register (&grub_bfs_fs); +} + +#ifdef MODE_AFS +GRUB_MOD_FINI (afs) +#else +GRUB_MOD_FINI (bfs) +#endif +{ + grub_fs_unregister (&grub_bfs_fs); +} diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c index a50bae000..3660b60ac 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -24,69 +24,1551 @@ #include #include #include +#include +#include +#include -#define BTRFS_SIGNATURE "_BHRfS_M" +GRUB_MOD_LICENSE ("GPLv3+"); -struct btrfs_superblock -{ - grub_uint8_t dummy1[32]; - grub_uint16_t uuid[8]; - grub_uint8_t dummy2[16]; - grub_uint8_t signature[sizeof (BTRFS_SIGNATURE) - 1]; +#define GRUB_BTRFS_SIGNATURE "_BHRfS_M" + +/* From http://www.oberhumer.com/opensource/lzo/lzofaq.php + * LZO will expand incompressible data by a little amount. I still haven't + * computed the exact values, but I suggest using these formulas for + * a worst-case expansion calculation: + * + * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + * */ +#define GRUB_BTRFS_LZO_BLOCK_SIZE 4096 +#define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \ + (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3) + +typedef grub_uint8_t grub_btrfs_checksum_t[0x20]; +typedef grub_uint16_t grub_btrfs_uuid_t[8]; + +struct grub_btrfs_device +{ + grub_uint64_t device_id; + grub_uint64_t size; + grub_uint8_t dummy[0x62 - 0x10]; } __attribute__ ((packed)); +struct grub_btrfs_superblock +{ + grub_btrfs_checksum_t checksum; + grub_btrfs_uuid_t uuid; + grub_uint8_t dummy[0x10]; + grub_uint8_t signature[sizeof (GRUB_BTRFS_SIGNATURE) - 1]; + grub_uint64_t generation; + grub_uint64_t root_tree; + grub_uint64_t chunk_tree; + grub_uint8_t dummy2[0x20]; + grub_uint64_t root_dir_objectid; + grub_uint8_t dummy3[0x41]; + struct grub_btrfs_device this_device; + char label[0x100]; + grub_uint8_t dummy4[0x100]; + grub_uint8_t bootstrap_mapping[0x800]; +} __attribute__ ((packed)); + +struct btrfs_header +{ + grub_btrfs_checksum_t checksum; + grub_btrfs_uuid_t uuid; + grub_uint8_t dummy[0x30]; + grub_uint32_t nitems; + grub_uint8_t level; +} __attribute__ ((packed)); + +struct grub_btrfs_device_desc +{ + grub_device_t dev; + grub_uint64_t id; +}; + struct grub_btrfs_data { - struct btrfs_superblock sblock; + struct grub_btrfs_superblock sblock; + grub_uint64_t tree; + grub_uint64_t inode; + + struct grub_btrfs_device_desc *devices_attached; + unsigned n_devices_attached; + unsigned n_devices_allocated; + + /* Cached extent data. */ + grub_uint64_t extstart; + grub_uint64_t extend; + grub_uint64_t extino; + grub_uint64_t exttree; + grub_size_t extsize; + struct grub_btrfs_extent_data *extent; }; -static struct grub_btrfs_data * -grub_btrfs_mount (grub_disk_t disk) +struct grub_btrfs_key { - struct grub_btrfs_data *data = grub_malloc (sizeof (*data)); - if (! data) - return NULL; + grub_uint64_t object_id; +#define GRUB_BTRFS_ITEM_TYPE_INODE_ITEM 0x01 +#define GRUB_BTRFS_ITEM_TYPE_DIR_ITEM 0x54 +#define GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM 0x6c +#define GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM 0x84 +#define GRUB_BTRFS_ITEM_TYPE_DEVICE 0xd8 +#define GRUB_BTRFS_ITEM_TYPE_CHUNK 0xe4 + grub_uint8_t type; + grub_uint64_t offset; +} __attribute__ ((packed)); - if (grub_disk_read (disk, 128, 0, sizeof (data->sblock), - &data->sblock) != GRUB_ERR_NONE) - goto fail; +struct grub_btrfs_chunk_item +{ + grub_uint64_t size; + grub_uint64_t dummy; + grub_uint64_t stripe_length; + grub_uint64_t type; +#define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07 +#define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00 +#define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08 +#define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10 +#define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20 +#define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40 + grub_uint8_t dummy2[0xc]; + grub_uint16_t nstripes; + grub_uint16_t nsubstripes; +} __attribute__ ((packed)); - if (grub_strncmp ((char *) data->sblock.signature, BTRFS_SIGNATURE, sizeof (BTRFS_SIGNATURE) - 1)) +struct grub_btrfs_chunk_stripe +{ + grub_uint64_t device_id; + grub_uint64_t offset; + grub_btrfs_uuid_t device_uuid; +} __attribute__ ((packed)); + +struct grub_btrfs_leaf_node +{ + struct grub_btrfs_key key; + grub_uint32_t offset; + grub_uint32_t size; +} __attribute__ ((packed)); + +struct grub_btrfs_internal_node +{ + struct grub_btrfs_key key; + grub_uint64_t addr; + grub_uint64_t dummy; +} __attribute__ ((packed)); + +struct grub_btrfs_dir_item +{ + struct grub_btrfs_key key; + grub_uint8_t dummy[8]; + grub_uint16_t m; + grub_uint16_t n; +#define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1 +#define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2 +#define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7 + grub_uint8_t type; + char name[0]; +} __attribute__ ((packed)); + +struct grub_btrfs_leaf_descriptor +{ + unsigned depth; + unsigned allocated; + struct + { + grub_disk_addr_t addr; + unsigned iter; + unsigned maxiter; + int leaf; + } *data; +}; + +struct grub_btrfs_root_item +{ + grub_uint8_t dummy[0xb0]; + grub_uint64_t tree; + grub_uint64_t inode; +}; + +struct grub_btrfs_time +{ + grub_int64_t sec; + grub_uint32_t nanosec; +} __attribute__ ((aligned (4))); + +struct grub_btrfs_inode +{ + grub_uint8_t dummy1[0x10]; + grub_uint64_t size; + grub_uint8_t dummy2[0x70]; + struct grub_btrfs_time mtime; +} __attribute__ ((packed)); + +struct grub_btrfs_extent_data +{ + grub_uint64_t dummy; + grub_uint64_t size; + grub_uint8_t compression; + grub_uint8_t encryption; + grub_uint16_t encoding; + grub_uint8_t type; + union + { + char inl[0]; + struct { - grub_error (GRUB_ERR_BAD_FS, "not a Btrfs filesystem"); - goto fail; + grub_uint64_t laddr; + grub_uint64_t compressed_size; + grub_uint64_t offset; + grub_uint64_t filled; + }; + }; +} __attribute__ ((packed)); + +#define GRUB_BTRFS_EXTENT_INLINE 0 +#define GRUB_BTRFS_EXTENT_REGULAR 1 + +#define GRUB_BTRFS_COMPRESSION_NONE 0 +#define GRUB_BTRFS_COMPRESSION_ZLIB 1 +#define GRUB_BTRFS_COMPRESSION_LZO 2 + +#define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + +static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 +}; + +static grub_err_t +grub_btrfs_read_logical (struct grub_btrfs_data *data, + grub_disk_addr_t addr, void *buf, grub_size_t size); + +static grub_err_t +read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +{ + unsigned i; + grub_err_t err = GRUB_ERR_NONE; + for (i = 0; i < ARRAY_SIZE (superblock_sectors); i++) + { + struct grub_btrfs_superblock sblock; + /* Don't try additional superblocks beyond device size. */ + if (i && (grub_le_to_cpu64 (sblock.this_device.size) + >> GRUB_DISK_SECTOR_BITS) <= superblock_sectors[i]) + break; + err = grub_disk_read (disk, superblock_sectors[i], 0, + sizeof (sblock), &sblock); + if (err == GRUB_ERR_OUT_OF_RANGE) + break; + + if (grub_memcmp ((char *) sblock.signature, GRUB_BTRFS_SIGNATURE, + sizeof (GRUB_BTRFS_SIGNATURE) - 1) != 0) + break; + if (i == 0 || grub_le_to_cpu64 (sblock.generation) + > grub_le_to_cpu64 (sb->generation)) + grub_memcpy (sb, &sblock, sizeof (sblock)); } + if ((err == GRUB_ERR_OUT_OF_RANGE || !err) && i == 0) + return grub_error (GRUB_ERR_BAD_FS, "not a Btrfs filesystem"); + + if (err == GRUB_ERR_OUT_OF_RANGE) + grub_errno = err = GRUB_ERR_NONE; + + return err; +} + +static int +key_cmp (const struct grub_btrfs_key *a, const struct grub_btrfs_key *b) +{ + if (grub_cpu_to_le64 (a->object_id) < grub_cpu_to_le64 (b->object_id)) + return -1; + if (grub_cpu_to_le64 (a->object_id) > grub_cpu_to_le64 (b->object_id)) + return +1; + + if (a->type < b->type) + return -1; + if (a->type > b->type) + return +1; + + if (grub_cpu_to_le64 (a->offset) < grub_cpu_to_le64 (b->offset)) + return -1; + if (grub_cpu_to_le64 (a->offset) > grub_cpu_to_le64 (b->offset)) + return +1; + return 0; +} + +static void +free_iterator (struct grub_btrfs_leaf_descriptor *desc) +{ + grub_free (desc->data); +} + +static grub_err_t +save_ref (struct grub_btrfs_leaf_descriptor *desc, + grub_disk_addr_t addr, unsigned i, unsigned m, int l) +{ + desc->depth++; + if (desc->allocated < desc->depth) + { + void *newdata; + desc->allocated *= 2; + newdata = grub_realloc (desc->data, sizeof (desc->data[0]) + * desc->allocated); + if (!newdata) + return grub_errno; + desc->data = newdata; + } + desc->data[desc->depth - 1].addr = addr; + desc->data[desc->depth - 1].iter = i; + desc->data[desc->depth - 1].maxiter = m; + desc->data[desc->depth - 1].leaf = l; + return GRUB_ERR_NONE; +} + +static int +next (struct grub_btrfs_data *data, + struct grub_btrfs_leaf_descriptor *desc, + grub_disk_addr_t * outaddr, grub_size_t * outsize, + struct grub_btrfs_key *key_out) +{ + grub_err_t err; + struct grub_btrfs_leaf_node leaf; + + for (; desc->depth > 0; desc->depth--) + { + desc->data[desc->depth - 1].iter++; + if (desc->data[desc->depth - 1].iter + < desc->data[desc->depth - 1].maxiter) + break; + } + if (desc->depth == 0) + return 0; + while (!desc->data[desc->depth - 1].leaf) + { + struct grub_btrfs_internal_node node; + struct btrfs_header head; + + err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter + * sizeof (node) + + sizeof (struct btrfs_header) + + desc->data[desc->depth - 1].addr, + &node, sizeof (node)); + if (err) + return -err; + + err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (node.addr), + &head, sizeof (head)); + if (err) + return -err; + + save_ref (desc, grub_le_to_cpu64 (node.addr), 0, + grub_le_to_cpu32 (head.nitems), !head.level); + } + err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter + * sizeof (leaf) + + sizeof (struct btrfs_header) + + desc->data[desc->depth - 1].addr, &leaf, + sizeof (leaf)); + if (err) + return -err; + *outsize = grub_le_to_cpu32 (leaf.size); + *outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header) + + grub_le_to_cpu32 (leaf.offset); + *key_out = leaf.key; + return 1; +} + +static grub_err_t +lower_bound (struct grub_btrfs_data *data, + const struct grub_btrfs_key *key_in, + struct grub_btrfs_key *key_out, + grub_disk_addr_t root, + grub_disk_addr_t *outaddr, grub_size_t *outsize, + struct grub_btrfs_leaf_descriptor *desc) +{ + grub_disk_addr_t addr = root; + int depth = -1; + + if (desc) + { + desc->allocated = 16; + desc->depth = 0; + desc->data = grub_malloc (sizeof (desc->data[0]) * desc->allocated); + if (!desc->data) + return grub_errno; + } + + grub_dprintf ("btrfs", + "retrieving %" PRIxGRUB_UINT64_T + " %x %" PRIxGRUB_UINT64_T "\n", + key_in->object_id, key_in->type, key_in->offset); + + while (1) + { + grub_err_t err; + struct btrfs_header head; + + reiter: + depth++; + /* FIXME: preread few nodes into buffer. */ + err = grub_btrfs_read_logical (data, addr, &head, sizeof (head)); + if (err) + return err; + addr += sizeof (head); + if (head.level) + { + unsigned i; + struct grub_btrfs_internal_node node, node_last; + int have_last = 0; + grub_memset (&node_last, 0, sizeof (node_last)); + for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++) + { + err = grub_btrfs_read_logical (data, addr + i * sizeof (node), + &node, sizeof (node)); + if (err) + return err; + + grub_dprintf ("btrfs", + "internal node (depth %d) %" PRIxGRUB_UINT64_T + " %x %" PRIxGRUB_UINT64_T "\n", depth, + node.key.object_id, node.key.type, + node.key.offset); + + if (key_cmp (&node.key, key_in) == 0) + { + err = GRUB_ERR_NONE; + if (desc) + err = save_ref (desc, addr - sizeof (head), i, + grub_le_to_cpu32 (head.nitems), 0); + if (err) + return err; + addr = grub_le_to_cpu64 (node.addr); + goto reiter; + } + if (key_cmp (&node.key, key_in) > 0) + break; + node_last = node; + have_last = 1; + } + if (have_last) + { + err = GRUB_ERR_NONE; + if (desc) + err = save_ref (desc, addr - sizeof (head), i - 1, + grub_le_to_cpu32 (head.nitems), 0); + if (err) + return err; + addr = grub_le_to_cpu64 (node_last.addr); + goto reiter; + } + *outsize = 0; + *outaddr = 0; + grub_memset (key_out, 0, sizeof (*key_out)); + if (desc) + return save_ref (desc, addr - sizeof (head), -1, + grub_le_to_cpu32 (head.nitems), 0); + return GRUB_ERR_NONE; + } + { + unsigned i; + struct grub_btrfs_leaf_node leaf, leaf_last; + int have_last = 0; + for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++) + { + err = grub_btrfs_read_logical (data, addr + i * sizeof (leaf), + &leaf, sizeof (leaf)); + if (err) + return err; + + grub_dprintf ("btrfs", + "leaf (depth %d) %" PRIxGRUB_UINT64_T + " %x %" PRIxGRUB_UINT64_T "\n", depth, + leaf.key.object_id, leaf.key.type, leaf.key.offset); + + if (key_cmp (&leaf.key, key_in) == 0) + { + grub_memcpy (key_out, &leaf.key, sizeof (*key_out)); + *outsize = grub_le_to_cpu32 (leaf.size); + *outaddr = addr + grub_le_to_cpu32 (leaf.offset); + if (desc) + return save_ref (desc, addr - sizeof (head), i, + grub_le_to_cpu32 (head.nitems), 1); + return GRUB_ERR_NONE; + } + + if (key_cmp (&leaf.key, key_in) > 0) + break; + + have_last = 1; + leaf_last = leaf; + } + + if (have_last) + { + grub_memcpy (key_out, &leaf_last.key, sizeof (*key_out)); + *outsize = grub_le_to_cpu32 (leaf_last.size); + *outaddr = addr + grub_le_to_cpu32 (leaf_last.offset); + if (desc) + return save_ref (desc, addr - sizeof (head), i - 1, + grub_le_to_cpu32 (head.nitems), 1); + return GRUB_ERR_NONE; + } + *outsize = 0; + *outaddr = 0; + grub_memset (key_out, 0, sizeof (*key_out)); + if (desc) + return save_ref (desc, addr - sizeof (head), -1, + grub_le_to_cpu32 (head.nitems), 1); + return GRUB_ERR_NONE; + } + } +} + +static grub_device_t +find_device (struct grub_btrfs_data *data, grub_uint64_t id, int do_rescan) +{ + grub_device_t dev_found = NULL; + auto int hook (const char *name); + int hook (const char *name) + { + grub_device_t dev; + grub_err_t err; + struct grub_btrfs_superblock sb; + dev = grub_device_open (name); + if (!dev) + return 0; + if (!dev->disk) + { + grub_device_close (dev); + return 0; + } + err = read_sblock (dev->disk, &sb); + if (err == GRUB_ERR_BAD_FS) + { + grub_device_close (dev); + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (err) + { + grub_device_close (dev); + grub_print_error (); + return 0; + } + if (grub_memcmp (data->sblock.uuid, sb.uuid, sizeof (sb.uuid)) != 0 + || sb.this_device.device_id != id) + { + grub_device_close (dev); + return 0; + } + + dev_found = dev; + return 1; + } + + unsigned i; + + for (i = 0; i < data->n_devices_attached; i++) + if (id == data->devices_attached[i].id) + return data->devices_attached[i].dev; + if (do_rescan) + grub_device_iterate (hook); + if (!dev_found) + { + grub_error (GRUB_ERR_BAD_FS, "couldn't find a member device"); + return NULL; + } + data->n_devices_attached++; + if (data->n_devices_attached > data->n_devices_allocated) + { + void *tmp; + data->n_devices_allocated = 2 * data->n_devices_attached + 1; + data->devices_attached + = grub_realloc (tmp = data->devices_attached, + data->n_devices_allocated + * sizeof (data->devices_attached[0])); + if (!data->devices_attached) + { + grub_device_close (dev_found); + data->devices_attached = tmp; + return NULL; + } + } + data->devices_attached[data->n_devices_attached - 1].id = id; + data->devices_attached[data->n_devices_attached - 1].dev = dev_found; + return dev_found; +} + +static grub_err_t +grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + void *buf, grub_size_t size) +{ + while (size > 0) + { + grub_uint8_t *ptr; + struct grub_btrfs_key *key; + struct grub_btrfs_chunk_item *chunk; + grub_uint64_t csize; + grub_err_t err = 0; + struct grub_btrfs_key key_out; + int challoc = 0; + grub_device_t dev; + struct grub_btrfs_key key_in; + grub_size_t chsize; + grub_disk_addr_t chaddr; + + grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T "\n", + addr); + for (ptr = data->sblock.bootstrap_mapping; + ptr < data->sblock.bootstrap_mapping + + sizeof (data->sblock.bootstrap_mapping) + - sizeof (struct grub_btrfs_key);) + { + key = (struct grub_btrfs_key *) ptr; + if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK) + break; + chunk = (struct grub_btrfs_chunk_item *) (key + 1); + grub_dprintf ("btrfs", + "%" PRIxGRUB_UINT64_T " %" PRIxGRUB_UINT64_T " \n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size)); + if (grub_le_to_cpu64 (key->offset) <= addr + && addr < grub_le_to_cpu64 (key->offset) + + grub_le_to_cpu64 (chunk->size)) + goto chunk_found; + ptr += sizeof (*key) + sizeof (*chunk) + + sizeof (struct grub_btrfs_chunk_stripe) + * grub_le_to_cpu16 (chunk->nstripes); + } + + key_in.object_id = GRUB_BTRFS_OBJECT_ID_CHUNK; + key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK; + key_in.offset = addr; + err = lower_bound (data, &key_in, &key_out, + grub_le_to_cpu64 (data->sblock.chunk_tree), + &chaddr, &chsize, NULL); + if (err) + return err; + key = &key_out; + if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK + || !(grub_le_to_cpu64 (key->offset) <= addr)) + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; + + challoc = 1; + err = grub_btrfs_read_logical (data, chaddr, chunk, chsize); + if (err) + { + grub_free (chunk); + return err; + } + + chunk_found: + { + grub_uint64_t stripen; + grub_uint64_t stripe_offset; + grub_uint64_t off = addr - grub_le_to_cpu64 (key->offset); + unsigned redundancy = 1; + unsigned i, j; + + if (grub_le_to_cpu64 (chunk->size) <= off) + { + grub_dprintf ("btrfs", "no chunk\n"); + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + } + + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" + PRIxGRUB_UINT64_T ")\n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + grub_le_to_cpu16 (chunk->nsubstripes), + grub_le_to_cpu64 (chunk->stripe_length)); + + switch (grub_le_to_cpu64 (chunk->type) + & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE) + { + case GRUB_BTRFS_CHUNK_TYPE_SINGLE: + { + grub_uint64_t stripe_length; + grub_dprintf ("btrfs", "single\n"); + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + NULL); + stripen = grub_divmod64 (off, stripe_length, &stripe_offset); + csize = (stripen + 1) * stripe_length - off; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED: + case GRUB_BTRFS_CHUNK_TYPE_RAID1: + { + grub_dprintf ("btrfs", "RAID1\n"); + stripen = 0; + stripe_offset = off; + csize = grub_le_to_cpu64 (chunk->size) - off; + redundancy = 2; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: + { + grub_uint64_t middle, high; + grub_uint64_t low; + grub_dprintf ("btrfs", "RAID0\n"); + middle = grub_divmod64 (off, + grub_le_to_cpu64 (chunk->stripe_length), + &low); + + high = grub_divmod64 (middle, grub_le_to_cpu16 (chunk->nstripes), + &stripen); + stripe_offset = + low + grub_le_to_cpu64 (chunk->stripe_length) * high; + csize = grub_le_to_cpu64 (chunk->stripe_length) - low; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID10: + { + grub_uint64_t middle, high; + grub_uint64_t low; + middle = grub_divmod64 (off, + grub_le_to_cpu64 (chunk->stripe_length), + &low); + + high = grub_divmod64 (middle, + grub_le_to_cpu16 (chunk->nstripes) + / grub_le_to_cpu16 (chunk->nsubstripes), + &stripen); + stripen *= grub_le_to_cpu16 (chunk->nsubstripes); + redundancy = grub_le_to_cpu16 (chunk->nsubstripes); + stripe_offset = low + grub_le_to_cpu64 (chunk->stripe_length) + * high; + csize = grub_le_to_cpu64 (chunk->stripe_length) - low; + break; + } + default: + grub_dprintf ("btrfs", "unsupported RAID\n"); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID flags %" PRIxGRUB_UINT64_T, + grub_le_to_cpu64 (chunk->type)); + } + if (csize == 0) + return grub_error (GRUB_ERR_BUG, + "couldn't find the chunk descriptor"); + if ((grub_size_t) csize > size) + csize = size; + + for (j = 0; j < 2; j++) + { + for (i = 0; i < redundancy; i++) + { + struct grub_btrfs_chunk_stripe *stripe; + grub_disk_addr_t paddr; + + stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1); + /* Right now the redundancy handling is easy. + With RAID5-like it will be more difficult. */ + stripe += stripen + i; + + paddr = stripe->offset + stripe_offset; + + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" + PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT64_T + " maps to 0x%" PRIxGRUB_UINT64_T "\n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + grub_le_to_cpu16 (chunk->nsubstripes), + grub_le_to_cpu64 (chunk->stripe_length), + stripen, stripe->offset); + grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T + " for laddr 0x%" PRIxGRUB_UINT64_T "\n", paddr, + addr); + + dev = find_device (data, stripe->device_id, j); + if (!dev) + { + err = grub_errno; + grub_errno = GRUB_ERR_NONE; + continue; + } + + err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS, + paddr & (GRUB_DISK_SECTOR_SIZE - 1), + csize, buf); + if (!err) + break; + grub_errno = GRUB_ERR_NONE; + } + if (i != redundancy) + break; + } + if (err) + return grub_errno = err; + } + size -= csize; + buf = (grub_uint8_t *) buf + csize; + addr += csize; + if (challoc) + grub_free (chunk); + } + return GRUB_ERR_NONE; +} + +static struct grub_btrfs_data * +grub_btrfs_mount (grub_device_t dev) +{ + struct grub_btrfs_data *data; + grub_err_t err; + + if (!dev->disk) + { + grub_error (GRUB_ERR_BAD_FS, "not BtrFS"); + return NULL; + } + + data = grub_zalloc (sizeof (*data)); + if (!data) + return NULL; + + err = read_sblock (dev->disk, &data->sblock); + if (err) + { + grub_free (data); + return NULL; + } + + data->n_devices_allocated = 16; + data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) + * data->n_devices_allocated); + if (!data->devices_attached) + { + grub_free (data); + return NULL; + } + data->n_devices_attached = 1; + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + return data; +} - fail: +static void +grub_btrfs_unmount (struct grub_btrfs_data *data) +{ + unsigned i; + /* The device 0 is closed one layer upper. */ + for (i = 1; i < data->n_devices_attached; i++) + grub_device_close (data->devices_attached[i].dev); + grub_free (data->devices_attached); + grub_free (data->extent); grub_free (data); - return NULL; } static grub_err_t -grub_btrfs_open (struct grub_file *file __attribute__ ((unused)), - const char *name __attribute__ ((unused))) +grub_btrfs_read_inode (struct grub_btrfs_data *data, + struct grub_btrfs_inode *inode, grub_uint64_t num, + grub_uint64_t tree) { - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "only detection is supported for Btrfs"); + struct grub_btrfs_key key_in, key_out; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + grub_err_t err; + + key_in.object_id = num; + key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM; + key_in.offset = 0; + + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL); + if (err) + return err; + if (num != key_out.object_id + || key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM) + return grub_error (GRUB_ERR_BAD_FS, "inode not found"); + + return grub_btrfs_read_logical (data, elemaddr, inode, sizeof (*inode)); +} + +static grub_ssize_t +grub_btrfs_lzo_decompress(char *ibuf, grub_size_t isize, grub_off_t off, + char *obuf, grub_size_t osize) +{ + grub_uint32_t total_size, cblock_size, ret = 0; + unsigned char buf[GRUB_BTRFS_LZO_BLOCK_SIZE]; + + total_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf)); + ibuf += sizeof (total_size); + + if (isize < total_size) + return -1; + + /* Jump forward to first block with requested data. */ + while (off >= GRUB_BTRFS_LZO_BLOCK_SIZE) + { + cblock_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf)); + ibuf += sizeof (cblock_size); + + if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) + return -1; + + off -= GRUB_BTRFS_LZO_BLOCK_SIZE; + ibuf += cblock_size; + } + + while (osize > 0) + { + lzo_uint usize = GRUB_BTRFS_LZO_BLOCK_SIZE; + + cblock_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf)); + ibuf += sizeof (cblock_size); + + if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) + return -1; + + /* Block partially filled with requested data. */ + if (off > 0 || osize < GRUB_BTRFS_LZO_BLOCK_SIZE) + { + grub_size_t to_copy = GRUB_BTRFS_LZO_BLOCK_SIZE - off; + + if (to_copy > osize) + to_copy = osize; + + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, buf, &usize, + NULL) != LZO_E_OK) + return -1; + + if (to_copy > usize) + to_copy = usize; + grub_memcpy(obuf, buf + off, to_copy); + + osize -= to_copy; + ret += to_copy; + obuf += to_copy; + ibuf += cblock_size; + off = 0; + continue; + } + + /* Decompress whole block directly to output buffer. */ + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)obuf, + &usize, NULL) != LZO_E_OK) + return -1; + + osize -= usize; + ret += usize; + obuf += usize; + ibuf += cblock_size; + } + + return ret; +} + +static grub_ssize_t +grub_btrfs_extent_read (struct grub_btrfs_data *data, + grub_uint64_t ino, grub_uint64_t tree, + grub_off_t pos0, char *buf, grub_size_t len) +{ + grub_off_t pos = pos0; + while (len) + { + grub_size_t csize; + grub_err_t err; + grub_off_t extoff; + if (!data->extent || data->extstart > pos || data->extino != ino + || data->exttree != tree || data->extend <= pos) + { + struct grub_btrfs_key key_in, key_out; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + + grub_free (data->extent); + key_in.object_id = ino; + key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; + key_in.offset = grub_cpu_to_le64 (pos); + err = lower_bound (data, &key_in, &key_out, tree, + &elemaddr, &elemsize, NULL); + if (err) + return -1; + if (key_out.object_id != ino + || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM) + { + grub_error (GRUB_ERR_BAD_FS, "extent not found"); + return -1; + } + if ((grub_ssize_t) elemsize < ((char *) &data->extent->inl + - (char *) data->extent)) + { + grub_error (GRUB_ERR_BAD_FS, "extent descriptor is too short"); + return -1; + } + data->extstart = grub_le_to_cpu64 (key_out.offset); + data->extsize = elemsize; + data->extent = grub_malloc (elemsize); + data->extino = ino; + data->exttree = tree; + if (!data->extent) + return grub_errno; + + err = grub_btrfs_read_logical (data, elemaddr, data->extent, + elemsize); + if (err) + return err; + + data->extend = data->extstart + grub_le_to_cpu64 (data->extent->size); + if (data->extent->type == GRUB_BTRFS_EXTENT_REGULAR + && (char *) &data->extent + elemsize + >= (char *) &data->extent->filled + sizeof (data->extent->filled)) + data->extend = + data->extstart + grub_le_to_cpu64 (data->extent->filled); + + grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T "+0x%" + PRIxGRUB_UINT64_T "\n", + grub_le_to_cpu64 (key_out.offset), + grub_le_to_cpu64 (data->extent->size)); + if (data->extend <= pos) + { + grub_error (GRUB_ERR_BAD_FS, "extent not found"); + return -1; + } + } + csize = data->extend - pos; + extoff = pos - data->extstart; + if (csize > len) + csize = len; + + if (data->extent->encryption) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "encryption not supported"); + return -1; + } + + if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE + && data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB + && data->extent->compression != GRUB_BTRFS_COMPRESSION_LZO) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "compression type 0x%x not supported", + data->extent->compression); + return -1; + } + + if (data->extent->encoding) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "encoding not supported"); + return -1; + } + + switch (data->extent->type) + { + case GRUB_BTRFS_EXTENT_INLINE: + if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + { + if (grub_zlib_decompress (data->extent->inl, data->extsize - + ((grub_uint8_t *) data->extent->inl + - (grub_uint8_t *) data->extent), + extoff, buf, csize) + != (grub_ssize_t) csize) + return -1; + } + else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO) + { + if (grub_btrfs_lzo_decompress(data->extent->inl, data->extsize - + ((grub_uint8_t *) data->extent->inl + - (grub_uint8_t *) data->extent), + extoff, buf, csize) + != (grub_ssize_t) csize) + return -1; + } + else + grub_memcpy (buf, data->extent->inl + extoff, csize); + break; + case GRUB_BTRFS_EXTENT_REGULAR: + if (!data->extent->laddr) + { + grub_memset (buf, 0, csize); + break; + } + + if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE) + { + char *tmp; + grub_uint64_t zsize; + grub_ssize_t ret; + + zsize = grub_le_to_cpu64 (data->extent->compressed_size); + tmp = grub_malloc (zsize); + if (!tmp) + return -1; + err = grub_btrfs_read_logical (data, + grub_le_to_cpu64 (data->extent->laddr), + tmp, zsize); + if (err) + { + grub_free (tmp); + return -1; + } + + if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + ret = grub_zlib_decompress (tmp, zsize, extoff + + grub_le_to_cpu64 (data->extent->offset), + buf, csize); + else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO) + ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff + + grub_le_to_cpu64 (data->extent->offset), + buf, csize); + else + ret = -1; + + grub_free (tmp); + + if (ret != (grub_ssize_t) csize) + return -1; + + break; + } + err = grub_btrfs_read_logical (data, + grub_le_to_cpu64 (data->extent->laddr) + + grub_le_to_cpu64 (data->extent->offset) + + extoff, buf, csize); + if (err) + return -1; + break; + default: + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported extent type 0x%x", data->extent->type); + return -1; + } + buf += csize; + pos += csize; + len -= csize; + } + return pos - pos0; } static grub_err_t -grub_btrfs_dir (grub_device_t device, - const char *path __attribute__ ((unused)), - int (*hook) (const char *filename, - const struct grub_dirhook_info *info) - __attribute__ ((unused))) +find_path (struct grub_btrfs_data *data, + const char *path, struct grub_btrfs_key *key, + grub_uint64_t *tree, grub_uint8_t *type) { - struct grub_btrfs_data *data = grub_btrfs_mount (device->disk); - if (grub_errno) + const char *slash = path; + grub_err_t err; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_key key_out; + int skip_default; + const char *ctoken; + grub_size_t ctokenlen; + char *path_alloc = NULL; + char *origpath = NULL; + unsigned symlinks_max = 32; + + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + *tree = data->sblock.root_tree; + key->object_id = data->sblock.root_dir_objectid; + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = 0; + skip_default = 1; + origpath = grub_strdup (path); + if (!origpath) return grub_errno; - grub_free (data); + while (1) + { + if (!skip_default) + { + while (path[0] == '/') + path++; + if (!path[0]) + break; + slash = grub_strchr (path, '/'); + if (!slash) + slash = path + grub_strlen (path); + ctoken = path; + ctokenlen = slash - path; + } + else + { + ctoken = "default"; + ctokenlen = sizeof ("default") - 1; + } + + if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { + grub_free (path_alloc); + grub_free (origpath); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + } + + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); + + err = lower_bound (data, key, &key_out, *tree, &elemaddr, &elemsize, + NULL); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + if (key_cmp (key, &key_out) != 0) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + grub_free (origpath); + return err; + } + + struct grub_btrfs_dir_item *cdirel; + if (elemsize > allocated) + { + allocated = 2 * elemsize; + grub_free (direl); + direl = grub_malloc (allocated + 1); + if (!direl) + { + grub_free (path_alloc); + grub_free (origpath); + return grub_errno; + } + } + + err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; + cdirel = (void *) ((grub_uint8_t *) (direl + 1) + + grub_le_to_cpu16 (cdirel->n) + + grub_le_to_cpu16 (cdirel->m))) + { + if (ctokenlen == grub_le_to_cpu16 (cdirel->n) + && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) + break; + } + if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl + >= (grub_ssize_t) elemsize) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + grub_free (origpath); + return err; + } + + if (!skip_default) + path = slash; + skip_default = 0; + if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) + { + struct grub_btrfs_inode inode; + char *tmp; + if (--symlinks_max == 0) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return grub_error (GRUB_ERR_SYMLINK_LOOP, + "too deep nesting of symlinks"); + } + + err = grub_btrfs_read_inode (data, &inode, + cdirel->key.object_id, *tree); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + tmp = grub_malloc (grub_le_to_cpu64 (inode.size) + + grub_strlen (path) + 1); + if (!tmp) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return grub_errno; + } + + if (grub_btrfs_extent_read (data, cdirel->key.object_id, + *tree, 0, tmp, + grub_le_to_cpu64 (inode.size)) + != (grub_ssize_t) grub_le_to_cpu64 (inode.size)) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + grub_free (tmp); + return grub_errno; + } + grub_memcpy (tmp + grub_le_to_cpu64 (inode.size), path, + grub_strlen (path) + 1); + grub_free (path_alloc); + path = path_alloc = tmp; + if (path[0] == '/') + { + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + *tree = data->sblock.root_tree; + key->object_id = data->sblock.root_dir_objectid; + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = 0; + skip_default = 1; + } + continue; + } + *type = cdirel->type; + + switch (cdirel->key.type) + { + case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM: + { + struct grub_btrfs_root_item ri; + err = lower_bound (data, &cdirel->key, &key_out, + data->sblock.root_tree, + &elemaddr, &elemsize, NULL); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + if (cdirel->key.object_id != key_out.object_id + || cdirel->key.type != key_out.type) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + grub_free (origpath); + return err; + } + err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri)); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = 0; + key->object_id = GRUB_BTRFS_OBJECT_ID_CHUNK; + *tree = grub_le_to_cpu64 (ri.tree); + break; + } + case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM: + if (*slash && *type == GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + grub_free (origpath); + return err; + } + *key = cdirel->key; + if (*type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + break; + default: + grub_free (path_alloc); + grub_free (origpath); + grub_free (direl); + return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x", + cdirel->key.type); + } + } + + grub_free (direl); + grub_free (origpath); + grub_free (path_alloc); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_btrfs_dir (grub_device_t device, const char *path, + int (*hook) (const char *filename, + const struct grub_dirhook_info *info)) +{ + struct grub_btrfs_data *data = grub_btrfs_mount (device); + struct grub_btrfs_key key_in, key_out; + grub_err_t err; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_leaf_descriptor desc; + int r = 0; + grub_uint64_t tree; + grub_uint8_t type; + + if (!data) + return grub_errno; + + err = find_path (data, path, &key_in, &tree, &type); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { + grub_btrfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + } + + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM + || key_out.object_id != key_in.object_id) + { + r = next (data, &desc, &elemaddr, &elemsize, &key_out); + if (r <= 0) + goto out; + } + do + { + struct grub_btrfs_dir_item *cdirel; + if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM + || key_out.object_id != key_in.object_id) + { + r = 0; + break; + } + if (elemsize > allocated) + { + allocated = 2 * elemsize; + grub_free (direl); + direl = grub_malloc (allocated + 1); + if (!direl) + { + r = -grub_errno; + break; + } + } + + err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize); + if (err) + { + r = -err; + break; + } + + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; + cdirel = (void *) ((grub_uint8_t *) (direl + 1) + + grub_le_to_cpu16 (cdirel->n) + + grub_le_to_cpu16 (cdirel->m))) + { + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); + if (err) + grub_errno = GRUB_ERR_NONE; + else + { + info.mtime = inode.mtime.sec; + info.mtimeset = 1; + } + c = cdirel->name[grub_le_to_cpu16 (cdirel->n)]; + cdirel->name[grub_le_to_cpu16 (cdirel->n)] = 0; + info.dir = (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY); + if (hook (cdirel->name, &info)) + goto out; + cdirel->name[grub_le_to_cpu16 (cdirel->n)] = c; + } + r = next (data, &desc, &elemaddr, &elemsize, &key_out); + } + while (r > 0); + +out: + grub_free (direl); + + free_iterator (&desc); + grub_btrfs_unmount (data); + + return -r; +} + +static grub_err_t +grub_btrfs_open (struct grub_file *file, const char *name) +{ + struct grub_btrfs_data *data = grub_btrfs_mount (file->device); + grub_err_t err; + struct grub_btrfs_inode inode; + grub_uint8_t type; + struct grub_btrfs_key key_in; + + if (!data) + return grub_errno; + + err = find_path (data, name, &key_in, &data->tree, &type); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + if (type != GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR) + { + grub_btrfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file"); + } + + data->inode = key_in.object_id; + err = grub_btrfs_read_inode (data, &inode, data->inode, data->tree); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + + file->data = data; + file->size = grub_le_to_cpu64 (inode.size); + + return err; +} + +static grub_err_t +grub_btrfs_close (grub_file_t file) +{ + grub_btrfs_unmount (file->data); return GRUB_ERR_NONE; } +static grub_ssize_t +grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_btrfs_data *data = file->data; + + return grub_btrfs_extent_read (data, data->inode, + data->tree, file->offset, buf, len); +} + static grub_err_t grub_btrfs_uuid (grub_device_t device, char **uuid) { @@ -94,8 +1576,8 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) *uuid = NULL; - data = grub_btrfs_mount (device->disk); - if (! data) + data = grub_btrfs_mount (device); + if (!data) return grub_errno; *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", @@ -108,25 +1590,78 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) grub_be_to_cpu16 (data->sblock.uuid[6]), grub_be_to_cpu16 (data->sblock.uuid[7])); - grub_free (data); + grub_btrfs_unmount (data); return grub_errno; } -static struct grub_fs grub_btrfs_fs = - { - .name = "btrfs", - .dir = grub_btrfs_dir, - .open = grub_btrfs_open, - .uuid = grub_btrfs_uuid, - }; +static grub_err_t +grub_btrfs_label (grub_device_t device, char **label) +{ + struct grub_btrfs_data *data; -GRUB_MOD_INIT(btrfs) + *label = NULL; + + data = grub_btrfs_mount (device); + if (!data) + return grub_errno; + + *label = grub_strndup (data->sblock.label, sizeof (data->sblock.label)); + + grub_btrfs_unmount (data); + + return grub_errno; +} + +#ifdef GRUB_UTIL +static grub_err_t +grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) +{ + unsigned i; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "BtrFS currently supports only PC-BIOS embedding"); + + if (64 * 2 - 1 < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your core.img is unusually large. " + "It won't fit in the embedding area."); + + *nsectors = 64 * 2 - 1; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = i + 1; + + return GRUB_ERR_NONE; +} +#endif + +static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .dir = grub_btrfs_dir, + .open = grub_btrfs_open, + .read = grub_btrfs_read, + .close = grub_btrfs_close, + .uuid = grub_btrfs_uuid, + .label = grub_btrfs_label, +#ifdef GRUB_UTIL + .embed = grub_btrfs_embed, + .reserved_first_sector = 1, +#endif +}; + +GRUB_MOD_INIT (btrfs) { grub_fs_register (&grub_btrfs_fs); } -GRUB_MOD_FINI(btrfs) +GRUB_MOD_FINI (btrfs) { grub_fs_unregister (&grub_btrfs_fs); } diff --git a/grub-core/fs/cpio.c b/grub-core/fs/cpio.c index c087b4f90..b7c3191cc 100644 --- a/grub-core/fs/cpio.c +++ b/grub-core/fs/cpio.c @@ -23,28 +23,76 @@ #include #include -#ifndef MODE_USTAR -/* cpio support */ -#define MAGIC_BCPIO 070707 +GRUB_MOD_LICENSE ("GPLv3+"); + +#define ATTR_TYPE 0160000 +#define ATTR_FILE 0100000 +#define ATTR_DIR 0040000 +#define ATTR_LNK 0120000 + +#ifdef MODE_ODC +#define ALIGN_CPIO(x) x +#define MAGIC "070707" struct head { - grub_uint16_t magic; + char magic[6]; + char dev[6]; + char ino[6]; + char mode[6]; + char uid[6]; + char gid[6]; + char nlink[6]; + char rdev[6]; + char mtime[11]; + char namesize[6]; + char filesize[11]; +} __attribute__ ((packed)); +#elif defined (MODE_NEWC) +#define ALIGN_CPIO(x) (ALIGN_UP ((x), 4)) +#define MAGIC "070701" +#define MAGIC2 "070702" +struct head +{ + char magic[6]; + char ino[8]; + char mode[8]; + char uid[8]; + char gid[8]; + char nlink[8]; + char mtime[8]; + char filesize[8]; + char devmajor[8]; + char devminor[8]; + char rdevmajor[8]; + char rdevminor[8]; + char namesize[8]; + char check[8]; +} __attribute__ ((packed)); +#elif !defined (MODE_USTAR) +/* cpio support */ +#define ALIGN_CPIO(x) (ALIGN_UP ((x), 2)) +#ifdef MODE_BIGENDIAN +#define MAGIC "\x71\xc7" +#else +#define MAGIC "\xc7\x71" +#endif +struct head +{ + grub_uint16_t magic[1]; grub_uint16_t dev; grub_uint16_t ino; - grub_uint16_t mode; + grub_uint16_t mode[1]; grub_uint16_t uid; grub_uint16_t gid; grub_uint16_t nlink; grub_uint16_t rdev; - grub_uint16_t mtime_1; - grub_uint16_t mtime_2; - grub_uint16_t namesize; - grub_uint16_t filesize_1; - grub_uint16_t filesize_2; + grub_uint16_t mtime[2]; + grub_uint16_t namesize[1]; + grub_uint16_t filesize[2]; } __attribute__ ((packed)); #else /* tar support */ -#define MAGIC_USTAR "ustar" +#define MAGIC "ustar" struct head { char name[100]; @@ -69,58 +117,140 @@ struct head struct grub_cpio_data { grub_disk_t disk; - grub_uint32_t hofs; - grub_uint32_t dofs; - grub_uint32_t size; + grub_off_t hofs; + grub_off_t dofs; + grub_off_t size; +#ifdef MODE_USTAR + char *linkname; + grub_size_t linkname_alloc; +#endif }; static grub_dl_t my_mod; +static inline void +canonicalize (char *name) +{ + char *iptr, *optr; + for (iptr = name, optr = name; *iptr; ) + { + while (*iptr == '/') + iptr++; + if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0)) + { + iptr += 2; + continue; + } + while (*iptr && *iptr != '/') + *optr++ = *iptr++; + if (*iptr) + *optr++ = *iptr++; + } + *optr = 0; +} + +#if defined (MODE_ODC) || defined (MODE_USTAR) +static inline unsigned long long +read_number (const char *str, grub_size_t size) +{ + unsigned long long ret = 0; + while (size-- && *str >= '0' && *str <= '7') + ret = (ret << 3) | (*str++ & 0xf); + return ret; +} +#elif defined (MODE_NEWC) +static inline unsigned long long +read_number (const char *str, grub_size_t size) +{ + unsigned long long ret = 0; + while (size-- && grub_isxdigit (*str)) + { + char dig = *str++; + if (dig >= '0' && dig <= '9') + dig &= 0xf; + else if (dig >= 'a' && dig <= 'f') + dig -= 'a' - 10; + else + dig -= 'A' - 10; + ret = (ret << 4) | (dig); + } + return ret; +} +#else +static inline unsigned long long +read_number (const grub_uint16_t *arr, grub_size_t size) +{ + long long ret = 0; +#ifdef MODE_BIGENDIAN + while (size--) + ret = (ret << 16) | grub_be_to_cpu16 (*arr++); +#else + while (size--) + ret = (ret << 16) | grub_le_to_cpu16 (*arr++); +#endif + return ret; +} +#endif + static grub_err_t grub_cpio_find_file (struct grub_cpio_data *data, char **name, - grub_uint32_t * ofs) + grub_int32_t *mtime, grub_disk_addr_t *ofs, + grub_uint32_t *mode) { #ifndef MODE_USTAR - struct head hd; + struct head hd; + grub_size_t namesize; + grub_uint32_t modeval; - if (grub_disk_read - (data->disk, 0, data->hofs, sizeof (hd), &hd)) - return grub_errno; + if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd)) + return grub_errno; - if (hd.magic != MAGIC_BCPIO) - return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); + if (grub_memcmp (hd.magic, MAGIC, sizeof (hd.magic)) != 0 +#ifdef MAGIC2 + && grub_memcmp (hd.magic, MAGIC2, sizeof (hd.magic)) != 0 +#endif + ) + return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); + data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize)); + if (mtime) + *mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime)); + modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode)); + namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize)); - data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2; + if (mode) + *mode = modeval; - if (hd.namesize & 1) - hd.namesize++; + *name = grub_malloc (namesize + 1); + if (*name == NULL) + return grub_errno; - if ((*name = grub_malloc (hd.namesize)) == NULL) - return grub_errno; + if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd), + namesize, *name)) + { + grub_free (*name); + return grub_errno; + } + (*name)[namesize] = 0; - if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd), - hd.namesize, *name)) - { - grub_free (*name); - return grub_errno; - } + if (data->size == 0 && modeval == 0 && namesize == 11 + && grub_memcmp(*name, "TRAILER!!!", 11) == 0) + { + *ofs = 0; + grub_free (*name); + return GRUB_ERR_NONE; + } - if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1 - && ! grub_memcmp(*name, "TRAILER!!!", 11)) - { - *ofs = 0; - return GRUB_ERR_NONE; - } + canonicalize (*name); - data->dofs = data->hofs + sizeof (hd) + hd.namesize; - *ofs = data->dofs + data->size; - if (data->size & 1) - (*ofs)++; + data->dofs = data->hofs + ALIGN_CPIO (sizeof (hd) + namesize); + *ofs = data->dofs + ALIGN_CPIO (data->size); #else - struct head hd; + struct head hd; + int reread = 0, have_longname = 0, have_longlink = 0; - if (grub_disk_read - (data->disk, 0, data->hofs, sizeof (hd), &hd)) + for (reread = 0; reread < 3; reread++) + { + if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd)) return grub_errno; if (!hd.name[0]) @@ -129,16 +259,105 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name, return GRUB_ERR_NONE; } - if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1)) + if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1)) return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); - if ((*name = grub_strdup (hd.name)) == NULL) - return grub_errno; + if (hd.typeflag == 'L') + { + grub_err_t err; + grub_size_t namesize = read_number (hd.size, sizeof (hd.size)); + *name = grub_malloc (namesize + 1); + if (*name == NULL) + return grub_errno; + err = grub_disk_read (data->disk, 0, + data->hofs + GRUB_DISK_SECTOR_SIZE, namesize, + *name); + (*name)[namesize] = 0; + if (err) + return err; + data->hofs += GRUB_DISK_SECTOR_SIZE + + ((namesize + GRUB_DISK_SECTOR_SIZE - 1) & + ~(GRUB_DISK_SECTOR_SIZE - 1)); + have_longname = 1; + continue; + } - data->size = grub_strtoul (hd.size, NULL, 8); + if (hd.typeflag == 'K') + { + grub_err_t err; + grub_size_t linksize = read_number (hd.size, sizeof (hd.size)); + if (data->linkname_alloc < linksize + 1) + { + char *n; + n = grub_malloc (2 * (linksize + 1)); + if (!n) + return grub_errno; + grub_free (data->linkname); + data->linkname = n; + data->linkname_alloc = 2 * (linksize + 1); + } + + err = grub_disk_read (data->disk, 0, + data->hofs + GRUB_DISK_SECTOR_SIZE, linksize, + data->linkname); + if (err) + return err; + data->linkname[linksize] = 0; + data->hofs += GRUB_DISK_SECTOR_SIZE + + ((linksize + GRUB_DISK_SECTOR_SIZE - 1) & + ~(GRUB_DISK_SECTOR_SIZE - 1)); + have_longlink = 1; + continue; + } + + if (!have_longname) + { + *name = grub_strndup (hd.name, sizeof (hd.name)); + if (*name == NULL) + return grub_errno; + } + + data->size = read_number (hd.size, sizeof (hd.size)); data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE; *ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) & ~(GRUB_DISK_SECTOR_SIZE - 1)); + if (mtime) + *mtime = read_number (hd.mtime, sizeof (hd.mtime)); + if (mode) + { + *mode = read_number (hd.mode, sizeof (hd.mode)); + switch (hd.typeflag) + { + case '2': + *mode |= ATTR_LNK; + break; + case '0': + *mode |= ATTR_FILE; + break; + case '5': + *mode |= ATTR_DIR; + break; + } + } + if (!have_longlink) + { + if (data->linkname_alloc < 101) + { + char *n; + n = grub_malloc (101); + if (!n) + return grub_errno; + grub_free (data->linkname); + data->linkname = n; + data->linkname_alloc = 101; + } + grub_memcpy (data->linkname, hd.linkname, sizeof (hd.linkname)); + data->linkname[100] = 0; + } + + canonicalize (*name); + return GRUB_ERR_NONE; + } #endif return GRUB_ERR_NONE; } @@ -152,15 +371,14 @@ grub_cpio_mount (grub_disk_t disk) if (grub_disk_read (disk, 0, 0, sizeof (hd), &hd)) goto fail; -#ifndef MODE_USTAR - if (hd.magic != MAGIC_BCPIO) -#else - if (grub_memcmp (hd.magic, MAGIC_USTAR, - sizeof (MAGIC_USTAR) - 1)) + if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1) +#ifdef MAGIC2 + && grub_memcmp (hd.magic, MAGIC2, sizeof (MAGIC2) - 1) #endif + ) goto fail; - data = (struct grub_cpio_data *) grub_malloc (sizeof (*data)); + data = (struct grub_cpio_data *) grub_zalloc (sizeof (*data)); if (!data) goto fail; @@ -180,15 +398,107 @@ fail: } static grub_err_t -grub_cpio_dir (grub_device_t device, const char *path, +handle_symlink (struct grub_cpio_data *data, + const char *fn, char **name, + grub_uint32_t mode, int *restart) +{ + grub_size_t flen; + char *target; +#ifndef MODE_USTAR + grub_err_t err; +#endif + char *ptr; + char *lastslash; + grub_size_t prefixlen; + char *rest; + grub_size_t size; + + *restart = 0; + + if ((mode & ATTR_TYPE) != ATTR_LNK) + return GRUB_ERR_NONE; + flen = grub_strlen (fn); + if (grub_memcmp (*name, fn, flen) != 0 + || ((*name)[flen] != 0 && (*name)[flen] != '/')) + return GRUB_ERR_NONE; + rest = *name + flen; + lastslash = rest; + if (*rest) + rest++; + while (lastslash >= *name && *lastslash != '/') + lastslash--; + if (lastslash >= *name) + prefixlen = lastslash - *name; + else + prefixlen = 0; + + if (prefixlen) + prefixlen++; + +#ifdef MODE_USTAR + size = grub_strlen (data->linkname); +#else + size = data->size; +#endif + if (size == 0) + return GRUB_ERR_NONE; + target = grub_malloc (size + grub_strlen (*name) + 2); + if (!target) + return grub_errno; + +#ifdef MODE_USTAR + grub_memcpy (target + prefixlen, data->linkname, size); +#else + err = grub_disk_read (data->disk, 0, data->dofs, data->size, + target + prefixlen); + if (err) + return err; +#endif + if (target[prefixlen] == '/') + { + grub_memmove (target, target + prefixlen, data->size - 1); + ptr = target + data->size - 1; + ptr = grub_stpcpy (ptr, rest); + *ptr = 0; + grub_dprintf ("cpio", "symlink redirected %s to %s\n", + *name, target); + grub_free (*name); + *name = target; + *restart = 1; + return GRUB_ERR_NONE; + } + if (prefixlen) + { + grub_memcpy (target, *name, prefixlen); + target[prefixlen-1] = '/'; + } + ptr = target + prefixlen + size; + ptr = grub_stpcpy (ptr, rest); + *ptr = 0; + grub_dprintf ("cpio", "symlink redirected %s to %s\n", + *name, target); + grub_free (*name); + *name = target; + *restart = 1; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cpio_dir (grub_device_t device, const char *path_in, int (*hook) (const char *filename, const struct grub_dirhook_info *info)) { struct grub_cpio_data *data; - grub_uint32_t ofs; - char *prev, *name; - const char *np; - int len; + grub_disk_addr_t ofs; + char *prev, *name, *path, *ptr; + grub_size_t len; + int symlinknest = 0; + + path = grub_strdup (path_in + 1); + if (!path) + return grub_errno; + for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--) + *ptr = 0; grub_dl_ref (my_mod); @@ -196,56 +506,84 @@ grub_cpio_dir (grub_device_t device, const char *path, data = grub_cpio_mount (device->disk); if (!data) - goto fail; - - np = path + 1; - len = grub_strlen (path) - 1; + { + grub_free (path); + return grub_errno; + } + len = grub_strlen (path); data->hofs = 0; while (1) { - if (grub_cpio_find_file (data, &name, &ofs)) + grub_int32_t mtime; + grub_uint32_t mode; + grub_err_t err; + + if (grub_cpio_find_file (data, &name, &mtime, &ofs, &mode)) goto fail; if (!ofs) break; - if (grub_memcmp (np, name, len) == 0) + if (grub_memcmp (path, name, len) == 0 + && (name[len] == 0 || name[len] == '/' || len == 0)) { char *p, *n; n = name + len; - if (*n == '/') + while (*n == '/') n++; - p = grub_strchr (name + len, '/'); + p = grub_strchr (n, '/'); if (p) *p = 0; - if ((!prev) || (grub_strcmp (prev, name) != 0)) + if (((!prev) || (grub_strcmp (prev, n) != 0)) && *n != 0) { struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = (p != NULL); + info.mtime = mtime; + info.mtimeset = 1; - hook (name + len, &info); - if (prev) - grub_free (prev); + if (hook (n, &info)) + goto fail; + grub_free (prev); prev = name; } else - grub_free (name); + { + int restart; + err = handle_symlink (data, name, &path, mode, &restart); + grub_free (name); + if (err) + goto fail; + if (restart) + { + len = grub_strlen (path); + if (++symlinknest == 8) + { + grub_error (GRUB_ERR_SYMLINK_LOOP, + "too deep nesting of symlinks"); + goto fail; + } + ofs = 0; + } + } } + else + grub_free (name); data->hofs = ofs; } fail: - if (prev) - grub_free (prev); - - if (data) - grub_free (data); + grub_free (path); + grub_free (prev); +#ifdef MODE_USTAR + grub_free (data->linkname); +#endif + grub_free (data); grub_dl_unref (my_mod); @@ -253,23 +591,33 @@ fail: } static grub_err_t -grub_cpio_open (grub_file_t file, const char *name) +grub_cpio_open (grub_file_t file, const char *name_in) { struct grub_cpio_data *data; - grub_uint32_t ofs; + grub_disk_addr_t ofs; char *fn; - int i, j; + char *name = grub_strdup (name_in + 1); + int symlinknest = 0; + + if (!name) + return grub_errno; grub_dl_ref (my_mod); data = grub_cpio_mount (file->device->disk); if (!data) - goto fail; + { + grub_free (name); + return grub_errno; + } data->hofs = 0; while (1) { - if (grub_cpio_find_file (data, &fn, &ofs)) + grub_uint32_t mode; + int restart; + + if (grub_cpio_find_file (data, &fn, NULL, &ofs, &mode)) goto fail; if (!ofs) @@ -278,33 +626,31 @@ grub_cpio_open (grub_file_t file, const char *name) break; } - /* Compare NAME and FN by hand in order to cope with duplicate - slashes. */ - i = 0; - j = 0; - while (name[i] == '/') - i++; - while (1) + if (handle_symlink (data, fn, &name, mode, &restart)) { - if (name[i] != fn[j]) - goto no_match; - - if (name[i] == '\0') - break; - - while (name[i] == '/' && name[i+1] == '/') - i++; - - i++; - j++; + grub_free (fn); + goto fail; } - if (name[i] != fn[j]) + if (restart) + { + ofs = 0; + if (++symlinknest == 8) + { + grub_error (GRUB_ERR_SYMLINK_LOOP, + "too deep nesting of symlinks"); + goto fail; + } + goto no_match; + } + + if (grub_strcmp (name, fn) != 0) goto no_match; file->data = data; file->size = data->size; grub_free (fn); + grub_free (name); return GRUB_ERR_NONE; @@ -315,9 +661,11 @@ grub_cpio_open (grub_file_t file, const char *name) } fail: - - if (data) - grub_free (data); +#ifdef MODE_USTAR + grub_free (data->linkname); +#endif + grub_free (data); + grub_free (name); grub_dl_unref (my_mod); @@ -337,7 +685,13 @@ grub_cpio_read (grub_file_t file, char *buf, grub_size_t len) static grub_err_t grub_cpio_close (grub_file_t file) { - grub_free (file->data); + struct grub_cpio_data *data; + + data = file->data; +#ifdef MODE_USTAR + grub_free (data->linkname); +#endif + grub_free (data); grub_dl_unref (my_mod); @@ -347,6 +701,10 @@ grub_cpio_close (grub_file_t file) static struct grub_fs grub_cpio_fs = { #ifdef MODE_USTAR .name = "tarfs", +#elif defined (MODE_ODC) + .name = "odc", +#elif defined (MODE_NEWC) + .name = "newc", #else .name = "cpiofs", #endif @@ -354,10 +712,19 @@ static struct grub_fs grub_cpio_fs = { .open = grub_cpio_open, .read = grub_cpio_read, .close = grub_cpio_close, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, +#endif }; #ifdef MODE_USTAR GRUB_MOD_INIT (tar) +#elif defined (MODE_ODC) +GRUB_MOD_INIT (odc) +#elif defined (MODE_NEWC) +GRUB_MOD_INIT (newc) +#elif defined (MODE_BIGENDIAN) +GRUB_MOD_INIT (cpio_be) #else GRUB_MOD_INIT (cpio) #endif @@ -368,6 +735,12 @@ GRUB_MOD_INIT (cpio) #ifdef MODE_USTAR GRUB_MOD_FINI (tar) +#elif defined (MODE_ODC) +GRUB_MOD_FINI (odc) +#elif defined (MODE_NEWC) +GRUB_MOD_FINI (newc) +#elif defined (MODE_BIGENDIAN) +GRUB_MOD_FINI (cpio_be) #else GRUB_MOD_FINI (cpio) #endif diff --git a/grub-core/fs/afs_be.c b/grub-core/fs/cpio_be.c similarity index 58% rename from grub-core/fs/afs_be.c rename to grub-core/fs/cpio_be.c index 1f1f48fbb..8bad314cd 100644 --- a/grub-core/fs/afs_be.c +++ b/grub-core/fs/cpio_be.c @@ -1,2 +1,2 @@ #define MODE_BIGENDIAN 1 -#include "afs.c" +#include "cpio.c" diff --git a/grub-core/fs/exfat.c b/grub-core/fs/exfat.c new file mode 100644 index 000000000..fe149ddd3 --- /dev/null +++ b/grub-core/fs/exfat.c @@ -0,0 +1,2 @@ +#define MODE_EXFAT 1 +#include "fat.c" diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c index dfc75c625..875f7b928 100644 --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@ -21,10 +21,6 @@ #define EXT2_MAGIC 0xEF53 /* Amount of indirect blocks in an inode. */ #define INDIRECT_BLOCKS 12 -/* Maximum length of a pathname. */ -#define EXT2_PATH_MAX 4096 -/* Maximum nesting of symlinks, used to prevent a loop. */ -#define EXT2_MAX_SYMLINKCNT 8 /* The good old revision and the default inode size. */ #define EXT2_GOOD_OLD_REVISION 0 @@ -51,6 +47,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Log2 size of ext2 block in 512 blocks. */ #define LOG2_EXT2_BLOCK_SIZE(data) \ (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1) @@ -229,7 +227,7 @@ struct grub_ext2_inode }; grub_uint32_t version; grub_uint32_t acl; - grub_uint32_t dir_acl; + grub_uint32_t size_high; grub_uint32_t fragment_addr; grub_uint32_t osd2[3]; }; @@ -335,7 +333,7 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group, } static struct grub_ext4_extent_header * -grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf, +grub_ext4_find_leaf (struct grub_ext2_data *data, grub_properly_aligned_t *buf, struct grub_ext4_extent_header *ext_block, grub_uint32_t fileblock) { @@ -385,7 +383,7 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) if (grub_le_to_cpu32(inode->flags) & EXT4_EXTENTS_FLAG) { - char buf[EXT2_BLOCK_SIZE(data)]; + GRUB_PROPERLY_ALIGNED_ARRAY (buf, EXT2_BLOCK_SIZE(data)); struct grub_ext4_extent_header *leaf; struct grub_ext4_extent *ext; int i; @@ -470,10 +468,41 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) blknr = grub_le_to_cpu32 (indir[rblock % perblock]); } /* triple indirect. */ + else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1) + + (blksz / 4) * (blksz / 4) * (blksz / 4 + 1)) + { + unsigned int perblock = blksz / 4; + unsigned int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 + * (blksz / 4 + 1)); + grub_uint32_t indir[blksz / 4]; + + if (grub_disk_read (data->disk, + ((grub_disk_addr_t) + grub_le_to_cpu32 (inode->blocks.triple_indir_block)) + << log2_blksz, + 0, blksz, indir)) + return grub_errno; + + if (grub_disk_read (data->disk, + ((grub_disk_addr_t) + grub_le_to_cpu32 (indir[(rblock / perblock) / perblock])) + << log2_blksz, + 0, blksz, indir)) + return grub_errno; + + if (grub_disk_read (data->disk, + ((grub_disk_addr_t) + grub_le_to_cpu32 (indir[(rblock / perblock) % perblock])) + << log2_blksz, + 0, blksz, indir)) + return grub_errno; + + blknr = grub_le_to_cpu32 (indir[rblock % perblock]); + } else { grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "ext2fs doesn't support triple indirect blocks"); + "ext2fs doesn't support quadruple indirect blocks"); } return blknr; @@ -485,11 +514,12 @@ static grub_ssize_t grub_ext2_read_file (grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { return grub_fshelp_read_file (node->data->disk, node, read_hook, pos, len, buf, grub_ext2_read_block, - node->inode.size, + grub_cpu_to_le32 (node->inode.size) + | (((grub_off_t) grub_cpu_to_le32 (node->inode.size_high)) << 32), LOG2_EXT2_BLOCK_SIZE (node->data)); } @@ -523,7 +553,7 @@ grub_ext2_read_inode (struct grub_ext2_data *data, /* Read the inode. */ if (grub_disk_read (data->disk, - ((grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) + (((grub_disk_addr_t) grub_le_to_cpu32 (blkgrp.inode_table_id) + blkno) << LOG2_EXT2_BLOCK_SIZE (data)), EXT2_INODE_SIZE (data) * blkoff, sizeof (struct grub_ext2_inode), inode)) @@ -655,7 +685,7 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir, if (dirent.direntlen == 0) return 0; - if (dirent.namelen != 0) + if (dirent.inode != 0 && dirent.namelen != 0) { char filename[dirent.namelen + 1]; struct grub_fshelp_node *fdiro; @@ -756,6 +786,7 @@ grub_ext2_open (struct grub_file *file, const char *name) grub_free (fdiro); file->size = grub_le_to_cpu32 (data->inode->size); + file->size |= ((grub_off_t) grub_le_to_cpu32 (data->inode->size_high)) << 32; file->data = data; file->offset = 0; @@ -861,7 +892,8 @@ grub_ext2_label (grub_device_t device, char **label) data = grub_ext2_mount (disk); if (data) - *label = grub_strndup (data->sblock.volume_name, 14); + *label = grub_strndup (data->sblock.volume_name, + sizeof (data->sblock.volume_name)); else *label = NULL; diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c index 89050943c..64b07e6d8 100644 --- a/grub-core/fs/fat.c +++ b/grub-core/fs/fat.c @@ -26,75 +26,120 @@ #include #include #include +#include -#define GRUB_FAT_DIR_ENTRY_SIZE 32 +GRUB_MOD_LICENSE ("GPLv3+"); -#define GRUB_FAT_ATTR_READ_ONLY 0x01 -#define GRUB_FAT_ATTR_HIDDEN 0x02 -#define GRUB_FAT_ATTR_SYSTEM 0x04 -#define GRUB_FAT_ATTR_VOLUME_ID 0x08 -#define GRUB_FAT_ATTR_DIRECTORY 0x10 -#define GRUB_FAT_ATTR_ARCHIVE 0x20 +enum + { + GRUB_FAT_ATTR_READ_ONLY = 0x01, + GRUB_FAT_ATTR_HIDDEN = 0x02, + GRUB_FAT_ATTR_SYSTEM = 0x04, +#ifndef MODE_EXFAT + GRUB_FAT_ATTR_VOLUME_ID = 0x08, +#endif + GRUB_FAT_ATTR_DIRECTORY = 0x10, + GRUB_FAT_ATTR_ARCHIVE = 0x20, -#define GRUB_FAT_MAXFILE 256 +#ifndef MODE_EXFAT + GRUB_FAT_ATTR_LONG_NAME = (GRUB_FAT_ATTR_READ_ONLY + | GRUB_FAT_ATTR_HIDDEN + | GRUB_FAT_ATTR_SYSTEM + | GRUB_FAT_ATTR_VOLUME_ID), +#endif + GRUB_FAT_ATTR_VALID = (GRUB_FAT_ATTR_READ_ONLY + | GRUB_FAT_ATTR_HIDDEN + | GRUB_FAT_ATTR_SYSTEM + | GRUB_FAT_ATTR_DIRECTORY + | GRUB_FAT_ATTR_ARCHIVE +#ifndef MODE_EXFAT + | GRUB_FAT_ATTR_VOLUME_ID +#endif + ) + }; -#define GRUB_FAT_ATTR_LONG_NAME (GRUB_FAT_ATTR_READ_ONLY \ - | GRUB_FAT_ATTR_HIDDEN \ - | GRUB_FAT_ATTR_SYSTEM \ - | GRUB_FAT_ATTR_VOLUME_ID) -#define GRUB_FAT_ATTR_VALID (GRUB_FAT_ATTR_READ_ONLY \ - | GRUB_FAT_ATTR_HIDDEN \ - | GRUB_FAT_ATTR_SYSTEM \ - | GRUB_FAT_ATTR_DIRECTORY \ - | GRUB_FAT_ATTR_ARCHIVE \ - | GRUB_FAT_ATTR_VOLUME_ID) - -struct grub_fat_bpb +#ifdef MODE_EXFAT +struct grub_exfat_bpb { grub_uint8_t jmp_boot[3]; grub_uint8_t oem_name[8]; - grub_uint16_t bytes_per_sector; - grub_uint8_t sectors_per_cluster; - grub_uint16_t num_reserved_sectors; + grub_uint8_t mbz[53]; + grub_uint64_t num_hidden_sectors; + grub_uint64_t num_total_sectors; + grub_uint32_t num_reserved_sectors; + grub_uint32_t sectors_per_fat; + grub_uint32_t cluster_offset; + grub_uint32_t cluster_count; + grub_uint32_t root_cluster; + grub_uint32_t num_serial; + grub_uint16_t fs_revision; + grub_uint16_t volume_flags; + grub_uint8_t bytes_per_sector_shift; + grub_uint8_t sectors_per_cluster_shift; grub_uint8_t num_fats; - grub_uint16_t num_root_entries; - grub_uint16_t num_total_sectors_16; - grub_uint8_t media; - grub_uint16_t sectors_per_fat_16; - grub_uint16_t sectors_per_track; - grub_uint16_t num_heads; - grub_uint32_t num_hidden_sectors; - grub_uint32_t num_total_sectors_32; + grub_uint8_t num_ph_drive; + grub_uint8_t reserved[8]; +} __attribute__ ((packed)); +typedef struct grub_exfat_bpb grub_current_fat_bpb_t; +#else +typedef struct grub_fat_bpb grub_current_fat_bpb_t; +#endif + +#ifdef MODE_EXFAT +struct grub_fat_dir_entry +{ + grub_uint8_t entry_type; union { - struct - { - grub_uint8_t num_ph_drive; - grub_uint8_t reserved; - grub_uint8_t boot_sig; - grub_uint32_t num_serial; - grub_uint8_t label[11]; - grub_uint8_t fstype[8]; - } __attribute__ ((packed)) fat12_or_fat16; - struct - { - grub_uint32_t sectors_per_fat_32; - grub_uint16_t extended_flags; - grub_uint16_t fs_version; - grub_uint32_t root_cluster; - grub_uint16_t fs_info; - grub_uint16_t backup_boot_sector; - grub_uint8_t reserved[12]; - grub_uint8_t num_ph_drive; + grub_uint8_t placeholder[31]; + struct { + grub_uint8_t secondary_count; + grub_uint16_t checksum; + grub_uint16_t attr; + grub_uint16_t reserved1; + grub_uint32_t c_time; + grub_uint32_t m_time; + grub_uint32_t a_time; + grub_uint8_t c_time_tenth; + grub_uint8_t m_time_tenth; + grub_uint8_t a_time_tenth; + grub_uint8_t reserved2[9]; + } __attribute__ ((packed)) file; + struct { + grub_uint8_t flags; grub_uint8_t reserved1; - grub_uint8_t boot_sig; - grub_uint32_t num_serial; - grub_uint8_t label[11]; - grub_uint8_t fstype[8]; - } __attribute__ ((packed)) fat32; - } __attribute__ ((packed)) version_specific; + grub_uint8_t name_length; + grub_uint16_t name_hash; + grub_uint16_t reserved2; + grub_uint64_t valid_size; + grub_uint32_t reserved3; + grub_uint32_t first_cluster; + grub_uint64_t file_size; + } __attribute__ ((packed)) stream_extension; + struct { + grub_uint8_t flags; + grub_uint16_t str[15]; + } __attribute__ ((packed)) file_name; + struct { + grub_uint8_t character_count; + grub_uint16_t str[15]; + } __attribute__ ((packed)) volume_label; + } __attribute__ ((packed)) type_specific; } __attribute__ ((packed)); +struct grub_fat_dir_node +{ + grub_uint32_t attr; + grub_uint32_t first_cluster; + grub_uint64_t file_size; + grub_uint64_t valid_size; + int have_stream; + int is_label; +}; + +typedef struct grub_fat_dir_node grub_fat_dir_node_t; + +#else struct grub_fat_dir_entry { grub_uint8_t name[11]; @@ -123,6 +168,10 @@ struct grub_fat_long_name_entry grub_uint16_t name3[2]; } __attribute__ ((packed)); +typedef struct grub_fat_dir_entry grub_fat_dir_node_t; + +#endif + struct grub_fat_data { int logical_sector_bits; @@ -133,8 +182,10 @@ struct grub_fat_data int fat_size; grub_uint32_t root_cluster; +#ifndef MODE_EXFAT grub_uint32_t root_sector; grub_uint32_t num_root_sectors; +#endif int cluster_bits; grub_uint32_t cluster_eof_mark; @@ -152,6 +203,7 @@ struct grub_fat_data static grub_dl_t my_mod; +#ifndef MODE_EXFAT static int fat_log2 (unsigned x) { @@ -168,11 +220,12 @@ fat_log2 (unsigned x) return i; } +#endif static struct grub_fat_data * grub_fat_mount (grub_disk_t disk) { - struct grub_fat_bpb bpb; + grub_current_fat_bpb_t bpb; struct grub_fat_data *data = 0; grub_uint32_t first_fat, magic; @@ -187,20 +240,30 @@ grub_fat_mount (grub_disk_t disk) if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb)) goto fail; - if (grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT12", 5) - && grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT16", 5) - && grub_strncmp((const char *) bpb.version_specific.fat32.fstype, "FAT32", 5)) - goto fail; +#ifdef MODE_EXFAT + if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ", + sizeof (bpb.oem_name)) != 0) + goto fail; +#endif /* Get the sizes of logical sectors and clusters. */ +#ifdef MODE_EXFAT + data->logical_sector_bits = bpb.bytes_per_sector_shift; +#else data->logical_sector_bits = fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector)); - if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS) +#endif + if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS + || data->logical_sector_bits >= 16) goto fail; data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS; +#ifdef MODE_EXFAT + data->cluster_bits = bpb.sectors_per_cluster_shift; +#else data->cluster_bits = fat_log2 (bpb.sectors_per_cluster); - if (data->cluster_bits < 0) +#endif + if (data->cluster_bits < 0 || data->cluster_bits > 25) goto fail; data->cluster_bits += data->logical_sector_bits; @@ -210,18 +273,28 @@ grub_fat_mount (grub_disk_t disk) if (data->fat_sector == 0) goto fail; +#ifdef MODE_EXFAT + data->sectors_per_fat = (grub_le_to_cpu32 (bpb.sectors_per_fat) + << data->logical_sector_bits); +#else data->sectors_per_fat = ((bpb.sectors_per_fat_16 ? grub_le_to_cpu16 (bpb.sectors_per_fat_16) : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32)) << data->logical_sector_bits); +#endif if (data->sectors_per_fat == 0) goto fail; /* Get the number of sectors in this volume. */ +#ifdef MODE_EXFAT + data->num_sectors = ((grub_le_to_cpu64 (bpb.num_total_sectors)) + << data->logical_sector_bits); +#else data->num_sectors = ((bpb.num_total_sectors_16 ? grub_le_to_cpu16 (bpb.num_total_sectors_16) : grub_le_to_cpu32 (bpb.num_total_sectors_32)) << data->logical_sector_bits); +#endif if (data->num_sectors == 0) goto fail; @@ -229,22 +302,44 @@ grub_fat_mount (grub_disk_t disk) if (bpb.num_fats == 0) goto fail; +#ifndef MODE_EXFAT data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat; data->num_root_sectors = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries) - * GRUB_FAT_DIR_ENTRY_SIZE + * sizeof (struct grub_fat_dir_entry) + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1) >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS)) << (data->logical_sector_bits)); +#endif +#ifdef MODE_EXFAT + data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset) + << data->logical_sector_bits); + data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count) + << data->logical_sector_bits); +#else data->cluster_sector = data->root_sector + data->num_root_sectors; data->num_clusters = (((data->num_sectors - data->cluster_sector) >> (data->cluster_bits + data->logical_sector_bits)) + 2); +#endif if (data->num_clusters <= 2) goto fail; +#ifdef MODE_EXFAT + { + /* exFAT. */ + grub_uint16_t flags = grub_le_to_cpu16 (bpb.volume_flags); + + data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster); + data->fat_size = 32; + data->cluster_eof_mark = 0xffffffff; + + if ((flags & 0x1) && bpb.num_fats > 1) + data->fat_sector += data->sectors_per_fat; + } +#else if (! bpb.sectors_per_fat_16) { /* FAT32. */ @@ -286,6 +381,7 @@ grub_fat_mount (grub_disk_t disk) data->cluster_eof_mark = 0xfff8; } } +#endif /* More sanity checks. */ if (data->num_sectors <= data->fat_sector) @@ -317,17 +413,25 @@ grub_fat_mount (grub_disk_t disk) } /* Serial number. */ +#ifdef MODE_EXFAT + data->uuid = grub_le_to_cpu32 (bpb.num_serial); +#else if (bpb.sectors_per_fat_16) data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial); else data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial); +#endif +#ifndef MODE_EXFAT /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media descriptor, even if it is a so-called superfloppy (e.g. an USB key). The check may be too strict for this kind of stupid BIOSes, as they overwrite the media descriptor. */ if ((first_fat | 0x8) != (magic | bpb.media | 0x8)) goto fail; +#else + (void) magic; +#endif /* Start from the root directory. */ data->file_cluster = data->root_cluster; @@ -354,6 +458,7 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data, grub_ssize_t ret = 0; unsigned long sector; +#ifndef MODE_EXFAT /* This is a special case. FAT12 and FAT16 doesn't have the root directory in clusters. */ if (data->file_cluster == ~0U) @@ -367,13 +472,14 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data, return size; } +#endif /* Calculate the logical cluster number and offset. */ logical_cluster_bits = (data->cluster_bits + data->logical_sector_bits + GRUB_DISK_SECTOR_BITS); logical_cluster = offset >> logical_cluster_bits; - offset &= (1 << logical_cluster_bits) - 1; + offset &= (1ULL << logical_cluster_bits) - 1; if (logical_cluster < data->cur_cluster_num) { @@ -465,13 +571,116 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data, return ret; } +#ifdef MODE_EXFAT +static grub_err_t +grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, + int (*hook) (const char *filename, + grub_fat_dir_node_t *node)) +{ + struct grub_fat_dir_entry dir; + grub_ssize_t offset = -sizeof(dir); + grub_uint16_t *unibuf; + char *filename; + + unibuf = grub_malloc (15 * 256 * 2); + filename = grub_malloc (15 * 256 * GRUB_MAX_UTF8_PER_UTF16 + 1); + + while (1) + { + offset += sizeof (dir); + + if (grub_fat_read_data (disk, data, 0, + offset, sizeof (dir), (char *) &dir) + != sizeof (dir)) + break; + + if (dir.entry_type == 0) + break; + if (!(dir.entry_type & 0x80)) + continue; + + if (dir.entry_type == 0x85) + { + unsigned i, nsec, slots = 0; + grub_fat_dir_node_t node; + + nsec = dir.type_specific.file.secondary_count; + + node.attr = grub_cpu_to_le32 (dir.type_specific.file.attr); + node.have_stream = 0; + for (i = 0; i < nsec; i++) + { + struct grub_fat_dir_entry sec; + offset += sizeof (sec); + if (grub_fat_read_data (disk, data, 0, + offset, sizeof (sec), (char *) &sec) + != sizeof (sec)) + break; + if (!(sec.entry_type & 0x80)) + continue; + if (!(sec.entry_type & 0x40)) + break; + switch (sec.entry_type) + { + case 0xc0: + node.first_cluster = grub_cpu_to_le32 (sec.type_specific.stream_extension.first_cluster); + node.valid_size + = grub_cpu_to_le64 (sec.type_specific.stream_extension.valid_size); + node.file_size + = grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size); + node.have_stream = 1; + break; + case 0xc1: + grub_memcpy (unibuf + slots * 15, + sec.type_specific.file_name.str, 30); + slots++; + break; + default: + grub_dprintf ("exfat", "unknown secondary type 0x%02x\n", + sec.entry_type); + } + } + + if (i != nsec) + { + offset -= sizeof (dir); + continue; + } + + *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf, + slots * 15) = '\0'; + + if (hook (filename, &node)) + break; + continue; + } + /* Allocation bitmap. */ + if (dir.entry_type == 0x81) + continue; + /* Upcase table. */ + if (dir.entry_type == 0x82) + continue; + /* Volume label. */ + if (dir.entry_type == 0x83) + continue; + grub_dprintf ("exfat", "unknown primary type 0x%02x\n", dir.entry_type); + } + grub_free (filename); + grub_free (unibuf); + + return grub_errno; +} + +#else + static grub_err_t grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, int (*hook) (const char *filename, struct grub_fat_dir_entry *dir)) { struct grub_fat_dir_entry dir; - char *filename, *filep = 0; + char *filename; + char *filep = 0; grub_uint16_t *unibuf; int slot = -1, slots = -1; int checksum = -1; @@ -481,7 +690,7 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); /* Allocate space enough to hold a long name. */ - filename = grub_malloc (0x40 * 13 * 4 + 1); + filename = grub_malloc (0x40 * 13 * GRUB_MAX_UTF8_PER_UTF16 + 1); unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2); if (! filename || ! unibuf) { @@ -498,10 +707,11 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, offset += sizeof (dir); /* Read a directory entry. */ - if ((grub_fat_read_data (disk, data, 0, + if (grub_fat_read_data (disk, data, 0, offset, sizeof (dir), (char *) &dir) - != sizeof (dir) || dir.name[0] == 0)) + != sizeof (dir) || dir.name[0] == 0) break; + /* Handle long name entries. */ if (dir.attr == GRUB_FAT_ATTR_LONG_NAME) { @@ -586,7 +796,6 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, filep++; } *filep = '\0'; - if (hook (filename, &dir)) break; } @@ -596,7 +805,7 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, return grub_errno; } - +#endif /* Find the underlying directory or file in PATH and return the next path. If there is no next path or an error occurs, return NULL. @@ -608,11 +817,12 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, const struct grub_dirhook_info *info)) { char *dirname, *dirp; + char *origpath = NULL; int call_hook; int found = 0; - auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir); - int iter_hook (const char *filename, struct grub_fat_dir_entry *dir) + auto int iter_hook (const char *filename, grub_fat_dir_node_t *dir); + int iter_hook (const char *filename, grub_fat_dir_node_t *dir) { struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); @@ -620,8 +830,13 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, info.dir = !! (dir->attr & GRUB_FAT_ATTR_DIRECTORY); info.case_insensitive = 1; +#ifdef MODE_EXFAT + if (!dir->have_stream) + return 0; +#else if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID) return 0; +#endif if (*dirname == '\0' && call_hook) return hook (filename, &info); @@ -629,9 +844,14 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, { found = 1; data->attr = dir->attr; +#ifdef MODE_EXFAT + data->file_size = dir->file_size; + data->file_cluster = dir->first_cluster; +#else data->file_size = grub_le_to_cpu32 (dir->file_size); data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16) | grub_le_to_cpu16 (dir->first_cluster_low)); +#endif data->cur_cluster_num = ~0U; if (call_hook) @@ -648,6 +868,10 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, return 0; } + origpath = grub_strdup (path); + if (!origpath) + return 0; + /* Extract a directory name. */ while (*path == '/') path++; @@ -659,7 +883,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, dirname = grub_malloc (len + 1); if (! dirname) - return 0; + goto fail; grub_memcpy (dirname, path, len); dirname[len] = '\0'; @@ -672,9 +896,11 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data, grub_fat_iterate_dir (disk, data, iter_hook); if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook) - grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + fail: grub_free (dirname); + grub_free (origpath); return found ? dirp : 0; } @@ -781,14 +1007,68 @@ grub_fat_close (grub_file_t file) return grub_errno; } +#ifdef MODE_EXFAT +static grub_err_t +grub_fat_label (grub_device_t device, char **label) +{ + struct grub_fat_dir_entry dir; + grub_ssize_t offset = -sizeof(dir); + struct grub_fat_data *data; + grub_disk_t disk = device->disk; + + data = grub_fat_mount (disk); + if (! data) + return grub_errno; + + *label = NULL; + + while (1) + { + offset += sizeof (dir); + + if (grub_fat_read_data (disk, data, 0, + offset, sizeof (dir), (char *) &dir) + != sizeof (dir)) + break; + + if (dir.entry_type == 0) + break; + if (!(dir.entry_type & 0x80)) + continue; + + /* Volume label. */ + if (dir.entry_type == 0x83) + { + grub_size_t chc; + *label = grub_malloc (ARRAY_SIZE (dir.type_specific.volume_label.str) + * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (!*label) + { + grub_free (data); + return grub_errno; + } + chc = dir.type_specific.volume_label.character_count; + if (chc > ARRAY_SIZE (dir.type_specific.volume_label.str)) + chc = ARRAY_SIZE (dir.type_specific.volume_label.str); + *grub_utf16_to_utf8 ((grub_uint8_t *) *label, + dir.type_specific.volume_label.str, chc) = '\0'; + } + } + + grub_free (data); + return grub_errno; +} + +#else + static grub_err_t grub_fat_label (grub_device_t device, char **label) { struct grub_fat_data *data; grub_disk_t disk = device->disk; - auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir); - int iter_hook (const char *filename, struct grub_fat_dir_entry *dir) + auto int iter_hook (const char *filename, grub_fat_dir_node_t *dir); + int iter_hook (const char *filename, grub_fat_dir_node_t *dir) { if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID) { @@ -823,6 +1103,8 @@ grub_fat_label (grub_device_t device, char **label) return grub_errno; } +#endif + static grub_err_t grub_fat_uuid (grub_device_t device, char **uuid) { @@ -834,9 +1116,12 @@ grub_fat_uuid (grub_device_t device, char **uuid) data = grub_fat_mount (disk); if (data) { + char *ptr; *uuid = grub_xasprintf ("%04x-%04x", (grub_uint16_t) (data->uuid >> 16), (grub_uint16_t) data->uuid); + for (ptr = *uuid; ptr && *ptr; ptr++) + *ptr = grub_toupper (*ptr); } else *uuid = NULL; @@ -850,7 +1135,11 @@ grub_fat_uuid (grub_device_t device, char **uuid) static struct grub_fs grub_fat_fs = { +#ifdef MODE_EXFAT + .name = "exfat", +#else .name = "fat", +#endif .dir = grub_fat_dir, .open = grub_fat_open, .read = grub_fat_read, @@ -858,18 +1147,31 @@ static struct grub_fs grub_fat_fs = .label = grub_fat_label, .uuid = grub_fat_uuid, #ifdef GRUB_UTIL +#ifdef MODE_EXFAT + /* ExFAT BPB is 30 larger than FAT32 one. */ + .reserved_first_sector = 0, +#else .reserved_first_sector = 1, +#endif #endif .next = 0 }; +#ifdef MODE_EXFAT +GRUB_MOD_INIT(exfat) +#else GRUB_MOD_INIT(fat) +#endif { + COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32); grub_fs_register (&grub_fat_fs); my_mod = mod; } - +#ifdef MODE_EXFAT +GRUB_MOD_FINI(exfat) +#else GRUB_MOD_FINI(fat) +#endif { grub_fs_unregister (&grub_fat_fs); } diff --git a/grub-core/fs/fshelp.c b/grub-core/fs/fshelp.c index d0b1e493e..0944cf8c3 100644 --- a/grub-core/fs/fshelp.c +++ b/grub-core/fs/fshelp.c @@ -22,7 +22,9 @@ #include #include #include +#include +GRUB_MOD_LICENSE ("GPLv3+"); /* Lookup the node PATH. The node ROOTNODE describes the root of the directory tree. The node found is returned in FOUNDNODE, which is @@ -59,7 +61,6 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, char fpath[grub_strlen (currpath) + 1]; char *name = fpath; char *next; - // unsigned int pos = 0; enum grub_fshelp_filetype type = GRUB_FSHELP_DIR; grub_fshelp_node_t currnode = currroot; grub_fshelp_node_t oldnode = currroot; @@ -83,7 +84,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, if (filetype == GRUB_FSHELP_UNKNOWN || (grub_strcmp (name, filename) && (! (filetype & GRUB_FSHELP_CASE_INSENSITIVE) || - grub_strncasecmp (name, filename, GRUB_LONG_MAX)))) + grub_strcasecmp (name, filename)))) { grub_free (node); return 0; @@ -195,7 +196,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, name = next; } - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path); } if (!path || path[0] != '/') diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c index cef856326..c14a884cc 100644 --- a/grub-core/fs/hfs.c +++ b/grub-core/fs/hfs.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_HFS_SBLOCK 2 #define GRUB_HFS_EMBED_HFSPLUS_SIG 0x482B @@ -131,6 +133,8 @@ struct grub_hfs_dirrec grub_uint8_t type; grub_uint8_t unused[5]; grub_uint32_t dirid; + grub_uint32_t ctime; + grub_uint32_t mtime; } __attribute__ ((packed)); /* Information about a file. */ @@ -142,7 +146,9 @@ struct grub_hfs_filerec grub_uint32_t fileid; grub_uint8_t unused2[2]; grub_uint32_t size; - grub_uint8_t unused3[44]; + grub_uint8_t unused3[18]; + grub_uint32_t mtime; + grub_uint8_t unused4[22]; /* The first 3 extents of the file. The other extents can be found in the extent overflow file. */ @@ -238,22 +244,24 @@ static grub_ssize_t grub_hfs_read_file (struct grub_hfs_data *data, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { - int i; - int blockcnt; + grub_off_t i; + grub_off_t blockcnt; - blockcnt = ((len + pos) - + data->blksz - 1) / data->blksz; + blockcnt = grub_divmod64 (((len + pos) + + data->blksz - 1), data->blksz, 0); - for (i = pos / data->blksz; i < blockcnt; i++) + for (i = grub_divmod64 (pos, data->blksz, 0); i < blockcnt; i++) { - int blknr; - int blockoff = pos % data->blksz; - int blockend = data->blksz; + grub_disk_addr_t blknr; + grub_off_t blockoff; + grub_off_t blockend = data->blksz; int skipfirst = 0; + grub_divmod64 (pos, data->blksz, &blockoff); + blknr = grub_hfs_block (data, data->extents, data->fileid, i, 1); if (grub_errno) return -1; @@ -261,7 +269,7 @@ grub_hfs_read_file (struct grub_hfs_data *data, /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % data->blksz; + grub_divmod64 ((len + pos), data->blksz, &blockend); /* The last portion is exactly EXT2_BLOCK_SIZE (data). */ if (! blockend) @@ -269,7 +277,7 @@ grub_hfs_read_file (struct grub_hfs_data *data, } /* First block. */ - if (i == pos / data->blksz) + if (i == grub_divmod64 (pos, data->blksz, 0)) { skipfirst = blockoff; blockend -= skipfirst; @@ -742,10 +750,7 @@ grub_hfs_find_node (struct grub_hfs_data *data, char *key, entry. In case of a non-leaf mode it will be used to lookup the rest of the tree. */ if (cmp <= 0) - { - grub_uint32_t *node = (grub_uint32_t *) rec->data; - found = grub_be_to_cpu32 (*node); - } + found = grub_be_to_cpu32 (grub_get_unaligned32 (rec->data)); else /* The key can not be found in the tree. */ return 1; @@ -809,7 +814,7 @@ grub_hfs_iterate_dir (struct grub_hfs_data *data, grub_uint32_t root_idx, struct grub_hfs_catalog_key *ckey = rec->key; if (grub_hfs_cmp_catkeys (rec->key, (void *) &key) <= 0) - found = grub_be_to_cpu32 (*(grub_uint32_t *) rec->data); + found = grub_be_to_cpu32 (grub_get_unaligned32 (rec->data)); if (hnd->type == 0xFF && ckey->strlen > 0) { @@ -857,6 +862,203 @@ grub_hfs_iterate_dir (struct grub_hfs_data *data, grub_uint32_t root_idx, return grub_errno; } +#define MAX_UTF8_PER_MAC_ROMAN 3 + +static const char macroman[0x80][MAX_UTF8_PER_MAC_ROMAN + 1] = + { + /* 80 */ "\xc3\x84", + /* 81 */ "\xc3\x85", + /* 82 */ "\xc3\x87", + /* 83 */ "\xc3\x89", + /* 84 */ "\xc3\x91", + /* 85 */ "\xc3\x96", + /* 86 */ "\xc3\x9c", + /* 87 */ "\xc3\xa1", + /* 88 */ "\xc3\xa0", + /* 89 */ "\xc3\xa2", + /* 8A */ "\xc3\xa4", + /* 8B */ "\xc3\xa3", + /* 8C */ "\xc3\xa5", + /* 8D */ "\xc3\xa7", + /* 8E */ "\xc3\xa9", + /* 8F */ "\xc3\xa8", + /* 90 */ "\xc3\xaa", + /* 91 */ "\xc3\xab", + /* 92 */ "\xc3\xad", + /* 93 */ "\xc3\xac", + /* 94 */ "\xc3\xae", + /* 95 */ "\xc3\xaf", + /* 96 */ "\xc3\xb1", + /* 97 */ "\xc3\xb3", + /* 98 */ "\xc3\xb2", + /* 99 */ "\xc3\xb4", + /* 9A */ "\xc3\xb6", + /* 9B */ "\xc3\xb5", + /* 9C */ "\xc3\xba", + /* 9D */ "\xc3\xb9", + /* 9E */ "\xc3\xbb", + /* 9F */ "\xc3\xbc", + /* A0 */ "\xe2\x80\xa0", + /* A1 */ "\xc2\xb0", + /* A2 */ "\xc2\xa2", + /* A3 */ "\xc2\xa3", + /* A4 */ "\xc2\xa7", + /* A5 */ "\xe2\x80\xa2", + /* A6 */ "\xc2\xb6", + /* A7 */ "\xc3\x9f", + /* A8 */ "\xc2\xae", + /* A9 */ "\xc2\xa9", + /* AA */ "\xe2\x84\xa2", + /* AB */ "\xc2\xb4", + /* AC */ "\xc2\xa8", + /* AD */ "\xe2\x89\xa0", + /* AE */ "\xc3\x86", + /* AF */ "\xc3\x98", + /* B0 */ "\xe2\x88\x9e", + /* B1 */ "\xc2\xb1", + /* B2 */ "\xe2\x89\xa4", + /* B3 */ "\xe2\x89\xa5", + /* B4 */ "\xc2\xa5", + /* B5 */ "\xc2\xb5", + /* B6 */ "\xe2\x88\x82", + /* B7 */ "\xe2\x88\x91", + /* B8 */ "\xe2\x88\x8f", + /* B9 */ "\xcf\x80", + /* BA */ "\xe2\x88\xab", + /* BB */ "\xc2\xaa", + /* BC */ "\xc2\xba", + /* BD */ "\xce\xa9", + /* BE */ "\xc3\xa6", + /* BF */ "\xc3\xb8", + /* C0 */ "\xc2\xbf", + /* C1 */ "\xc2\xa1", + /* C2 */ "\xc2\xac", + /* C3 */ "\xe2\x88\x9a", + /* C4 */ "\xc6\x92", + /* C5 */ "\xe2\x89\x88", + /* C6 */ "\xe2\x88\x86", + /* C7 */ "\xc2\xab", + /* C8 */ "\xc2\xbb", + /* C9 */ "\xe2\x80\xa6", + /* CA */ "\xc2\xa0", + /* CB */ "\xc3\x80", + /* CC */ "\xc3\x83", + /* CD */ "\xc3\x95", + /* CE */ "\xc5\x92", + /* CF */ "\xc5\x93", + /* D0 */ "\xe2\x80\x93", + /* D1 */ "\xe2\x80\x94", + /* D2 */ "\xe2\x80\x9c", + /* D3 */ "\xe2\x80\x9d", + /* D4 */ "\xe2\x80\x98", + /* D5 */ "\xe2\x80\x99", + /* D6 */ "\xc3\xb7", + /* D7 */ "\xe2\x97\x8a", + /* D8 */ "\xc3\xbf", + /* D9 */ "\xc5\xb8", + /* DA */ "\xe2\x81\x84", + /* DB */ "\xe2\x82\xac", + /* DC */ "\xe2\x80\xb9", + /* DD */ "\xe2\x80\xba", + /* DE */ "\xef\xac\x81", + /* DF */ "\xef\xac\x82", + /* E0 */ "\xe2\x80\xa1", + /* E1 */ "\xc2\xb7", + /* E2 */ "\xe2\x80\x9a", + /* E3 */ "\xe2\x80\x9e", + /* E4 */ "\xe2\x80\xb0", + /* E5 */ "\xc3\x82", + /* E6 */ "\xc3\x8a", + /* E7 */ "\xc3\x81", + /* E8 */ "\xc3\x8b", + /* E9 */ "\xc3\x88", + /* EA */ "\xc3\x8d", + /* EB */ "\xc3\x8e", + /* EC */ "\xc3\x8f", + /* ED */ "\xc3\x8c", + /* EE */ "\xc3\x93", + /* EF */ "\xc3\x94", + /* F0 */ "\xef\xa3\xbf", + /* F1 */ "\xc3\x92", + /* F2 */ "\xc3\x9a", + /* F3 */ "\xc3\x9b", + /* F4 */ "\xc3\x99", + /* F5 */ "\xc4\xb1", + /* F6 */ "\xcb\x86", + /* F7 */ "\xcb\x9c", + /* F8 */ "\xc2\xaf", + /* F9 */ "\xcb\x98", + /* FA */ "\xcb\x99", + /* FB */ "\xcb\x9a", + /* FC */ "\xc2\xb8", + /* FD */ "\xcb\x9d", + /* FE */ "\xcb\x9b", + /* FF */ "\xcb\x87", + }; + +static void +macroman_to_utf8 (char *to, const grub_uint8_t *from, grub_size_t len) +{ + char *optr = to; + const grub_uint8_t *iptr; + + for (iptr = from; iptr < from + len && *iptr; iptr++) + { + /* Translate '/' to ':' as per HFS spec. */ + if (*iptr == '/') + { + *optr++ = ':'; + continue; + } + if (!(*iptr & 0x80)) + { + *optr++ = *iptr; + continue; + } + optr = grub_stpcpy (optr, macroman[*iptr & 0x7f]); + } + *optr = 0; +} + +static grub_ssize_t +utf8_to_macroman (grub_uint8_t *to, const char *from) +{ + grub_uint8_t *end = to + 31; + grub_uint8_t *optr = to; + const char *iptr = from; + + while (*iptr && optr < end) + { + int i, clen; + /* Translate ':' to '/' as per HFS spec. */ + if (*iptr == ':') + { + *optr++ = '/'; + iptr++; + continue; + } + if (!(*iptr & 0x80)) + { + *optr++ = *iptr++; + continue; + } + clen = 2; + if ((*iptr & 0xf0) == 0xe0) + clen++; + for (i = 0; i < 0x80; i++) + if (grub_memcmp (macroman[i], iptr, clen) == 0) + break; + if (i == 0x80) + break; + *optr++ = i | 0x80; + iptr += clen; + } + /* Too long or not encodable. */ + if (*iptr) + return -1; + return optr - to; +} + /* Find a file or directory with the pathname PATH in the filesystem DATA. Return the file record in RETDATA when it is non-zero. @@ -891,6 +1093,7 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path, while (path && grub_strlen (path)) { + grub_ssize_t slen; if (fdrec.frec.type != GRUB_HFS_FILETYPE_DIR) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); @@ -908,14 +1111,19 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path, struct grub_hfs_catalog_key key; key.parent_dir = grub_cpu_to_be32 (inode); - key.strlen = grub_strlen (path); - grub_strcpy ((char *) (key.str), path); + slen = utf8_to_macroman (key.str, path); + if (slen < 0) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path); + goto fail; + } + key.strlen = slen; /* Lookup this node. */ if (! grub_hfs_find_node (data, (char *) &key, data->cat_root, 0, (char *) &fdrec.frec, sizeof (fdrec.frec))) { - grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); goto fail; } @@ -950,20 +1158,37 @@ grub_hfs_dir (grub_device_t device, const char *path, int dir_hook (struct grub_hfs_record *rec) { - char fname[32] = { 0 }; - char *filetype = rec->data; + struct grub_hfs_dirrec *drec = rec->data; + struct grub_hfs_filerec *frec = rec->data; struct grub_hfs_catalog_key *ckey = rec->key; + char fname[sizeof (ckey->str) * MAX_UTF8_PER_MAC_ROMAN + 1] = { 0 }; struct grub_dirhook_info info; + grub_size_t len; + grub_memset (&info, 0, sizeof (info)); - grub_strncpy (fname, (char *) (ckey->str), ckey->strlen); + len = ckey->strlen; + if (len > sizeof (ckey->str)) + len = sizeof (ckey->str); + macroman_to_utf8 (fname, ckey->str, len); - if (*filetype == GRUB_HFS_FILETYPE_DIR - || *filetype == GRUB_HFS_FILETYPE_FILE) + info.case_insensitive = 1; + + if (drec->type == GRUB_HFS_FILETYPE_DIR) { - info.dir = (*filetype == GRUB_HFS_FILETYPE_DIR); + info.dir = 1; + info.mtimeset = 1; + info.mtime = grub_be_to_cpu32 (drec->mtime) - 2082844800; return hook (fname, &info); } + if (frec->type == GRUB_HFS_FILETYPE_FILE) + { + info.dir = 0; + info.mtimeset = 1; + info.mtime = grub_be_to_cpu32 (frec->mtime) - 2082844800; + return hook (fname, &info); + } + return 0; } @@ -1063,8 +1288,15 @@ grub_hfs_label (grub_device_t device, char **label) data = grub_hfs_mount (device->disk); if (data) - *label = grub_strndup ((char *) (data->sblock.volname + 1), - *data->sblock.volname); + { + grub_size_t len = data->sblock.volname[0]; + if (len > sizeof (data->sblock.volname) - 1) + len = sizeof (data->sblock.volname) - 1; + *label = grub_malloc (len * MAX_UTF8_PER_MAC_ROMAN + 1); + if (*label) + macroman_to_utf8 (*label, data->sblock.volname + 1, + len + 1); + } else *label = 0; @@ -1072,6 +1304,22 @@ grub_hfs_label (grub_device_t device, char **label) return grub_errno; } +static grub_err_t +grub_hfs_mtime (grub_device_t device, grub_int32_t *tm) +{ + struct grub_hfs_data *data; + + data = grub_hfs_mount (device->disk); + + if (data) + *tm = grub_be_to_cpu32 (data->sblock.mtime) - 2082844800; + else + *tm = 0; + + grub_free (data); + return grub_errno; +} + static grub_err_t grub_hfs_uuid (grub_device_t device, char **uuid) { @@ -1107,6 +1355,7 @@ static struct grub_fs grub_hfs_fs = .close = grub_hfs_close, .label = grub_hfs_label, .uuid = grub_hfs_uuid, + .mtime = grub_hfs_mtime, .next = 0 }; diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c index bcb8e9584..b20f9f3bb 100644 --- a/grub-core/fs/hfsplus.c +++ b/grub-core/fs/hfsplus.c @@ -30,6 +30,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_HFSPLUS_MAGIC 0x482B #define GRUB_HFSPLUSX_MAGIC 0x4858 #define GRUB_HFSPLUS_SBLOCK 2 @@ -178,8 +180,9 @@ enum grub_hfsplus_filetype /* Internal representation of a catalog key. */ struct grub_hfsplus_catkey_internal { - int parent; - char *name; + grub_uint32_t parent; + const grub_uint16_t *name; + grub_size_t namelen; }; /* Internal representation of an extent overflow key. */ @@ -212,7 +215,7 @@ struct grub_fshelp_node struct grub_hfsplus_btree { grub_uint32_t root; - int nodesize; + grub_size_t nodesize; /* Catalog file node. */ struct grub_fshelp_node file; @@ -234,7 +237,7 @@ struct grub_hfsplus_data /* This is the offset into the physical disk for an embedded HFS+ filesystem (one inside a plain HFS wrapper). */ - int embedded_offset; + grub_disk_addr_t embedded_offset; int case_sensitive; }; @@ -243,15 +246,14 @@ static grub_dl_t my_mod; /* Return the offset of the record with the index INDEX, in the node NODE which is part of the B+ tree BTREE. */ -static inline unsigned int +static inline grub_off_t grub_hfsplus_btree_recoffset (struct grub_hfsplus_btree *btree, struct grub_hfsplus_btnode *node, int index) { char *cnode = (char *) node; - grub_uint16_t *recptr; - recptr = (grub_uint16_t *) (&cnode[btree->nodesize - - index * sizeof (grub_uint16_t) - 2]); - return grub_be_to_cpu16 (*recptr); + void *recptr; + recptr = (&cnode[btree->nodesize - index * sizeof (grub_uint16_t) - 2]); + return grub_be_to_cpu16 (grub_get_unaligned16 (recptr)); } /* Return a pointer to the record with the index INDEX, in the node @@ -261,7 +263,7 @@ grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree, struct grub_hfsplus_btnode *node, int index) { char *cnode = (char *) node; - unsigned int offset; + grub_off_t offset; offset = grub_hfsplus_btree_recoffset (btree, node, index); return (struct grub_hfsplus_key *) &cnode[offset]; } @@ -270,12 +272,12 @@ grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree, /* Find the extent that points to FILEBLOCK. If it is not in one of the 8 extents described by EXTENT, return -1. In that case set FILEBLOCK to the next block. */ -static int +static grub_disk_addr_t grub_hfsplus_find_block (struct grub_hfsplus_extent *extent, - int *fileblock) + grub_disk_addr_t *fileblock) { int i; - grub_size_t blksleft = *fileblock; + grub_disk_addr_t blksleft = *fileblock; /* First lookup the file in the given extents. */ for (i = 0; i < 8; i++) @@ -286,7 +288,7 @@ grub_hfsplus_find_block (struct grub_hfsplus_extent *extent, } *fileblock = blksleft; - return -1; + return 0xffffffffffffffffULL; } static grub_err_t @@ -294,7 +296,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, struct grub_hfsplus_key_internal *key, int (*compare_keys) (struct grub_hfsplus_key *keya, struct grub_hfsplus_key_internal *keyb), - struct grub_hfsplus_btnode **matchnode, int *keyoffset); + struct grub_hfsplus_btnode **matchnode, + grub_off_t *keyoffset); static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya, struct grub_hfsplus_key_internal *keyb); @@ -305,15 +308,15 @@ static grub_disk_addr_t grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_hfsplus_btnode *nnode = 0; - int blksleft = fileblock; + grub_disk_addr_t blksleft = fileblock; struct grub_hfsplus_extent *extents = &node->extents[0]; while (1) { struct grub_hfsplus_extkey *key; - struct grub_hfsplus_extkey_internal extoverflow; - int blk; - int ptr; + struct grub_hfsplus_key_internal extoverflow; + grub_disk_addr_t blk; + grub_off_t ptr; /* Try to find this block in the current set of extents. */ blk = grub_hfsplus_find_block (extents, &blksleft); @@ -323,7 +326,7 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) grub_free (nnode); nnode = 0; - if (blk != -1) + if (blk != 0xffffffffffffffffULL) return (blk + (node->data->embedded_offset >> (node->data->log2blksize - GRUB_DISK_SECTOR_BITS))); @@ -339,11 +342,11 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) } /* Set up the key to look for in the extent overflow file. */ - extoverflow.fileid = node->fileid; - extoverflow.start = fileblock - blksleft; + extoverflow.extkey.fileid = node->fileid; + extoverflow.extkey.start = fileblock - blksleft; if (grub_hfsplus_btree_search (&node->data->extoverflow_tree, - (struct grub_hfsplus_key_internal *) &extoverflow, + &extoverflow, grub_hfsplus_cmp_extkey, &nnode, &ptr)) { grub_error (GRUB_ERR_READ_ERROR, @@ -374,7 +377,7 @@ static grub_ssize_t grub_hfsplus_read_file (grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { return grub_fshelp_read_file (node->data->disk, node, read_hook, pos, len, buf, grub_hfsplus_read_block, @@ -409,9 +412,9 @@ grub_hfsplus_mount (grub_disk_t disk) data->embedded_offset = 0; if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC) { - int extent_start; - int ablk_size; - int ablk_start; + grub_disk_addr_t extent_start; + grub_disk_addr_t ablk_size; + grub_disk_addr_t ablk_start; /* See if there's an embedded HFS+ filesystem. */ if (grub_be_to_cpu16 (volheader.hfs.embed_sig) != GRUB_HFSPLUS_MAGIC) @@ -516,37 +519,46 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya, { struct grub_hfsplus_catkey *catkey_a = &keya->catkey; struct grub_hfsplus_catkey_internal *catkey_b = &keyb->catkey; - char *filename; - int i; int diff; + grub_size_t len; - diff = grub_be_to_cpu32 (catkey_a->parent) - catkey_b->parent; - if (diff) - return diff; + /* Safe unsigned comparison */ + grub_uint32_t aparent = grub_be_to_cpu32 (catkey_a->parent); + if (aparent > catkey_b->parent) + return 1; + if (aparent < catkey_b->parent) + return -1; - /* Change the filename in keya so the endianness is correct. */ - for (i = 0; i < grub_be_to_cpu16 (catkey_a->namelen); i++) - catkey_a->name[i] = grub_be_to_cpu16 (catkey_a->name[i]); + len = grub_be_to_cpu16 (catkey_a->namelen); + if (len > catkey_b->namelen) + len = catkey_b->namelen; + diff = grub_memcmp (catkey_a->name, catkey_b->name, + len * sizeof (catkey_a->name[0])); + if (diff == 0) + diff = grub_be_to_cpu16 (catkey_a->namelen) - catkey_b->namelen; - filename = grub_malloc (grub_be_to_cpu16 (catkey_a->namelen) + 1); - - if (! grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey_a->name, - grub_be_to_cpu16 (catkey_a->namelen))) - return -1; /* XXX: This error never occurs, but in case it happens - just skip this entry. */ - - diff = grub_strncmp (filename, catkey_b->name, - grub_be_to_cpu16 (catkey_a->namelen)); - - grub_free (filename); - - /* The endianness was changed to host format, change it back to - whatever it was. */ - for (i = 0; i < grub_be_to_cpu16 (catkey_a->namelen); i++) - catkey_a->name[i] = grub_cpu_to_be16 (catkey_a->name[i]); return diff; } +/* Compare the on disk catalog key KEYA with the catalog key we are + looking for (KEYB). */ +static int +grub_hfsplus_cmp_catkey_id (struct grub_hfsplus_key *keya, + struct grub_hfsplus_key_internal *keyb) +{ + struct grub_hfsplus_catkey *catkey_a = &keya->catkey; + struct grub_hfsplus_catkey_internal *catkey_b = &keyb->catkey; + + /* Safe unsigned comparison */ + grub_uint32_t aparent = grub_be_to_cpu32 (catkey_a->parent); + if (aparent > catkey_b->parent) + return 1; + if (aparent < catkey_b->parent) + return -1; + + return 0; +} + /* Compare the on disk extent overflow key KEYA with the extent overflow key we are looking for (KEYB). */ static int @@ -555,15 +567,21 @@ grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya, { struct grub_hfsplus_extkey *extkey_a = &keya->extkey; struct grub_hfsplus_extkey_internal *extkey_b = &keyb->extkey; - int diff; + grub_uint32_t akey; - diff = grub_be_to_cpu32 (extkey_a->fileid) - extkey_b->fileid; - - if (diff) - return diff; - - diff = grub_be_to_cpu32 (extkey_a->start) - extkey_b->start; - return diff; + /* Safe unsigned comparison */ + akey = grub_be_to_cpu32 (extkey_a->fileid); + if (akey > extkey_b->fileid) + return 1; + if (akey < extkey_b->fileid) + return -1; + + akey = grub_be_to_cpu32 (extkey_a->start); + if (akey > extkey_b->start) + return 1; + if (akey < extkey_b->start) + return -1; + return 0; } static char * @@ -590,10 +608,10 @@ grub_hfsplus_read_symlink (grub_fshelp_node_t node) static int grub_hfsplus_btree_iterate_node (struct grub_hfsplus_btree *btree, struct grub_hfsplus_btnode *first_node, - int first_rec, + grub_disk_addr_t first_rec, int (*hook) (void *record)) { - int rec; + grub_disk_addr_t rec; for (;;) { @@ -631,12 +649,13 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, struct grub_hfsplus_key_internal *key, int (*compare_keys) (struct grub_hfsplus_key *keya, struct grub_hfsplus_key_internal *keyb), - struct grub_hfsplus_btnode **matchnode, int *keyoffset) + struct grub_hfsplus_btnode **matchnode, + grub_off_t *keyoffset) { grub_uint64_t currnode; char *node; struct grub_hfsplus_btnode *nodedesc; - int rec; + grub_disk_addr_t rec; node = grub_malloc (btree->nodesize); if (! node) @@ -649,7 +668,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, /* Read a node. */ if (grub_hfsplus_read_file (&btree->file, 0, - (long)currnode * (long)btree->nodesize, + (grub_disk_addr_t) currnode + * (grub_disk_addr_t) btree->nodesize, btree->nodesize, (char *) node) <= 0) { grub_free (node); @@ -678,7 +698,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, } else if (nodedesc->type == GRUB_HFSPLUS_BTNODE_TYPE_INDEX) { - grub_uint32_t *pointer; + void *pointer; /* The place where the key could have been found didn't contain the key. This means that the previous match @@ -690,10 +710,10 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, that we are looking for. The last match that is found will be used to locate the child which can contain the record. */ - pointer = (grub_uint32_t *) ((char *) currkey - + grub_be_to_cpu16 (currkey->keylen) - + 2); - currnode = grub_be_to_cpu32 (*pointer); + pointer = ((char *) currkey + + grub_be_to_cpu16 (currkey->keylen) + + 2); + currnode = grub_be_to_cpu32 (grub_get_unaligned32 (pointer)); match = 1; } } @@ -759,53 +779,51 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir, if (type == GRUB_FSHELP_UNKNOWN) return 0; + filename = grub_malloc (grub_be_to_cpu16 (catkey->namelen) + * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (! filename) + return 0; + /* Make sure the byte order of the UTF16 string is correct. */ for (i = 0; i < grub_be_to_cpu16 (catkey->namelen); i++) { catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]); + if (catkey->name[i] == '/') + catkey->name[i] = ':'; + /* If the name is obviously invalid, skip this node. */ if (catkey->name[i] == 0) return 0; } - filename = grub_malloc (grub_be_to_cpu16 (catkey->namelen) + 1); - if (! filename) - return 0; - - if (! grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name, - grub_be_to_cpu16 (catkey->namelen))) - { - grub_free (filename); - return 0; - } - - filename[grub_be_to_cpu16 (catkey->namelen)] = '\0'; + *grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name, + grub_be_to_cpu16 (catkey->namelen)) = '\0'; /* Restore the byte order to what it was previously. */ for (i = 0; i < grub_be_to_cpu16 (catkey->namelen); i++) - catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]); + { + if (catkey->name[i] == ':') + catkey->name[i] = '/'; + catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]); + } /* hfs+ is case insensitive. */ if (! dir->data->case_sensitive) type |= GRUB_FSHELP_CASE_INSENSITIVE; - /* Only accept valid nodes. */ - if (grub_strlen (filename) == grub_be_to_cpu16 (catkey->namelen)) - { - /* A valid node is found; setup the node and call the - callback function. */ - node = grub_malloc (sizeof (*node)); - node->data = dir->data; + /* A valid node is found; setup the node and call the + callback function. */ + node = grub_malloc (sizeof (*node)); + node->data = dir->data; - grub_memcpy (node->extents, fileinfo->data.extents, - sizeof (node->extents)); - node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800; - node->size = grub_be_to_cpu64 (fileinfo->data.size); - node->fileid = grub_be_to_cpu32 (fileinfo->fileid); + grub_memcpy (node->extents, fileinfo->data.extents, + sizeof (node->extents)); + node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800; + node->size = grub_be_to_cpu64 (fileinfo->data.size); + node->fileid = grub_be_to_cpu32 (fileinfo->fileid); - ret = hook (filename, type, node); - } + ret = hook (filename, type, node); grub_free (filename); @@ -814,11 +832,12 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir, struct grub_hfsplus_key_internal intern; struct grub_hfsplus_btnode *node; - int ptr; + grub_disk_addr_t ptr; /* Create a key that points to the first entry in the directory. */ intern.catkey.parent = dir->fileid; - intern.catkey.name = ""; + intern.catkey.name = 0; + intern.catkey.namelen = 0; /* First lookup the first entry. */ if (grub_hfsplus_btree_search (&dir->data->catalog_tree, &intern, @@ -883,7 +902,6 @@ grub_hfsplus_close (grub_file_t file) return GRUB_ERR_NONE; } - /* Read LEN bytes data from FILE into BUF. */ static grub_ssize_t grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len) @@ -891,13 +909,10 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len) struct grub_hfsplus_data *data = (struct grub_hfsplus_data *) file->data; - int size = grub_hfsplus_read_file (&data->opened_file, file->read_hook, + return grub_hfsplus_read_file (&data->opened_file, file->read_hook, file->offset, len, buf); - - return size; } - static grub_err_t grub_hfsplus_dir (grub_device_t device, const char *path, int (*hook) (const char *filename, @@ -952,13 +967,59 @@ grub_hfsplus_dir (grub_device_t device, const char *path, static grub_err_t -grub_hfsplus_label (grub_device_t device __attribute__((unused)) - , char **label __attribute__((unused))) +grub_hfsplus_label (grub_device_t device, char **label) { - /* XXX: It's not documented how to read a label. */ - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "reading the label of a HFS+ " - "partition is not implemented"); + struct grub_hfsplus_data *data; + grub_disk_t disk = device->disk; + struct grub_hfsplus_catkey *catkey; + int i, label_len; + struct grub_hfsplus_key_internal intern; + struct grub_hfsplus_btnode *node; + grub_disk_addr_t ptr; + + *label = 0; + + data = grub_hfsplus_mount (disk); + if (!data) + return grub_errno; + + /* Create a key that points to the label. */ + intern.catkey.parent = 1; + intern.catkey.name = 0; + intern.catkey.namelen = 0; + + /* First lookup the first entry. */ + if (grub_hfsplus_btree_search (&data->catalog_tree, &intern, + grub_hfsplus_cmp_catkey_id, &node, &ptr)) + { + grub_free (data); + return 0; + } + + catkey = (struct grub_hfsplus_catkey *) + grub_hfsplus_btree_recptr (&data->catalog_tree, node, 0); + + label_len = grub_be_to_cpu16 (catkey->namelen); + for (i = 0; i < label_len; i++) + { + catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]); + + /* If the name is obviously invalid, skip this node. */ + if (catkey->name[i] == 0) + return 0; + } + + *label = grub_malloc (label_len * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (! *label) + return grub_errno; + + *grub_utf16_to_utf8 ((grub_uint8_t *) (*label), catkey->name, + label_len) = '\0'; + + grub_free (node); + grub_free (data); + + return GRUB_ERR_NONE; } /* Get mtime. */ diff --git a/grub-core/fs/i386/pc/pxe.c b/grub-core/fs/i386/pc/pxe.c deleted file mode 100644 index cbb3c7d87..000000000 --- a/grub-core/fs/i386/pc/pxe.c +++ /dev/null @@ -1,641 +0,0 @@ -/* pxe.c - Driver to provide access to the pxe filesystem */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SEGMENT(x) ((x) >> 4) -#define OFFSET(x) ((x) & 0xF) -#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x)) -#define LINEAR(x) (void *) (((x >> 16) <<4) + (x & 0xFFFF)) - -struct grub_pxe_disk_data -{ - grub_uint32_t server_ip; - grub_uint32_t gateway_ip; -}; - -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; -static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE; - -static grub_file_t curr_file = 0; - -struct grub_pxe_data -{ - grub_uint32_t packet_number; - grub_uint32_t block_size; - 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)) -{ - if (hook ("pxe")) - return 1; - return 0; -} - -static grub_err_t -parse_ip (const char *val, grub_uint32_t *ip, const char **rest) -{ - grub_uint32_t newip = 0; - unsigned long t; - int i; - const char *ptr = val; - - for (i = 0; i < 4; i++) - { - t = grub_strtoul (ptr, (char **) &ptr, 0); - if (grub_errno) - return grub_errno; - if (t & ~0xff) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); - newip >>= 8; - newip |= (t << 24); - if (i != 3 && *ptr != '.') - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP."); - ptr++; - } - *ip = newip; - if (rest) - *rest = ptr - 1; - return 0; -} - -static grub_err_t -grub_pxe_open (const char *name, grub_disk_t disk) -{ - struct grub_pxe_disk_data *data; - - if (grub_strcmp (name, "pxe") != 0 - && grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk"); - - data = grub_malloc (sizeof (*data)); - if (!data) - return grub_errno; - - if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) - { - const char *ptr; - grub_err_t err; - - ptr = name + sizeof ("pxe:") - 1; - err = parse_ip (ptr, &(data->server_ip), &ptr); - if (err) - return err; - if (*ptr == ':') - { - err = parse_ip (ptr + 1, &(data->gateway_ip), 0); - if (err) - return err; - } - else - data->gateway_ip = grub_pxe_default_gateway_ip; - } - else - { - data->server_ip = grub_pxe_default_server_ip; - data->gateway_ip = grub_pxe_default_gateway_ip; - } - - disk->total_sectors = 0; - disk->id = (unsigned long) data; - - disk->data = data; - - return GRUB_ERR_NONE; -} - -static void -grub_pxe_close (grub_disk_t disk) -{ - grub_free (disk->data); -} - -static grub_err_t -grub_pxe_read (grub_disk_t disk __attribute((unused)), - grub_disk_addr_t sector __attribute((unused)), - grub_size_t size __attribute((unused)), - char *buf __attribute((unused))) -{ - return GRUB_ERR_OUT_OF_RANGE; -} - -static grub_err_t -grub_pxe_write (grub_disk_t disk __attribute((unused)), - grub_disk_addr_t sector __attribute((unused)), - grub_size_t size __attribute((unused)), - const char *buf __attribute((unused))) -{ - return GRUB_ERR_OUT_OF_RANGE; -} - -static struct grub_disk_dev grub_pxe_dev = - { - .name = "pxe", - .id = GRUB_DISK_DEVICE_PXE_ID, - .iterate = grub_pxe_iterate, - .open = grub_pxe_open, - .close = grub_pxe_close, - .read = grub_pxe_read, - .write = grub_pxe_write, - .next = 0 - }; - -static grub_err_t -grub_pxefs_dir (grub_device_t device, - const char *path __attribute__ ((unused)), - int (*hook) (const char *filename, - const struct grub_dirhook_info *info) - __attribute__ ((unused))) -{ - if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) - return grub_error (GRUB_ERR_IO, "not a pxe disk"); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_pxefs_open (struct grub_file *file, const char *name) -{ - union - { - struct grub_pxenv_tftp_get_fsize c1; - struct grub_pxenv_tftp_open c2; - } c; - struct grub_pxe_data *data; - struct grub_pxe_disk_data *disk_data = file->device->disk->data; - grub_file_t file_int, bufio; - - if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID) - return grub_error (GRUB_ERR_IO, "not a pxe disk"); - - if (curr_file != 0) - { - 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, pxe_rm_entry); - if (c.c1.status) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); - - file->size = c.c1.file_size; - - 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, pxe_rm_entry); - if (c.c2.status) - return grub_error (GRUB_ERR_BAD_FS, "open fails"); - - data = grub_zalloc (sizeof (struct grub_pxe_data) + grub_strlen (name) + 1); - if (! data) - return grub_errno; - - data->block_size = c.c2.packet_size; - grub_strcpy (data->filename, name); - - file_int = grub_malloc (sizeof (*file_int)); - if (! file_int) - { - grub_free (data); - return grub_errno; - } - - file->data = data; - file->not_easly_seekable = 1; - grub_memcpy (file_int, file, sizeof (struct grub_file)); - curr_file = file_int; - - bufio = grub_bufio_open (file_int, data->block_size); - if (! bufio) - { - grub_free (file_int); - grub_free (data); - return grub_errno; - } - - grub_memcpy (file, bufio, sizeof (struct grub_file)); - - return GRUB_ERR_NONE; -} - -static grub_ssize_t -grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len) -{ - struct grub_pxenv_tftp_read c; - struct grub_pxe_data *data; - struct grub_pxe_disk_data *disk_data = file->device->disk->data; - grub_uint32_t pn, r; - - data = file->data; - - pn = grub_divmod64 (file->offset, data->block_size, &r); - if (r) - { - grub_error (GRUB_ERR_BAD_FS, - "read access must be aligned to packet size"); - return -1; - } - - if ((curr_file != file) || (data->packet_number > pn)) - { - struct grub_pxenv_tftp_open o; - - if (curr_file != 0) - 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 = 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"); - return -1; - } - data->block_size = o.packet_size; - data->packet_number = 0; - curr_file = file; - } - - c.buffer = SEGOFS (GRUB_MEMORY_MACHINE_SCRATCH_ADDR); - while (pn >= data->packet_number) - { - c.buffer_size = data->block_size; - grub_pxe_call (GRUB_PXENV_TFTP_READ, &c, pxe_rm_entry); - if (c.status) - { - grub_error (GRUB_ERR_BAD_FS, "read fails"); - return -1; - } - data->packet_number++; - } - - grub_memcpy (buf, (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, len); - - return len; -} - -static grub_err_t -grub_pxefs_close (grub_file_t file) -{ - struct grub_pxenv_tftp_close c; - - if (curr_file == file) - { - grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c, pxe_rm_entry); - curr_file = 0; - } - - grub_free (file->data); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_pxefs_label (grub_device_t device __attribute ((unused)), - char **label __attribute ((unused))) -{ - *label = 0; - return GRUB_ERR_NONE; -} - -static struct grub_fs grub_pxefs_fs = - { - .name = "pxefs", - .dir = grub_pxefs_dir, - .open = grub_pxefs_open, - .read = grub_pxefs_read, - .close = grub_pxefs_close, - .label = grub_pxefs_label, - .next = 0 - }; - -static char * -grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), - const char *val __attribute__ ((unused))) -{ - return NULL; -} - -static void -set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len) -{ - char buf[(sizeof ("XX:") - 1) * mac_len + 1]; - char *ptr = buf; - unsigned i; - - for (i = 0; i < mac_len; i++) - { - grub_snprintf (ptr, sizeof (buf) - (ptr - buf), - "%02x:", mac_addr[i] & 0xff); - ptr += (sizeof ("XX:") - 1); - } - if (mac_len) - *(ptr - 1) = 0; - else - buf[0] = 0; - - grub_env_set ("net_pxe_mac", buf); - /* XXX: Is it possible to change MAC in PXE? */ - grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly); -} - -static void -set_env_limn_ro (const char *varname, char *value, grub_size_t len) -{ - char c; - c = value[len]; - value[len] = 0; - grub_env_set (varname, value); - value[len] = c; - grub_register_variable_hook (varname, 0, grub_env_write_readonly); -} - -static void -parse_dhcp_vendor (void *vend, int limit) -{ - grub_uint8_t *ptr, *ptr0; - - ptr = ptr0 = vend; - - if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363) - return; - ptr = ptr + sizeof (grub_uint32_t); - while (ptr - ptr0 < limit) - { - grub_uint8_t tagtype; - grub_uint8_t taglength; - - tagtype = *ptr++; - - /* Pad tag. */ - if (tagtype == 0) - continue; - - /* End tag. */ - if (tagtype == 0xff) - return; - - taglength = *ptr++; - - switch (tagtype) - { - case 12: - set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength); - break; - - case 15: - set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength); - break; - - case 17: - set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength); - break; - - case 18: - set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength); - break; - - /* If you need any other options please contact GRUB - developpement team. */ - } - - ptr += taglength; - } -} - -static void -grub_pxe_detect (void) -{ - struct grub_pxe_bangpxe *pxenv; - struct grub_pxenv_get_cached_info ci; - struct grub_pxenv_boot_player *bp; - - pxenv = grub_pxe_scan (); - if (! pxenv) - return; - - 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, pxe_rm_entry); - if (ci.status) - return; - - bp = LINEAR (ci.buffer); - - grub_pxe_your_ip = bp->your_ip; - grub_pxe_default_server_ip = bp->server_ip; - grub_pxe_default_gateway_ip = bp->gateway_ip; - set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len - : sizeof (bp->mac_addr)); - set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file, - sizeof (bp->boot_file)); - set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name, - sizeof (bp->server_name)); - parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor)); - grub_pxe_pxenv = pxenv; -} - -void -grub_pxe_unload (void) -{ - if (grub_pxe_pxenv) - { - grub_fs_unregister (&grub_pxefs_fs); - grub_disk_dev_unregister (&grub_pxe_dev); - - grub_pxe_pxenv = 0; - } -} - -static void -set_ip_env (char *varname, grub_uint32_t ip) -{ - char buf[sizeof ("XXX.XXX.XXX.XXX")]; - - grub_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff), - (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff); - grub_env_set (varname, buf); -} - -static char * -write_ip_env (grub_uint32_t *ip, const char *val) -{ - char *buf; - grub_err_t err; - grub_uint32_t newip; - - err = parse_ip (val, &newip, 0); - if (err) - return 0; - - /* Normalize the IP. */ - buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff, - (newip >> 16) & 0xff, (newip >> 24) & 0xff); - if (!buf) - return 0; - - *ip = newip; - - return buf; -} - -static char * -grub_env_write_pxe_default_server (struct grub_env_var *var - __attribute__ ((unused)), - const char *val) -{ - return write_ip_env (&grub_pxe_default_server_ip, val); -} - -static char * -grub_env_write_pxe_default_gateway (struct grub_env_var *var - __attribute__ ((unused)), - const char *val) -{ - return write_ip_env (&grub_pxe_default_gateway_ip, val); -} - -static char * -grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)), - const char *val) -{ - unsigned size; - char *buf; - - size = grub_strtoul (val, 0, 0); - if (grub_errno) - return 0; - - if (size < GRUB_PXE_MIN_BLKSIZE) - size = GRUB_PXE_MIN_BLKSIZE; - else if (size > GRUB_PXE_MAX_BLKSIZE) - size = GRUB_PXE_MAX_BLKSIZE; - - buf = grub_xasprintf ("%d", size); - if (!buf) - return 0; - - grub_pxe_blksize = size; - - return buf; -} - - -GRUB_MOD_INIT(pxe) -{ - grub_pxe_detect (); - if (grub_pxe_pxenv) - { - char *buf; - - buf = grub_xasprintf ("%d", grub_pxe_blksize); - if (buf) - grub_env_set ("pxe_blksize", buf); - grub_free (buf); - - set_ip_env ("pxe_default_server", grub_pxe_default_server_ip); - set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip); - set_ip_env ("net_pxe_ip", grub_pxe_your_ip); - grub_register_variable_hook ("pxe_default_server", 0, - grub_env_write_pxe_default_server); - grub_register_variable_hook ("pxe_default_gateway", 0, - grub_env_write_pxe_default_gateway); - - /* XXX: Is it possible to change IP in PXE? */ - grub_register_variable_hook ("net_pxe_ip", 0, - grub_env_write_readonly); - grub_register_variable_hook ("pxe_blksize", 0, - grub_env_write_pxe_blocksize); - grub_disk_dev_register (&grub_pxe_dev); - grub_fs_register (&grub_pxefs_fs); - } -} - -GRUB_MOD_FINI(pxe) -{ - grub_pxe_unload (); -} diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c index 6dc465f25..fb5da2aa7 100644 --- a/grub-core/fs/iso9660.c +++ b/grub-core/fs/iso9660.c @@ -27,6 +27,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_ISO9660_FSTYPE_DIR 0040000 #define GRUB_ISO9660_FSTYPE_REG 0100000 @@ -53,6 +56,17 @@ struct grub_iso9660_voldesc grub_uint8_t version; } __attribute__ ((packed)); +struct grub_iso9660_date2 +{ + grub_uint8_t year; + grub_uint8_t month; + grub_uint8_t day; + grub_uint8_t hour; + grub_uint8_t minute; + grub_uint8_t second; + grub_uint8_t offset; +} __attribute__ ((packed)); + /* A directory entry. */ struct grub_iso9660_dir { @@ -62,7 +76,7 @@ struct grub_iso9660_dir grub_uint32_t first_sector_be; grub_uint32_t size; grub_uint32_t size_be; - grub_uint8_t unused1[7]; + struct grub_iso9660_date2 mtime; grub_uint8_t flags; grub_uint8_t unused2[6]; grub_uint8_t namelen; @@ -135,53 +149,149 @@ struct grub_iso9660_data { struct grub_iso9660_primary_voldesc voldesc; grub_disk_t disk; - unsigned int first_sector; int rockridge; int susp_skip; int joliet; + struct grub_fshelp_node *node; }; struct grub_fshelp_node { struct grub_iso9660_data *data; - unsigned int size; - unsigned int blk; - unsigned int dir_blk; - unsigned int dir_off; + grub_size_t have_dirents, alloc_dirents; + int have_symlink; + struct grub_iso9660_dir dirents[8]; + char symlink[0]; }; +enum + { + FLAG_TYPE_PLAIN = 0, + FLAG_TYPE_DIR = 2, + FLAG_TYPE = 3, + FLAG_MORE_EXTENTS = 0x80 + }; + static grub_dl_t my_mod; +static grub_err_t +iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix) +{ + struct grub_datetime datetime; + + if (! i->year[0] && ! i->year[1] + && ! i->year[2] && ! i->year[3] + && ! i->month[0] && ! i->month[1] + && ! i->day[0] && ! i->day[1] + && ! i->hour[0] && ! i->hour[1] + && ! i->minute[0] && ! i->minute[1] + && ! i->second[0] && ! i->second[1] + && ! i->hundredth[0] && ! i->hundredth[1]) + return grub_error (GRUB_ERR_BAD_NUMBER, "empty date"); + datetime.year = (i->year[0] - '0') * 1000 + (i->year[1] - '0') * 100 + + (i->year[2] - '0') * 10 + (i->year[3] - '0'); + datetime.month = (i->month[0] - '0') * 10 + (i->month[1] - '0'); + datetime.day = (i->day[0] - '0') * 10 + (i->day[1] - '0'); + datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0'); + datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0'); + datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0'); + + if (!grub_datetime2unixtime (&datetime, nix)) + return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date"); + *nix -= i->offset * 60 * 15; + return GRUB_ERR_NONE; +} + +static int +iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix) +{ + struct grub_datetime datetime; + + datetime.year = i->year + 1900; + datetime.month = i->month; + datetime.day = i->day; + datetime.hour = i->hour; + datetime.minute = i->minute; + datetime.second = i->second; + + if (!grub_datetime2unixtime (&datetime, nix)) + return 0; + *nix -= i->offset * 60 * 15; + return 1; +} + +static grub_err_t +read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf) +{ + grub_size_t i = 0; + + while (len > 0) + { + grub_size_t toread; + grub_err_t err; + while (i < node->have_dirents + && off >= grub_le_to_cpu32 (node->dirents[i].size)) + { + off -= grub_le_to_cpu32 (node->dirents[i].size); + i++; + } + if (i == node->have_dirents) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range"); + toread = grub_le_to_cpu32 (node->dirents[i].size); + if (toread > len) + toread = len; + err = grub_disk_read (node->data->disk, + ((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ, + off, toread, buf); + if (err) + return err; + len -= toread; + off += toread; + buf += toread; + } + return GRUB_ERR_NONE; +} + /* Iterate over the susp entries, starting with block SUA_BLOCK on the offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for every entry. */ static grub_err_t -grub_iso9660_susp_iterate (struct grub_iso9660_data *data, - int sua_block, int sua_pos, int sua_size, +grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off, + grub_ssize_t sua_size, grub_err_t (*hook) (struct grub_iso9660_susp_entry *entry)) { char *sua; struct grub_iso9660_susp_entry *entry; + grub_disk_addr_t ce_block; + int is_ce = 0; auto grub_err_t load_sua (void); /* Load a part of the System Usage Area. */ grub_err_t load_sua (void) { + grub_err_t err; sua = grub_malloc (sua_size); if (!sua) return grub_errno; - if (grub_disk_read (data->disk, sua_block, sua_pos, - sua_size, sua)) - return grub_errno; + if (is_ce) + err = grub_disk_read (node->data->disk, ce_block, off, + sua_size, sua); + else + err = read_node (node, off, sua_size, sua); + if (err) + return err; entry = (struct grub_iso9660_susp_entry *) sua; return 0; } + if (sua_size <= 0) + return GRUB_ERR_NONE; + if (load_sua ()) return grub_errno; @@ -198,10 +308,11 @@ grub_iso9660_susp_iterate (struct grub_iso9660_data *data, { struct grub_iso9660_susp_ce *ce; + is_ce = 1; ce = (struct grub_iso9660_susp_ce *) entry; sua_size = grub_le_to_cpu32 (ce->len); - sua_pos = grub_le_to_cpu32 (ce->off); - sua_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ; + off = grub_le_to_cpu32 (ce->off); + ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ; grub_free (sua); if (load_sua ()) @@ -220,34 +331,32 @@ grub_iso9660_susp_iterate (struct grub_iso9660_data *data, } static char * -grub_iso9660_convert_string (grub_uint16_t *us, int len) +grub_iso9660_convert_string (grub_uint8_t *us, int len) { char *p; int i; + grub_uint16_t t[len]; - p = grub_malloc (len * 4 + 1); + p = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1); if (! p) return p; for (i=0; irockridge = 0; + + /* Read the system use area and test it to see if SUSP is + supported. */ + if (grub_disk_read (data->disk, + (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) + << GRUB_ISO9660_LOG2_BLKSZ), 0, + sizeof (rootdir), (char *) &rootdir)) + return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + + sua_pos = (sizeof (rootdir) + rootdir.namelen + + (rootdir.namelen % 2) - 1); + sua_size = rootdir.len - sua_pos; + + if (!sua_size) + return GRUB_ERR_NONE; + + sua = grub_malloc (sua_size); + if (! sua) + return grub_errno; + + if (grub_disk_read (data->disk, + (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) + << GRUB_ISO9660_LOG2_BLKSZ), sua_pos, + sua_size, sua)) + { + grub_free (sua); + return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + } + + entry = (struct grub_iso9660_susp_entry *) sua; + + /* Test if the SUSP protocol is used on this filesystem. */ + if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0) + { + struct grub_fshelp_node rootnode; + + rootnode.data = data; + rootnode.alloc_dirents = ARRAY_SIZE (rootnode.dirents); + rootnode.have_dirents = 1; + rootnode.have_symlink = 0; + rootnode.dirents[0] = data->voldesc.rootdir; + + /* The 2nd data byte stored how many bytes are skipped every time + to get to the SUA (System Usage Area). */ + data->susp_skip = entry->data[2]; + entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len); + + /* Iterate over the entries in the SUA area to detect + extensions. */ + if (grub_iso9660_susp_iterate (&rootnode, + sua_pos, sua_size, susp_iterate)) + { + grub_free (sua); + return grub_errno; + } + } + grub_free (sua); + return GRUB_ERR_NONE; +} + +static struct grub_iso9660_data * +grub_iso9660_mount (grub_disk_t disk) +{ + struct grub_iso9660_data *data = 0; + struct grub_iso9660_primary_voldesc voldesc; + int block; + data = grub_zalloc (sizeof (struct grub_iso9660_data)); if (! data) return 0; @@ -290,9 +467,11 @@ grub_iso9660_mount (grub_disk_t disk) } if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY) - copy_voldesc = 1; - else if ((voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP) && - (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f) && + copy_voldesc = 1; + else if (!data->rockridge + && (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP) + && (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f) + && ((voldesc.escape[2] == 0x40) || /* UCS-2 Level 1. */ (voldesc.escape[2] == 0x43) || /* UCS-2 Level 2. */ (voldesc.escape[2] == 0x45))) /* UCS-2 Level 3. */ @@ -302,57 +481,16 @@ grub_iso9660_mount (grub_disk_t disk) } if (copy_voldesc) - grub_memcpy((char *) &data->voldesc, (char *) &voldesc, - sizeof (struct grub_iso9660_primary_voldesc)); + { + grub_memcpy((char *) &data->voldesc, (char *) &voldesc, + sizeof (struct grub_iso9660_primary_voldesc)); + if (set_rockridge (data)) + goto fail; + } block++; } while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END); - /* Read the system use area and test it to see if SUSP is - supported. */ - if (grub_disk_read (disk, (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) - << GRUB_ISO9660_LOG2_BLKSZ), 0, - sizeof (rootdir), (char *) &rootdir)) - { - grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); - goto fail; - } - - sua_pos = (sizeof (rootdir) + rootdir.namelen - + (rootdir.namelen % 2) - 1); - sua_size = rootdir.len - sua_pos; - - sua = grub_malloc (sua_size); - if (! sua) - goto fail; - - if (grub_disk_read (disk, (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) - << GRUB_ISO9660_LOG2_BLKSZ), sua_pos, - sua_size, sua)) - { - grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); - goto fail; - } - - entry = (struct grub_iso9660_susp_entry *) sua; - - /* Test if the SUSP protocol is used on this filesystem. */ - if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0) - { - /* The 2nd data byte stored how many bytes are skipped every time - to get to the SUA (System Usage Area). */ - data->susp_skip = entry->data[2]; - entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len); - - /* Iterate over the entries in the SUA area to detect - extensions. */ - if (grub_iso9660_susp_iterate (data, - (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) - << GRUB_ISO9660_LOG2_BLKSZ), - sua_pos, sua_size, susp_iterate)) - goto fail; - } - return data; fail: @@ -364,43 +502,125 @@ grub_iso9660_mount (grub_disk_t disk) static char * grub_iso9660_read_symlink (grub_fshelp_node_t node) { - struct grub_iso9660_dir dirent; - int sua_off; - int sua_size; - char *symlink = 0; - int addslash = 0; + return node->have_symlink + ? grub_strdup (node->symlink + + (node->have_dirents) * sizeof (node->dirents[0]) + - sizeof (node->dirents)) : grub_strdup (""); +} - auto void add_part (const char *part, int len); - auto grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *); +static grub_off_t +get_node_size (grub_fshelp_node_t node) +{ + grub_off_t ret = 0; + grub_size_t i; + + for (i = 0; i < node->have_dirents; i++) + ret += grub_le_to_cpu32 (node->dirents[i].size); + return ret; +} + +static int +grub_iso9660_iterate_dir (grub_fshelp_node_t dir, + int NESTED_FUNC_ATTR + (*hook) (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node)) +{ + struct grub_iso9660_dir dirent; + grub_off_t offset = 0; + char *filename = 0; + int filename_alloc = 0; + enum grub_fshelp_filetype type; + grub_off_t len; + char *symlink = 0; /* Extend the symlink. */ - void add_part (const char *part, int len) - { - int size = grub_strlen (symlink); + auto inline void __attribute__ ((always_inline)) add_part (const char *part, + int len2); - symlink = grub_realloc (symlink, size + len + 1); + auto inline void __attribute__ ((always_inline)) add_part (const char *part, + int len2) + { + int size = symlink ? grub_strlen (symlink) : 0; + + symlink = grub_realloc (symlink, size + len2 + 1); if (! symlink) return; - grub_strncat (symlink, part, len); + symlink[size] = 0; + grub_strncat (symlink, part, len2); } - /* Read in a symlink. */ - grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *entry) + auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *); + + grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *entry) { - if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0) + /* The filename in the rock ridge entry. */ + if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0) + { + /* The flags are stored at the data position 0, here the + filename type is stored. */ + if (entry->data[0] & GRUB_ISO9660_RR_DOT) + filename = "."; + else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT) + filename = ".."; + else if (entry->len >= 5) + { + grub_size_t size = 1, csize = 1; + char *old; + csize = size = entry->len - 5; + old = filename; + if (filename_alloc) + { + size += grub_strlen (filename); + filename = grub_realloc (filename, size + 1); + } + else + { + filename_alloc = 1; + filename = grub_zalloc (size + 1); + filename[0] = 0; + } + if (!filename) + { + filename = old; + return grub_errno; + } + filename_alloc = 1; + grub_strncat (filename, (char *) &entry->data[1], csize); + filename[size] = '\0'; + } + } + /* The mode information (st_mode). */ + else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0) + { + /* At position 0 of the PX record the st_mode information is + stored (little-endian). */ + grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8)) + & GRUB_ISO9660_FSTYPE_MASK); + + switch (mode) + { + case GRUB_ISO9660_FSTYPE_DIR: + type = GRUB_FSHELP_DIR; + break; + case GRUB_ISO9660_FSTYPE_REG: + type = GRUB_FSHELP_REG; + break; + case GRUB_ISO9660_FSTYPE_SYMLINK: + type = GRUB_FSHELP_SYMLINK; + break; + default: + type = GRUB_FSHELP_UNKNOWN; + } + } + else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0) { unsigned int pos = 1; /* The symlink is not stored as a POSIX symlink, translate it. */ - while (pos < grub_le_to_cpu32 (entry->len)) + while (pos + sizeof (*entry) < grub_le_to_cpu32 (entry->len)) { - if (addslash) - { - add_part ("/", 1); - addslash = 0; - } - /* The current position is the `Component Flag'. */ switch (entry->data[pos] & 30) { @@ -409,10 +629,10 @@ grub_iso9660_read_symlink (grub_fshelp_node_t node) /* The data on pos + 2 is the actual data, pos + 1 is the length. Both are part of the `Component Record'. */ + if (symlink && (entry->data[pos] & 1)) + add_part ("/", 1); add_part ((char *) &entry->data[pos + 2], entry->data[pos + 1]); - if ((entry->data[pos] & 1)) - addslash = 1; break; } @@ -442,112 +662,13 @@ grub_iso9660_read_symlink (grub_fshelp_node_t node) return 0; } - if (grub_disk_read (node->data->disk, node->dir_blk, node->dir_off, - sizeof (dirent), (char *) &dirent)) - return 0; + len = get_node_size (dir); - sua_off = (sizeof (dirent) + dirent.namelen + 1 - (dirent.namelen % 2) - + node->data->susp_skip); - sua_size = dirent.len - sua_off; - - symlink = grub_malloc (1); - if (!symlink) - return 0; - - *symlink = '\0'; - - if (grub_iso9660_susp_iterate (node->data, node->dir_blk, - node->dir_off + sua_off, - sua_size, susp_iterate_sl)) + for (; offset < len; offset += dirent.len) { - grub_free (symlink); - return 0; - } + symlink = 0; - return symlink; -} - - -static int -grub_iso9660_iterate_dir (grub_fshelp_node_t dir, - int NESTED_FUNC_ATTR - (*hook) (const char *filename, - enum grub_fshelp_filetype filetype, - grub_fshelp_node_t node)) -{ - struct grub_iso9660_dir dirent; - unsigned int offset = 0; - char *filename; - int filename_alloc = 0; - enum grub_fshelp_filetype type; - - auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *); - - grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *entry) - { - /* The filename in the rock ridge entry. */ - if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0) - { - /* The flags are stored at the data position 0, here the - filename type is stored. */ - if (entry->data[0] & GRUB_ISO9660_RR_DOT) - filename = "."; - else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT) - filename = ".."; - else - { - int size = 1; - if (filename) - { - size += grub_strlen (filename); - grub_realloc (filename, - grub_strlen (filename) - + entry->len); - } - else - { - size = entry->len - 5; - filename = grub_zalloc (size + 1); - } - filename_alloc = 1; - grub_strncpy (filename, (char *) &entry->data[1], size); - filename[size] = '\0'; - } - } - /* The mode information (st_mode). */ - else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0) - { - /* At position 0 of the PX record the st_mode information is - stored (little-endian). */ - grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8)) - & GRUB_ISO9660_FSTYPE_MASK); - - switch (mode) - { - case GRUB_ISO9660_FSTYPE_DIR: - type = GRUB_FSHELP_DIR; - break; - case GRUB_ISO9660_FSTYPE_REG: - type = GRUB_FSHELP_REG; - break; - case GRUB_ISO9660_FSTYPE_SYMLINK: - type = GRUB_FSHELP_SYMLINK; - break; - default: - type = GRUB_FSHELP_UNKNOWN; - } - } - - return 0; - } - - while (offset < dir->size) - { - if (grub_disk_read (dir->data->disk, - (dir->blk << GRUB_ISO9660_LOG2_BLKSZ) - + offset / GRUB_DISK_SECTOR_SIZE, - offset % GRUB_DISK_SECTOR_SIZE, - sizeof (dirent), (char *) &dirent)) + if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) return 0; /* The end of the block, skip to the next one. */ @@ -572,39 +693,30 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, type = GRUB_FSHELP_UNKNOWN; if (dir->data->rockridge - && grub_iso9660_susp_iterate (dir->data, - (dir->blk << GRUB_ISO9660_LOG2_BLKSZ) - + (sua_off - / GRUB_DISK_SECTOR_SIZE), - sua_off % GRUB_DISK_SECTOR_SIZE, - sua_size, susp_iterate_dir)) + && grub_iso9660_susp_iterate (dir, sua_off, sua_size, + susp_iterate_dir)) return 0; /* Read the name. */ - if (grub_disk_read (dir->data->disk, - (dir->blk << GRUB_ISO9660_LOG2_BLKSZ) - + nameoffset / GRUB_DISK_SECTOR_SIZE, - nameoffset % GRUB_DISK_SECTOR_SIZE, - dirent.namelen, (char *) name)) + if (read_node (dir, nameoffset, dirent.namelen, (char *) name)) return 0; node = grub_malloc (sizeof (struct grub_fshelp_node)); if (!node) return 0; + node->alloc_dirents = ARRAY_SIZE (node->dirents); + node->have_dirents = 1; + /* Setup a new node. */ node->data = dir->data; - node->size = grub_le_to_cpu32 (dirent.size); - node->blk = grub_le_to_cpu32 (dirent.first_sector); - node->dir_blk = ((dir->blk << GRUB_ISO9660_LOG2_BLKSZ) - + offset / GRUB_DISK_SECTOR_SIZE); - node->dir_off = offset % GRUB_DISK_SECTOR_SIZE; + node->have_symlink = 0; /* If the filetype was not stored using rockridge, use whatever is stored in the iso9660 filesystem. */ if (type == GRUB_FSHELP_UNKNOWN) { - if ((dirent.flags & 3) == 2) + if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR) type = GRUB_FSHELP_DIR; else type = GRUB_FSHELP_REG; @@ -619,10 +731,12 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, if (filename) *filename = '\0'; - if (dirent.namelen == 1 && name[0] == 0) - filename = "."; - else if (dirent.namelen == 1 && name[0] == 1) - filename = ".."; + /* . and .. */ + if (dirent.namelen == 1 && (name[0] == 0 || name[0] == 1)) + { + grub_free (node); + continue; + } else filename = name; } @@ -633,7 +747,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, oldname = filename; filename = grub_iso9660_convert_string - ((grub_uint16_t *) oldname, dirent.namelen >> 1); + ((grub_uint8_t *) oldname, dirent.namelen >> 1); semicolon = grub_strrchr (filename, ';'); if (semicolon) @@ -645,6 +759,64 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, filename_alloc = 1; } + node->dirents[0] = dirent; + while (dirent.flags & FLAG_MORE_EXTENTS) + { + offset += dirent.len; + if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) + { + if (filename_alloc) + grub_free (filename); + grub_free (node); + return 0; + } + if (node->have_dirents >= node->alloc_dirents) + { + struct grub_fshelp_node *new_node; + node->alloc_dirents *= 2; + new_node = grub_realloc (node, + sizeof (struct grub_fshelp_node) + + ((node->alloc_dirents + - ARRAY_SIZE (node->dirents)) + * sizeof (node->dirents[0]))); + if (!new_node) + { + if (filename_alloc) + grub_free (filename); + grub_free (node); + return 0; + } + node = new_node; + } + node->dirents[node->have_dirents++] = dirent; + } + if (symlink) + { + if ((node->alloc_dirents - node->have_dirents) + * sizeof (node->dirents[0]) < grub_strlen (symlink) + 1) + { + struct grub_fshelp_node *new_node; + new_node = grub_realloc (node, + sizeof (struct grub_fshelp_node) + + ((node->alloc_dirents + - ARRAY_SIZE (node->dirents)) + * sizeof (node->dirents[0])) + + grub_strlen (symlink) + 1); + if (!new_node) + { + if (filename_alloc) + grub_free (filename); + grub_free (node); + return 0; + } + node = new_node; + } + node->have_symlink = 1; + grub_strcpy (node->symlink + + node->have_dirents * sizeof (node->dirents[0]) + - sizeof (node->dirents), symlink); + grub_free (symlink); + } if (hook (filename, type, node)) { if (filename_alloc) @@ -654,8 +826,6 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, if (filename_alloc) grub_free (filename); } - - offset += dirent.len; } return 0; @@ -683,6 +853,8 @@ grub_iso9660_dir (grub_device_t device, const char *path, struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime); + grub_free (node); return hook (filename, &info); } @@ -694,8 +866,10 @@ grub_iso9660_dir (grub_device_t device, const char *path, goto fail; rootnode.data = data; - rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector); - rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size); + rootnode.alloc_dirents = 0; + rootnode.have_dirents = 1; + rootnode.have_symlink = 0; + rootnode.dirents[0] = data->voldesc.rootdir; /* Use the fshelp function to traverse the path. */ if (grub_fshelp_find_file (path, &rootnode, @@ -735,8 +909,10 @@ grub_iso9660_open (struct grub_file *file, const char *name) goto fail; rootnode.data = data; - rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector); - rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size); + rootnode.alloc_dirents = 0; + rootnode.have_dirents = 1; + rootnode.have_symlink = 0; + rootnode.dirents[0] = data->voldesc.rootdir; /* Use the fshelp function to traverse the path. */ if (grub_fshelp_find_file (name, &rootnode, @@ -746,10 +922,9 @@ grub_iso9660_open (struct grub_file *file, const char *name) GRUB_FSHELP_REG)) goto fail; - data->first_sector = foundnode->blk; - + data->node = foundnode; file->data = data; - file->size = foundnode->size; + file->size = get_node_size (foundnode); file->offset = 0; return 0; @@ -771,10 +946,7 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len) /* XXX: The file is stored in as a single extent. */ data->disk->read_hook = file->read_hook; - grub_disk_read (data->disk, - data->first_sector << GRUB_ISO9660_LOG2_BLKSZ, - file->offset, - len, buf); + read_node (data->node, file->offset, len, buf); data->disk->read_hook = NULL; if (grub_errno) @@ -787,7 +959,10 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len) static grub_err_t grub_iso9660_close (grub_file_t file) { - grub_free (file->data); + struct grub_iso9660_data *data = + (struct grub_iso9660_data *) file->data; + grub_free (data->node); + grub_free (data); grub_dl_unref (my_mod); @@ -804,10 +979,18 @@ grub_iso9660_label (grub_device_t device, char **label) if (data) { if (data->joliet) - *label = grub_iso9660_convert_string - ((grub_uint16_t *) &data->voldesc.volname, 16); + *label = grub_iso9660_convert_string (data->voldesc.volname, 16); else *label = grub_strndup ((char *) data->voldesc.volname, 32); + if (*label) + { + char *ptr; + for (ptr = *label; *ptr;ptr++); + ptr--; + while (ptr >= *label && *ptr == ' ') + *ptr-- = 0; + } + grub_free (data); } else @@ -871,6 +1054,32 @@ grub_iso9660_uuid (grub_device_t device, char **uuid) return grub_errno; } +/* Get writing time of filesystem. */ +static grub_err_t +grub_iso9660_mtime (grub_device_t device, grub_int32_t *timebuf) +{ + struct grub_iso9660_data *data; + grub_disk_t disk = device->disk; + grub_err_t err; + + grub_dl_ref (my_mod); + + data = grub_iso9660_mount (disk); + if (!data) + { + grub_dl_unref (my_mod); + return grub_errno; + } + err = iso9660_to_unixtime (&data->voldesc.modified, timebuf); + + grub_dl_unref (my_mod); + + grub_free (data); + + return err; +} + + static struct grub_fs grub_iso9660_fs = @@ -882,6 +1091,7 @@ static struct grub_fs grub_iso9660_fs = .close = grub_iso9660_close, .label = grub_iso9660_label, .uuid = grub_iso9660_uuid, + .mtime = grub_iso9660_mtime, .next = 0 }; diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c index c9839a22f..d47be782a 100644 --- a/grub-core/fs/jfs.c +++ b/grub-core/fs/jfs.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_JFS_MAX_SYMLNK_CNT 8 #define GRUB_JFS_FILETYPE_MASK 0170000 #define GRUB_JFS_FILETYPE_REG 0100000 @@ -50,10 +52,11 @@ struct grub_jfs_sblock grub_uint32_t blksz; grub_uint16_t log2_blksz; - grub_uint8_t unused[71]; - grub_uint8_t volname[11]; - grub_uint8_t unused2[32]; + grub_uint8_t unused[79]; + char volname[11]; + grub_uint8_t unused2[24]; grub_uint8_t uuid[16]; + char volname2[16]; }; struct grub_jfs_extent @@ -153,6 +156,12 @@ struct grub_jfs_leaf_next_dirent grub_uint16_t namepart[15]; } __attribute__ ((packed)); +struct grub_jfs_time +{ + grub_int32_t sec; + grub_int32_t nanosec; +} __attribute__ ((packed)); + struct grub_jfs_inode { grub_uint32_t stamp; @@ -162,7 +171,10 @@ struct grub_jfs_inode grub_uint64_t size; grub_uint8_t unused2[20]; grub_uint32_t mode; - grub_uint8_t unused3[72]; + struct grub_jfs_time atime; + struct grub_jfs_time ctime; + struct grub_jfs_time mtime; + grub_uint8_t unused3[48]; grub_uint8_t unused4[96]; union @@ -194,7 +206,7 @@ struct grub_jfs_inode struct { grub_uint8_t unused[32]; - grub_uint8_t path[128]; + grub_uint8_t path[256]; } symlink; } __attribute__ ((packed)); } __attribute__ ((packed)); @@ -217,36 +229,39 @@ struct grub_jfs_diropen struct grub_jfs_tree_dir header; struct grub_jfs_leaf_dirent dirent[0]; struct grub_jfs_leaf_next_dirent next_dirent[0]; - char sorted[0]; + grub_uint8_t sorted[0]; } *dirpage __attribute__ ((packed)); struct grub_jfs_data *data; struct grub_jfs_inode *inode; int count; - char *sorted; + grub_uint8_t *sorted; struct grub_jfs_leaf_dirent *leaf; struct grub_jfs_leaf_next_dirent *next_leaf; /* The filename and inode of the last read dirent. */ - char name[255]; + /* On-disk name is at most 255 UTF-16 codepoints. + Every UTF-16 codepoint is at most 4 UTF-8 bytes. + */ + char name[256 * GRUB_MAX_UTF8_PER_UTF16 + 1]; grub_uint32_t ino; } __attribute__ ((packed)); static grub_dl_t my_mod; -static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino); +static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino); /* Get the block number for the block BLK in the node INODE in the mounted filesystem DATA. */ -static int +static grub_int64_t grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, - unsigned int blk) + grub_uint64_t blk) { - auto int getblk (struct grub_jfs_treehead *treehead, - struct grub_jfs_tree_extent *extents); + auto grub_int64_t getblk (struct grub_jfs_treehead *treehead, + struct grub_jfs_tree_extent *extents); - int getblk (struct grub_jfs_treehead *treehead, - struct grub_jfs_tree_extent *extents) + grub_int64_t getblk (struct grub_jfs_treehead *treehead, + struct grub_jfs_tree_extent *extents) { int found = -1; int i; @@ -258,7 +273,7 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, /* Read the leafnode. */ if (grub_le_to_cpu32 (extents[i].offset2) <= blk && ((grub_le_to_cpu16 (extents[i].extent.length)) - + (extents[i].extent.length2 << 8) + + (extents[i].extent.length2 << 16) + grub_le_to_cpu32 (extents[i].offset2)) > blk) return (blk - grub_le_to_cpu32 (extents[i].offset2) + grub_le_to_cpu32 (extents[i].extent.blk2)); @@ -277,7 +292,7 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, } tree; if (grub_disk_read (data->disk, - grub_le_to_cpu32 (extents[found].extent.blk2) + ((grub_disk_addr_t) grub_le_to_cpu32 (extents[found].extent.blk2)) << (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS), 0, sizeof (tree), (char *) &tree)) @@ -294,15 +309,15 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, static grub_err_t -grub_jfs_read_inode (struct grub_jfs_data *data, int ino, +grub_jfs_read_inode (struct grub_jfs_data *data, grub_uint32_t ino, struct grub_jfs_inode *inode) { struct grub_jfs_iag iag; - int iagnum = ino / 4096; - int inoext = (ino % 4096) / 32; - int inonum = (ino % 4096) % 32; - grub_uint32_t iagblk; - grub_uint32_t inoblk; + grub_uint32_t iagnum = ino / 4096; + unsigned inoext = (ino % 4096) / 32; + unsigned inonum = (ino % 4096) % 32; + grub_uint64_t iagblk; + grub_uint64_t inoblk; iagblk = grub_jfs_blkno (data, &data->fileset, iagnum + 1); if (grub_errno) @@ -348,6 +363,13 @@ grub_jfs_mount (grub_disk_t disk) goto fail; } + if (grub_le_to_cpu32 (data->sblock.blksz) + != (1U << grub_le_to_cpu16 (data->sblock.log2_blksz))) + { + grub_error (GRUB_ERR_BAD_FS, "not a JFS filesystem"); + goto fail; + } + data->disk = disk; data->pos = 0; data->linknest = 0; @@ -374,7 +396,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) { struct grub_jfs_internal_dirent *de; struct grub_jfs_diropen *diro; - int blk; + grub_disk_addr_t blk; de = (struct grub_jfs_internal_dirent *) inode->dir.dirents; @@ -397,7 +419,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) { diro->leaf = inode->dir.dirents; diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de; - diro->sorted = (char *) (inode->dir.header.sorted); + diro->sorted = inode->dir.header.sorted; diro->count = inode->dir.header.count; return diro; @@ -461,7 +483,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro) struct grub_jfs_leaf_next_dirent *next_leaf; int len; int nextent; - grub_uint16_t filename[255]; + grub_uint16_t filename[256]; auto void addstr (grub_uint16_t *uname, int ulen); @@ -469,13 +491,13 @@ grub_jfs_getent (struct grub_jfs_diropen *diro) void addstr (grub_uint16_t *name, int ulen) { while (ulen--) - filename[strpos++] = *(name++); + filename[strpos++] = grub_le_to_cpu16 (*(name++)); } /* The last node, read in more. */ if (diro->index == diro->count) { - unsigned int next; + grub_disk_addr_t next; /* If the inode contains the entry tree or if this was the last node, there is nothing to read. */ @@ -499,7 +521,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro) diro->index = 0; } - leaf = &diro->leaf[(int) diro->sorted[diro->index]]; + leaf = &diro->leaf[diro->sorted[diro->index]]; next_leaf = &diro->next_leaf[diro->index]; len = leaf->len; @@ -540,21 +562,21 @@ static grub_ssize_t grub_jfs_read_file (struct grub_jfs_data *data, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { - int i; - int blockcnt; + grub_off_t i; + grub_off_t blockcnt; - blockcnt = ((len + pos + grub_le_to_cpu32 (data->sblock.blksz) - 1) - / grub_le_to_cpu32 (data->sblock.blksz)); + blockcnt = (len + pos + grub_le_to_cpu32 (data->sblock.blksz) - 1) + >> grub_le_to_cpu16 (data->sblock.log2_blksz); - for (i = pos / grub_le_to_cpu32 (data->sblock.blksz); i < blockcnt; i++) + for (i = pos >> grub_le_to_cpu16 (data->sblock.log2_blksz); i < blockcnt; i++) { - int blknr; - int blockoff = pos % grub_le_to_cpu32 (data->sblock.blksz); - int blockend = grub_le_to_cpu32 (data->sblock.blksz); + grub_disk_addr_t blknr; + grub_uint32_t blockoff = pos & (grub_le_to_cpu32 (data->sblock.blksz) - 1); + grub_uint32_t blockend = grub_le_to_cpu32 (data->sblock.blksz); - int skipfirst = 0; + grub_uint64_t skipfirst = 0; blknr = grub_jfs_blkno (data, &data->currinode, i); if (grub_errno) @@ -563,14 +585,14 @@ grub_jfs_read_file (struct grub_jfs_data *data, /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % grub_le_to_cpu32 (data->sblock.blksz); + blockend = (len + pos) & (grub_le_to_cpu32 (data->sblock.blksz) - 1); if (!blockend) blockend = grub_le_to_cpu32 (data->sblock.blksz); } /* First block. */ - if (i == (pos / (int) grub_le_to_cpu32 (data->sblock.blksz))) + if (i == (pos >> grub_le_to_cpu16 (data->sblock.log2_blksz))) { skipfirst = blockoff; blockend -= skipfirst; @@ -596,17 +618,17 @@ grub_jfs_read_file (struct grub_jfs_data *data, /* Find the file with the pathname PATH on the filesystem described by DATA. */ static grub_err_t -grub_jfs_find_file (struct grub_jfs_data *data, const char *path) +grub_jfs_find_file (struct grub_jfs_data *data, const char *path, + grub_uint32_t start_ino) { char fpath[grub_strlen (path)]; char *name = fpath; char *next; - unsigned int pos = 0; struct grub_jfs_diropen *diro; grub_strncpy (fpath, path, grub_strlen (path) + 1); - if (grub_jfs_read_inode (data, GRUB_JFS_AGGR_INODE, &data->currinode)) + if (grub_jfs_read_inode (data, start_ino, &data->currinode)) return grub_errno; /* Skip the first slashes. */ @@ -643,8 +665,8 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path) pathname. */ if (!grub_strcmp (name, diro->name)) { - int ino = diro->ino; - int dirino = grub_le_to_cpu32 (data->currinode.inode); + grub_uint32_t ino = diro->ino; + grub_uint32_t dirino = grub_le_to_cpu32 (data->currinode.inode); grub_jfs_closedir (diro); diro = 0; @@ -664,8 +686,6 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path) if (!next) return 0; - pos = 0; - name = next; next = grub_strchr (name, '/'); if (next) @@ -684,22 +704,22 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path) } grub_jfs_closedir (diro); - grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path); return grub_errno; } static grub_err_t -grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino) +grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino) { - int size = grub_le_to_cpu64 (data->currinode.size); + grub_size_t size = grub_le_to_cpu64 (data->currinode.size); char symlink[size + 1]; if (++data->linknest > GRUB_JFS_MAX_SYMLNK_CNT) return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks"); - if (size <= 128) - grub_strncpy (symlink, (char *) (data->currinode.symlink.path), 128); + if (size <= sizeof (data->currinode.symlink.path)) + grub_strncpy (symlink, (char *) (data->currinode.symlink.path), size); else if (grub_jfs_read_file (data, 0, 0, size, symlink) < 0) return grub_errno; @@ -709,11 +729,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino) if (symlink[0] == '/') ino = 2; - /* Now load in the old inode. */ - if (grub_jfs_read_inode (data, ino, &data->currinode)) - return grub_errno; - - grub_jfs_find_file (data, symlink); + grub_jfs_find_file (data, symlink, ino); if (grub_errno) grub_error (grub_errno, "cannot follow symlink `%s'", symlink); @@ -735,7 +751,7 @@ grub_jfs_dir (grub_device_t device, const char *path, if (!data) goto fail; - if (grub_jfs_find_file (data, path)) + if (grub_jfs_find_file (data, path, GRUB_JFS_AGGR_INODE)) goto fail; diro = grub_jfs_opendir (data, &data->currinode); @@ -754,6 +770,8 @@ grub_jfs_dir (grub_device_t device, const char *path, info.dir = (grub_le_to_cpu32 (inode.mode) & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR; + info.mtimeset = 1; + info.mtime = grub_le_to_cpu32 (inode.mtime.sec); if (hook (diro->name, &info)) goto fail; } @@ -784,7 +802,7 @@ grub_jfs_open (struct grub_file *file, const char *name) if (!data) goto fail; - grub_jfs_find_file (data, name); + grub_jfs_find_file (data, name, GRUB_JFS_AGGR_INODE); if (grub_errno) goto fail; @@ -870,10 +888,19 @@ grub_jfs_label (grub_device_t device, char **label) data = grub_jfs_mount (device->disk); if (data) - *label = grub_strndup ((char *) (data->sblock.volname), 11); + { + if (data->sblock.volname2[0]) + *label = grub_strndup (data->sblock.volname2, + sizeof (data->sblock.volname2)); + else + *label = grub_strndup (data->sblock.volname, + sizeof (data->sblock.volname)); + } else *label = 0; + grub_free (data); + return grub_errno; } diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c index aa5b9a0c9..0128f1d8c 100644 --- a/grub-core/fs/minix.c +++ b/grub-core/fs/minix.c @@ -25,14 +25,19 @@ #include #include -#ifdef MODE_MINIX2 +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef MODE_MINIX3 +#define GRUB_MINIX_MAGIC 0x4D5A +#elif defined(MODE_MINIX2) #define GRUB_MINIX_MAGIC 0x2468 #define GRUB_MINIX_MAGIC_30 0x2478 #else #define GRUB_MINIX_MAGIC 0x137F #define GRUB_MINIX_MAGIC_30 0x138F #endif -#define GRUB_MINIX_BSIZE 1024U + +#define GRUB_MINIX_INODE_DIR_BLOCKS 7 #define GRUB_MINIX_LOG2_BSIZE 1 #define GRUB_MINIX_ROOT_INODE 1 #define GRUB_MINIX_MAX_SYMLNK_CNT 8 @@ -41,7 +46,7 @@ #define GRUB_MINIX_IFDIR 0040000U #define GRUB_MINIX_IFLNK 0120000U -#ifdef MODE_MINIX2 +#if defined(MODE_MINIX2) || defined(MODE_MINIX3) typedef grub_uint32_t grub_minix_uintn_t; #define grub_minix_le_to_cpu_n grub_le_to_cpu32 #else @@ -50,8 +55,15 @@ typedef grub_uint16_t grub_minix_uintn_t; #endif #define GRUB_MINIX_INODE_BLKSZ(data) sizeof (grub_minix_uintn_t) +#ifdef MODE_MINIX3 +typedef grub_uint32_t grub_minix_ino_t; +#define grub_minix_le_to_cpu_ino grub_le_to_cpu32 +#else +typedef grub_uint16_t grub_minix_ino_t; +#define grub_minix_le_to_cpu_ino grub_le_to_cpu16 +#endif -#define GRUB_MINIX_INODE_SIZE(data) (grub_minix_le_to_cpu_n (data->inode.size)) +#define GRUB_MINIX_INODE_SIZE(data) (grub_le_to_cpu32 (data->inode.size)) #define GRUB_MINIX_INODE_MODE(data) (grub_le_to_cpu16 (data->inode.mode)) #define GRUB_MINIX_INODE_DIR_ZONES(data,blk) (grub_minix_le_to_cpu_n \ (data->inode.dir_zones[blk])) @@ -60,11 +72,39 @@ typedef grub_uint16_t grub_minix_uintn_t; #define GRUB_MINIX_INODE_DINDIR_ZONE(data) (grub_minix_le_to_cpu_n \ (data->inode.double_indir_zone)) +#ifndef MODE_MINIX3 #define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \ - + grub_le_to_cpu16 (sblock->log2_zone_size)) -#define GRUB_MINIX_ZONESZ (GRUB_MINIX_BSIZE \ - << grub_le_to_cpu16 (sblock->log2_zone_size)) + + grub_le_to_cpu16 (data->sblock.log2_zone_size)) +#endif +#define GRUB_MINIX_ZONESZ (1 << (data->log_block_size \ + + grub_le_to_cpu16 (data->sblock.log2_zone_size))) +#ifdef MODE_MINIX3 +#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << (data->log_block_size - GRUB_DISK_SECTOR_BITS)) +#else +#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << GRUB_MINIX_LOG2_ZONESZ) +#endif + + +#ifdef MODE_MINIX3 +struct grub_minix_sblock +{ + grub_uint32_t inode_cnt; + grub_uint16_t zone_cnt; + grub_uint16_t inode_bmap_size; + grub_uint16_t zone_bmap_size; + grub_uint16_t first_data_zone; + grub_uint16_t log2_zone_size; + grub_uint16_t pad; + grub_uint32_t max_file_size; + grub_uint32_t zones; + grub_uint16_t magic; + + grub_uint16_t pad2; + grub_uint16_t block_size; + grub_uint8_t disk_version; +}; +#else struct grub_minix_sblock { grub_uint16_t inode_cnt; @@ -76,23 +116,9 @@ struct grub_minix_sblock grub_uint32_t max_file_size; grub_uint16_t magic; }; +#endif -#ifndef MODE_MINIX2 -struct grub_minix_inode -{ - grub_uint16_t mode; - grub_uint16_t uid; - grub_uint16_t size; - grub_uint32_t ctime; - grub_uint8_t gid; - grub_uint8_t nlinks; - grub_uint16_t dir_zones[7]; - grub_uint16_t indir_zone; - grub_uint16_t double_indir_zone; -}; - -#else - +#if defined(MODE_MINIX3) || defined(MODE_MINIX2) struct grub_minix_inode { grub_uint16_t mode; @@ -106,8 +132,20 @@ struct grub_minix_inode grub_uint32_t dir_zones[7]; grub_uint32_t indir_zone; grub_uint32_t double_indir_zone; - grub_uint32_t unused; - + grub_uint32_t triple_indir_zone; +}; +#else +struct grub_minix_inode +{ + grub_uint16_t mode; + grub_uint16_t uid; + grub_uint32_t size; + grub_uint32_t mtime; + grub_uint8_t gid; + grub_uint8_t nlinks; + grub_uint16_t dir_zones[7]; + grub_uint16_t indir_zone; + grub_uint16_t double_indir_zone; }; #endif @@ -121,6 +159,7 @@ struct grub_minix_data int linknest; grub_disk_t disk; int filename_size; + grub_size_t log_block_size; }; static grub_dl_t my_mod; @@ -128,50 +167,66 @@ static grub_dl_t my_mod; static grub_err_t grub_minix_find_file (struct grub_minix_data *data, const char *path); -static int +static grub_minix_uintn_t grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk) { - struct grub_minix_sblock *sblock = &data->sblock; - int indir; + grub_minix_uintn_t indir; + const grub_uint32_t block_per_zone = (GRUB_MINIX_ZONESZ + / GRUB_MINIX_INODE_BLKSZ (data)); - auto int grub_get_indir (int, int); + auto grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t, + grub_minix_uintn_t); /* Read the block pointer in ZONE, on the offset NUM. */ - int grub_get_indir (int zone, int num) + grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t zone, + grub_minix_uintn_t num) { grub_minix_uintn_t indirn; grub_disk_read (data->disk, - zone << GRUB_MINIX_LOG2_ZONESZ, + GRUB_MINIX_ZONE2SECT(zone), sizeof (grub_minix_uintn_t) * num, sizeof (grub_minix_uintn_t), (char *) &indirn); return grub_minix_le_to_cpu_n (indirn); } /* Direct block. */ - if (blk < 7) + if (blk < GRUB_MINIX_INODE_DIR_BLOCKS) return GRUB_MINIX_INODE_DIR_ZONES (data, blk); /* Indirect block. */ - blk -= 7; - if (blk < GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data)) + blk -= GRUB_MINIX_INODE_DIR_BLOCKS; + if (blk < block_per_zone) { indir = grub_get_indir (GRUB_MINIX_INODE_INDIR_ZONE (data), blk); return indir; } /* Double indirect block. */ - blk -= GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data); - if (blk < (GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data)) - * (GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data))) + blk -= block_per_zone; + if (blk < block_per_zone * block_per_zone) { indir = grub_get_indir (GRUB_MINIX_INODE_DINDIR_ZONE (data), - blk / GRUB_MINIX_ZONESZ); + blk / block_per_zone); - indir = grub_get_indir (indir, blk % GRUB_MINIX_ZONESZ); + indir = grub_get_indir (indir, blk % block_per_zone); return indir; } +#if defined (MODE_MINIX3) || defined (MODE_MINIX2) + blk -= block_per_zone * block_per_zone; + if (blk < ((grub_uint64_t) block_per_zone * (grub_uint64_t) block_per_zone + * (grub_uint64_t) block_per_zone)) + { + indir = grub_get_indir (grub_minix_le_to_cpu_n (data->inode.triple_indir_zone), + (blk / block_per_zone) / block_per_zone); + indir = grub_get_indir (indir, (blk / block_per_zone) % block_per_zone); + indir = grub_get_indir (indir, blk % block_per_zone); + + return indir; + } +#endif + /* This should never happen. */ grub_error (GRUB_ERR_OUT_OF_RANGE, "file bigger than maximum size"); @@ -185,25 +240,27 @@ static grub_ssize_t grub_minix_read_file (struct grub_minix_data *data, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_disk_addr_t len, char *buf) + grub_off_t pos, grub_disk_addr_t len, char *buf) { - struct grub_minix_sblock *sblock = &data->sblock; - int i; - int blockcnt; + grub_disk_addr_t i; + grub_disk_addr_t blockcnt; + grub_uint64_t posblock; + grub_uint64_t blockoff; /* Adjust len so it we can't read past the end of the file. */ if (len + pos > GRUB_MINIX_INODE_SIZE (data)) len = GRUB_MINIX_INODE_SIZE (data) - pos; - blockcnt = (len + pos + GRUB_MINIX_BSIZE - 1) / GRUB_MINIX_BSIZE; + blockcnt = ((len + pos + (1 << data->log_block_size) - 1) + >> data->log_block_size); + posblock = pos >> data->log_block_size; + blockoff = pos & ((1 << data->log_block_size) - 1); - for (i = pos / GRUB_MINIX_BSIZE; i < blockcnt; i++) + for (i = posblock; i < blockcnt; i++) { - int blknr; - int blockoff = pos % GRUB_MINIX_BSIZE; - int blockend = GRUB_MINIX_BSIZE; - - int skipfirst = 0; + grub_disk_addr_t blknr; + grub_uint64_t blockend = 1 << data->log_block_size; + grub_off_t skipfirst = 0; blknr = grub_minix_get_file_block (data, i); if (grub_errno) @@ -212,28 +269,28 @@ grub_minix_read_file (struct grub_minix_data *data, /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % GRUB_MINIX_BSIZE; + blockend = (len + pos) & ((1 << data->log_block_size) - 1); if (!blockend) - blockend = GRUB_MINIX_BSIZE; + blockend = 1 << data->log_block_size; } /* First block. */ - if (i == (pos / (int) GRUB_MINIX_BSIZE)) + if (i == posblock) { skipfirst = blockoff; blockend -= skipfirst; } data->disk->read_hook = read_hook; - grub_disk_read (data->disk, blknr << GRUB_MINIX_LOG2_ZONESZ, + grub_disk_read (data->disk, + GRUB_MINIX_ZONE2SECT(blknr), skipfirst, blockend, buf); - data->disk->read_hook = 0; if (grub_errno) return -1; - buf += GRUB_MINIX_BSIZE - skipfirst; + buf += (1 << data->log_block_size) - skipfirst; } return len; @@ -248,16 +305,13 @@ grub_minix_read_inode (struct grub_minix_data *data, int ino) struct grub_minix_sblock *sblock = &data->sblock; /* Block in which the inode is stored. */ - int block; + grub_disk_addr_t block; data->ino = ino; /* The first inode in minix is inode 1. */ ino--; - - block = ((2 + grub_le_to_cpu16 (sblock->inode_bmap_size) - + grub_le_to_cpu16 (sblock->zone_bmap_size)) - << GRUB_MINIX_LOG2_BSIZE); - + block = GRUB_MINIX_ZONE2SECT (2 + grub_le_to_cpu16 (sblock->inode_bmap_size) + + grub_le_to_cpu16 (sblock->zone_bmap_size)); block += ino / (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode)); int offs = (ino % (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode)) @@ -333,7 +387,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path) do { - grub_uint16_t ino; + grub_minix_ino_t ino; char filename[data->filename_size + 1]; if (grub_strlen (name) == 0) @@ -353,7 +407,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path) if (!grub_strcmp (name, filename)) { dirino = data->ino; - grub_minix_read_inode (data, grub_le_to_cpu16 (ino)); + grub_minix_read_inode (data, grub_minix_le_to_cpu_ino (ino)); /* Follow the symlink. */ if ((GRUB_MINIX_INODE_MODE (data) @@ -387,7 +441,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path) pos += sizeof (ino) + data->filename_size; } while (pos < GRUB_MINIX_INODE_SIZE (data)); - grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path); return grub_errno; } @@ -409,20 +463,46 @@ grub_minix_mount (grub_disk_t disk) goto fail; if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC) + { +#if !defined(MODE_MINIX3) data->filename_size = 14; +#else + data->filename_size = 60; +#endif + } +#if !defined(MODE_MINIX3) else if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC_30) data->filename_size = 30; +#endif else goto fail; data->disk = disk; data->linknest = 0; +#ifdef MODE_MINIX3 + /* These tests are endian-independent. No need to byteswap. */ + if (data->sblock.block_size == 0xffff) + data->log_block_size = 10; + else + { + if ((data->sblock.block_size & (data->sblock.block_size - 1)) + || data->sblock.block_size == 0) + goto fail; + for (data->log_block_size = 0; (1 << data->log_block_size) + < grub_le_to_cpu16 (data->sblock.block_size); + data->log_block_size++); + } +#else + data->log_block_size = 10; +#endif return data; fail: grub_free (data); -#ifdef MODE_MINIX2 +#if defined(MODE_MINIX3) + grub_error (GRUB_ERR_BAD_FS, "not a minix3 filesystem"); +#elif defined(MODE_MINIX2) grub_error (GRUB_ERR_BAD_FS, "not a minix2 filesystem"); #else grub_error (GRUB_ERR_BAD_FS, "not a minix filesystem"); @@ -436,7 +516,6 @@ grub_minix_dir (grub_device_t device, const char *path, const struct grub_dirhook_info *info)) { struct grub_minix_data *data = 0; - struct grub_minix_sblock *sblock; unsigned int pos = 0; data = grub_minix_mount (device->disk); @@ -447,8 +526,6 @@ grub_minix_dir (grub_device_t device, const char *path, if (grub_errno) goto fail; - sblock = &data->sblock; - grub_minix_find_file (data, path); if (grub_errno) goto fail; @@ -461,7 +538,7 @@ grub_minix_dir (grub_device_t device, const char *path, while (pos < GRUB_MINIX_INODE_SIZE (data)) { - grub_uint16_t ino; + grub_minix_ino_t ino; char filename[data->filename_size + 1]; int dirino = data->ino; struct grub_dirhook_info info; @@ -477,12 +554,18 @@ grub_minix_dir (grub_device_t device, const char *path, (char *) filename) < 0) return grub_errno; filename[data->filename_size] = '\0'; + if (!ino) + { + pos += sizeof (ino) + data->filename_size; + continue; + } - /* The filetype is not stored in the dirent. Read the inode to - find out the filetype. This *REALLY* sucks. */ - grub_minix_read_inode (data, grub_le_to_cpu16 (ino)); + grub_minix_read_inode (data, grub_minix_le_to_cpu_ino (ino)); info.dir = ((GRUB_MINIX_INODE_MODE (data) & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR); + info.mtimeset = 1; + info.mtime = grub_le_to_cpu32 (data->inode.mtime); + if (hook (filename, &info) ? 1 : 0) break; @@ -559,7 +642,9 @@ grub_minix_close (grub_file_t file) static struct grub_fs grub_minix_fs = { -#ifdef MODE_MINIX2 +#if defined(MODE_MINIX3) + .name = "minix3", +#elif defined(MODE_MINIX2) .name = "minix2", #else .name = "minix", @@ -571,7 +656,9 @@ static struct grub_fs grub_minix_fs = .next = 0 }; -#ifdef MODE_MINIX2 +#if defined(MODE_MINIX3) +GRUB_MOD_INIT(minix3) +#elif defined(MODE_MINIX2) GRUB_MOD_INIT(minix2) #else GRUB_MOD_INIT(minix) @@ -581,7 +668,9 @@ GRUB_MOD_INIT(minix) my_mod = mod; } -#ifdef MODE_MINIX2 +#if defined(MODE_MINIX3) +GRUB_MOD_FINI(minix3) +#elif defined(MODE_MINIX2) GRUB_MOD_FINI(minix2) #else GRUB_MOD_FINI(minix) diff --git a/grub-core/fs/minix3.c b/grub-core/fs/minix3.c new file mode 100644 index 000000000..58a21d2b5 --- /dev/null +++ b/grub-core/fs/minix3.c @@ -0,0 +1,2 @@ +#define MODE_MINIX3 1 +#include "minix.c" diff --git a/grub-core/fs/newc.c b/grub-core/fs/newc.c new file mode 100644 index 000000000..fdcc160e8 --- /dev/null +++ b/grub-core/fs/newc.c @@ -0,0 +1,2 @@ +#define MODE_NEWC 1 +#include "cpio.c" diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c index e529775f4..31d91dbd9 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -35,6 +35,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define NILFS_INODE_BMAP_SIZE 7 #define NILFS_SUPORT_REV 2 @@ -47,7 +49,6 @@ /* nilfs btree node level. */ #define NILFS_BTREE_LEVEL_DATA 0 #define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1) -#define NILFS_BTREE_LEVEL_MAX 14 /* nilfs 1st super block posission from beginning of the partition in 512 block size */ @@ -56,6 +57,7 @@ in 512 block size */ #define NILFS_2ND_SUPER_BLOCK(devsize) (((devsize >> 3) - 1) << 3) +#define LOG_INODE_SIZE 7 struct grub_nilfs2_inode { grub_uint64_t i_blocks; @@ -124,8 +126,7 @@ struct grub_nilfs2_super_block grub_uint16_t s_checkpoint_size; grub_uint16_t s_segment_usage_size; grub_uint8_t s_uuid[16]; - char s_volume_name[16]; - char s_last_mounted[64]; + char s_volume_name[80]; grub_uint32_t s_c_interval; grub_uint32_t s_c_block_max; grub_uint32_t s_reserved[192]; @@ -205,6 +206,7 @@ struct grub_nilfs2_btree_node grub_uint8_t bn_level; grub_uint16_t bn_nchildren; grub_uint32_t bn_pad; + grub_uint64_t keys[0]; }; struct grub_nilfs2_palloc_group_desc @@ -212,6 +214,7 @@ struct grub_nilfs2_palloc_group_desc grub_uint32_t pg_nfrees; }; +#define LOG_NILFS_DAT_ENTRY_SIZE 5 struct grub_nilfs2_dat_entry { grub_uint64_t de_blocknr; @@ -294,17 +297,17 @@ static grub_dl_t my_mod; static inline unsigned long -grub_nilfs2_palloc_entries_per_group (struct grub_nilfs2_data *data) +grub_nilfs2_log_palloc_entries_per_group (struct grub_nilfs2_data *data) { - return 1UL << (LOG2_BLOCK_SIZE (data) + 3); + return LOG2_BLOCK_SIZE (data) + 3; } static inline grub_uint64_t grub_nilfs2_palloc_group (struct grub_nilfs2_data *data, - grub_uint64_t nr, grub_uint32_t * offset) + grub_uint64_t nr, grub_uint64_t * offset) { - return grub_divmod64 (nr, grub_nilfs2_palloc_entries_per_group (data), - offset); + *offset = nr & ((1 << grub_nilfs2_log_palloc_entries_per_group (data)) - 1); + return nr >> grub_nilfs2_log_palloc_entries_per_group (data); } static inline grub_uint32_t @@ -315,64 +318,68 @@ grub_nilfs2_palloc_groups_per_desc_block (struct grub_nilfs2_data *data) } static inline grub_uint32_t -grub_nilfs2_entries_per_block (struct grub_nilfs2_data *data, - unsigned long entry_size) +grub_nilfs2_log_entries_per_block_log (struct grub_nilfs2_data *data, + unsigned long log_entry_size) { - return NILFS2_BLOCK_SIZE (data) / entry_size; + return LOG2_BLOCK_SIZE (data) - log_entry_size; } static inline grub_uint32_t -grub_nilfs2_blocks_per_group (struct grub_nilfs2_data *data, - unsigned long entry_size) +grub_nilfs2_blocks_per_group_log (struct grub_nilfs2_data *data, + unsigned long log_entry_size) { - return grub_div_roundup (grub_nilfs2_palloc_entries_per_group (data), - grub_nilfs2_entries_per_block (data, - entry_size)) + 1; + return (1 << (grub_nilfs2_log_palloc_entries_per_group (data) + - grub_nilfs2_log_entries_per_block_log (data, + log_entry_size))) + 1; } static inline grub_uint32_t -grub_nilfs2_blocks_per_desc_block (struct grub_nilfs2_data *data, - unsigned long entry_size) +grub_nilfs2_blocks_per_desc_block_log (struct grub_nilfs2_data *data, + unsigned long log_entry_size) { return grub_nilfs2_palloc_groups_per_desc_block (data) * - grub_nilfs2_blocks_per_group (data, entry_size) + 1; + grub_nilfs2_blocks_per_group_log (data, log_entry_size) + 1; } static inline grub_uint32_t -grub_nilfs2_palloc_desc_block_offset (struct grub_nilfs2_data *data, - unsigned long group, - unsigned long entry_size) +grub_nilfs2_palloc_desc_block_offset_log (struct grub_nilfs2_data *data, + unsigned long group, + unsigned long log_entry_size) { grub_uint32_t desc_block = group / grub_nilfs2_palloc_groups_per_desc_block (data); - return desc_block * grub_nilfs2_blocks_per_desc_block (data, entry_size); + return desc_block * grub_nilfs2_blocks_per_desc_block_log (data, + log_entry_size); } static inline grub_uint32_t grub_nilfs2_palloc_bitmap_block_offset (struct grub_nilfs2_data *data, unsigned long group, - unsigned long entry_size) + unsigned long log_entry_size) { unsigned long desc_offset = group % grub_nilfs2_palloc_groups_per_desc_block (data); - return grub_nilfs2_palloc_desc_block_offset (data, group, entry_size) + 1 + - desc_offset * grub_nilfs2_blocks_per_group (data, entry_size); + return grub_nilfs2_palloc_desc_block_offset_log (data, group, log_entry_size) + + 1 + + desc_offset * grub_nilfs2_blocks_per_group_log (data, log_entry_size); } static inline grub_uint32_t -grub_nilfs2_palloc_entry_offset (struct grub_nilfs2_data *data, - grub_uint64_t nr, unsigned long entry_size) +grub_nilfs2_palloc_entry_offset_log (struct grub_nilfs2_data *data, + grub_uint64_t nr, + unsigned long log_entry_size) { unsigned long group; - grub_uint32_t group_offset; + grub_uint64_t group_offset; group = grub_nilfs2_palloc_group (data, nr, &group_offset); return grub_nilfs2_palloc_bitmap_block_offset (data, group, - entry_size) + 1 + - group_offset / grub_nilfs2_entries_per_block (data, entry_size); + 1 << log_entry_size) + 1 + + (group_offset >> grub_nilfs2_log_entries_per_block_log (data, + log_entry_size)); } @@ -391,9 +398,9 @@ grub_nilfs2_btree_get_level (struct grub_nilfs2_btree_node *node) static inline grub_uint64_t * grub_nilfs2_btree_node_dkeys (struct grub_nilfs2_btree_node *node) { - return (grub_uint64_t *) ((char *) (node + 1) + - ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ? - 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE)); + return (node->keys + + ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ? + 0 : (NILFS_BTREE_NODE_EXTRA_PAD_SIZE / sizeof (grub_uint64_t)))); } static inline grub_uint64_t @@ -494,7 +501,7 @@ grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data, grub_uint64_t key, int need_translate) { struct grub_nilfs2_btree_node *node; - unsigned char block[NILFS2_BLOCK_SIZE (data)]; + GRUB_PROPERLY_ALIGNED_ARRAY (block, NILFS2_BLOCK_SIZE (data)); grub_uint64_t ptr; int level, found, index; @@ -575,15 +582,14 @@ grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key) struct grub_nilfs2_dat_entry entry; grub_disk_t disk = data->disk; grub_uint64_t pptr; - grub_uint32_t blockno, offset; + grub_uint64_t blockno, offset; unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); - blockno = grub_nilfs2_palloc_entry_offset (data, key, - sizeof (struct - grub_nilfs2_dat_entry)); + blockno = grub_nilfs2_palloc_entry_offset_log (data, key, + LOG_NILFS_DAT_ENTRY_SIZE); - grub_divmod64 (key * sizeof (struct grub_nilfs2_dat_entry), - NILFS2_BLOCK_SIZE (data), &offset); + offset = ((key * sizeof (struct grub_nilfs2_dat_entry)) + & ((1 << LOG2_BLOCK_SIZE (data)) - 1)); pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_dat, blockno, 0); if (pptr == (grub_uint64_t) - 1) @@ -624,7 +630,7 @@ grub_nilfs2_read_file (grub_fshelp_node_t node, sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { return grub_fshelp_read_file (node->data->disk, node, read_hook, pos, len, buf, grub_nilfs2_read_block, @@ -639,7 +645,7 @@ grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data, struct grub_nilfs2_checkpoint *cpp) { grub_uint64_t blockno; - grub_uint32_t offset; + grub_uint64_t offset; grub_uint64_t pptr; grub_disk_t disk = data->disk; unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); @@ -648,8 +654,8 @@ grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data, sizeof(struct grub_nilfs2_checkpoint). */ blockno = grub_divmod64 (cpno, NILFS2_BLOCK_SIZE (data) / - sizeof (struct grub_nilfs2_checkpoint), &offset); - + sizeof (struct grub_nilfs2_checkpoint), &offset); + pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_cpfile, blockno, 1); if (pptr == (grub_uint64_t) - 1) { @@ -677,17 +683,16 @@ grub_nilfs2_read_inode (struct grub_nilfs2_data *data, grub_uint64_t ino, struct grub_nilfs2_inode *inodep) { grub_uint64_t blockno; - unsigned int offset; + grub_uint64_t offset; grub_uint64_t pptr; grub_disk_t disk = data->disk; unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); - blockno = grub_nilfs2_palloc_entry_offset (data, ino, - sizeof (struct - grub_nilfs2_inode)); + blockno = grub_nilfs2_palloc_entry_offset_log (data, ino, + LOG_INODE_SIZE); - grub_divmod64 (sizeof (struct grub_nilfs2_inode) * ino, - NILFS2_BLOCK_SIZE (data), &offset); + offset = ((sizeof (struct grub_nilfs2_inode) * ino) + & ((1 << LOG2_BLOCK_SIZE (data)) - 1)); pptr = grub_nilfs2_bmap_lookup (data, &data->ifile, blockno, 1); if (pptr == (grub_uint64_t) - 1) { @@ -728,7 +733,11 @@ grub_nilfs2_load_sb (struct grub_nilfs2_data *data) /* Make sure if 1st super block is valid. */ valid[0] = grub_nilfs2_valid_sb (&data->sblock); - partition_size = grub_disk_get_size (disk); + if (valid[0]) + partition_size = (grub_le_to_cpu64 (data->sblock.s_dev_size) + >> GRUB_DISK_SECTOR_BITS); + else + partition_size = grub_disk_get_size (disk); if (partition_size != GRUB_DISK_SIZE_UNKNOWN) { /* Read second super block. */ @@ -862,7 +871,7 @@ grub_nilfs2_iterate_dir (grub_fshelp_node_t dir, enum grub_fshelp_filetype filetype, grub_fshelp_node_t node)) { - unsigned int fpos = 0; + grub_off_t fpos = 0; struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; if (!diro->inode_read) @@ -1089,7 +1098,8 @@ grub_nilfs2_label (grub_device_t device, char **label) data = grub_nilfs2_mount (disk); if (data) - *label = grub_strndup (data->sblock.s_volume_name, 14); + *label = grub_strndup (data->sblock.s_volume_name, + sizeof (data->sblock.s_volume_name)); else *label = NULL; @@ -1113,7 +1123,7 @@ grub_nilfs2_uuid (grub_device_t device, char **uuid) { *uuid = grub_xasprintf - ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x", + ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", data->sblock.s_uuid[0], data->sblock.s_uuid[1], data->sblock.s_uuid[2], data->sblock.s_uuid[3], data->sblock.s_uuid[4], data->sblock.s_uuid[5], @@ -1146,7 +1156,7 @@ grub_nilfs2_mtime (grub_device_t device, grub_int32_t * tm) if (!data) *tm = 0; else - *tm = (grub_int32_t) grub_le_to_cpu64 (data->sblock.s_mtime); + *tm = (grub_int32_t) grub_le_to_cpu64 (data->sblock.s_wtime); grub_dl_unref (my_mod); @@ -1174,6 +1184,11 @@ static struct grub_fs grub_nilfs2_fs = { GRUB_MOD_INIT (nilfs2) { + COMPILE_TIME_ASSERT ((1 << LOG_NILFS_DAT_ENTRY_SIZE) + == sizeof (struct + grub_nilfs2_dat_entry)); + COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE + == sizeof (struct grub_nilfs2_inode)); grub_fs_register (&grub_nilfs2_fs); my_mod = mod; } diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c index dd041e23a..6023d74df 100644 --- a/grub-core/fs/ntfs.c +++ b/grub-core/fs/ntfs.c @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#define grub_fshelp_node grub_ntfs_file + #include #include #include @@ -26,35 +28,58 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; -ntfscomp_func_t grub_ntfscomp_func; +#define grub_fshelp_node grub_ntfs_file + +static inline grub_uint16_t +u16at (void *ptr, grub_size_t ofs) +{ + return grub_le_to_cpu16 (grub_get_unaligned16 ((char *) ptr + ofs)); +} + +static inline grub_uint32_t +u32at (void *ptr, grub_size_t ofs) +{ + return grub_le_to_cpu32 (grub_get_unaligned32 ((char *) ptr + ofs)); +} + +static inline grub_uint64_t +u64at (void *ptr, grub_size_t ofs) +{ + return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs)); +} + +grub_ntfscomp_func_t grub_ntfscomp_func; static grub_err_t -fixup (struct grub_ntfs_data *data, char *buf, int len, char *magic) +fixup (char *buf, int len, const char *magic) { int ss; char *pu; grub_uint16_t us; + COMPILE_TIME_ASSERT ((1 << GRUB_NTFS_BLK_SHR) == GRUB_DISK_SECTOR_SIZE); + if (grub_memcmp (buf, magic, 4)) return grub_error (GRUB_ERR_BAD_FS, "%s label not found", magic); ss = u16at (buf, 6) - 1; - if (ss * (int) data->blocksize != len * GRUB_DISK_SECTOR_SIZE) - return grub_error (GRUB_ERR_BAD_FS, "size not match", - ss * (int) data->blocksize, - len * GRUB_DISK_SECTOR_SIZE); + if (ss != len) + return grub_error (GRUB_ERR_BAD_FS, "size not match"); pu = buf + u16at (buf, 4); us = u16at (pu, 0); buf -= 2; while (ss > 0) { - buf += data->blocksize; + buf += GRUB_DISK_SECTOR_SIZE; pu += 2; if (u16at (buf, 0) != us) return grub_error (GRUB_ERR_BAD_FS, "fixup signature not match"); - v16at (buf, 0) = v16at (pu, 0); + buf[0] = pu[0]; + buf[1] = pu[1]; ss--; } @@ -85,7 +110,7 @@ static void init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) { at->mft = mft; - at->flags = (mft == &mft->data->mmft) ? AF_MMFT : 0; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; at->attr_nxt = mft->buf + u16at (mft->buf, 0x14); at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; } @@ -101,7 +126,7 @@ free_attr (struct grub_ntfs_attr *at) static char * find_attr (struct grub_ntfs_attr *at, unsigned char attr) { - if (at->flags & AF_ALST) + if (at->flags & GRUB_NTFS_AF_ALST) { retry: while (at->attr_nxt < at->attr_end) @@ -112,20 +137,18 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) { char *new_pos; - if (at->flags & AF_MMFT) + if (at->flags & GRUB_NTFS_AF_MMFT) { if ((grub_disk_read - (at->mft->data->disk, v32at (at->attr_cur, 0x10), 0, + (at->mft->data->disk, u32at (at->attr_cur, 0x10), 0, 512, at->emft_buf)) || (grub_disk_read - (at->mft->data->disk, v32at (at->attr_cur, 0x14), 0, + (at->mft->data->disk, u32at (at->attr_cur, 0x14), 0, 512, at->emft_buf + 512))) return NULL; - if (fixup - (at->mft->data, at->emft_buf, at->mft->data->mft_size, - "FILE")) + if (fixup (at->emft_buf, at->mft->data->mft_size, "FILE")) return NULL; } else @@ -158,7 +181,7 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) while ((unsigned char) *at->attr_cur != 0xFF) { at->attr_nxt += u16at (at->attr_cur, 4); - if ((unsigned char) *at->attr_cur == AT_ATTRIBUTE_LIST) + if ((unsigned char) *at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST) at->attr_end = at->attr_cur; if (((unsigned char) *at->attr_cur == attr) || (attr == 0)) return at->attr_cur; @@ -168,7 +191,7 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) { char *pa; - at->emft_buf = grub_malloc (at->mft->data->mft_size << BLK_SHR); + at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); if (at->emft_buf == NULL) return NULL; @@ -197,7 +220,7 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) at->attr_nxt = at->attr_end + u16at (pa, 0x14); at->attr_end = at->attr_end + u32at (pa, 4); } - at->flags |= AF_ALST; + at->flags |= GRUB_NTFS_AF_ALST; while (at->attr_nxt < at->attr_end) { if (((unsigned char) *at->attr_nxt == attr) || (attr == 0)) @@ -207,13 +230,16 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) if (at->attr_nxt >= at->attr_end) return NULL; - if ((at->flags & AF_MMFT) && (attr == AT_DATA)) + if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA)) { - at->flags |= AF_GPOS; + at->flags |= GRUB_NTFS_AF_GPOS; at->attr_cur = at->attr_nxt; pa = at->attr_cur; - v32at (pa, 0x10) = at->mft->data->mft_start; - v32at (pa, 0x14) = at->mft->data->mft_start + 1; + grub_set_unaligned32 ((char *) pa + 0x10, + grub_cpu_to_le32 (at->mft->data->mft_start)); + grub_set_unaligned32 ((char *) pa + 0x14, + grub_cpu_to_le32 (at->mft->data->mft_start + + 1)); pa = at->attr_nxt + u16at (pa, 4); while (pa < at->attr_end) { @@ -221,13 +247,13 @@ find_attr (struct grub_ntfs_attr *at, unsigned char attr) break; if (read_attr (at, pa + 0x10, - u32at (pa, 0x10) * (at->mft->data->mft_size << BLK_SHR), - at->mft->data->mft_size << BLK_SHR, 0, 0)) + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), + at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0)) return NULL; pa += u16at (pa, 4); } at->attr_nxt = at->attr_cur; - at->flags &= ~AF_GPOS; + at->flags &= ~GRUB_NTFS_AF_GPOS; } goto retry; } @@ -243,13 +269,13 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft, init_attr (at, mft); if ((pa = find_attr (at, attr)) == NULL) return NULL; - if ((at->flags & AF_ALST) == 0) + if ((at->flags & GRUB_NTFS_AF_ALST) == 0) { while (1) { if ((pa = find_attr (at, attr)) == NULL) break; - if (at->flags & AF_ALST) + if (at->flags & GRUB_NTFS_AF_ALST) return pa; } grub_errno = GRUB_ERR_NONE; @@ -294,7 +320,7 @@ retry: c2 = ((unsigned char) (*run) >> 4); if (!c1) { - if ((ctx->attr) && (ctx->attr->flags & AF_ALST)) + if ((ctx->attr) && (ctx->attr->flags & GRUB_NTFS_AF_ALST)) { void NESTED_FUNC_ATTR (*save_hook) (grub_disk_addr_t sector, unsigned offset, @@ -323,9 +349,9 @@ retry: run = read_run_data (run, c2, &val, 1); /* offset to previous LCN */ ctx->curr_lcn += val; if (val == 0) - ctx->flags |= RF_BLNK; + ctx->flags |= GRUB_NTFS_RF_BLNK; else - ctx->flags &= ~RF_BLNK; + ctx->flags &= ~GRUB_NTFS_RF_BLNK; ctx->cur_run = run; return 0; } @@ -343,7 +369,7 @@ grub_ntfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block) return ctx->curr_lcn; } else - return (ctx->flags & RF_BLNK) ? 0 : (block - + return (ctx->flags & GRUB_NTFS_RF_BLNK) ? 0 : (block - ctx->curr_vcn + ctx->curr_lcn); } @@ -374,24 +400,24 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest, return 0; } - if (u16at (pa, 0xC) & FLAG_COMPRESSED) - ctx->flags |= RF_COMP; + if (u16at (pa, 0xC) & GRUB_NTFS_FLAG_COMPRESSED) + ctx->flags |= GRUB_NTFS_RF_COMP; else - ctx->flags &= ~RF_COMP; + ctx->flags &= ~GRUB_NTFS_RF_COMP; ctx->cur_run = pa + u16at (pa, 0x20); - if (ctx->flags & RF_COMP) + if (ctx->flags & GRUB_NTFS_RF_COMP) { if (!cached) return grub_error (GRUB_ERR_BAD_FS, "attribute can\'t be compressed"); if (at->sbuf) { - if ((ofs & (~(COM_LEN - 1))) == at->save_pos) + if ((ofs & (~(GRUB_NTFS_COM_LEN - 1))) == at->save_pos) { grub_disk_addr_t n; - n = COM_LEN - (ofs - at->save_pos); + n = GRUB_NTFS_COM_LEN - (ofs - at->save_pos); if (n > len) n = len; @@ -406,17 +432,17 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest, } else { - at->sbuf = grub_malloc (COM_LEN); + at->sbuf = grub_malloc (GRUB_NTFS_COM_LEN); if (at->sbuf == NULL) return grub_errno; at->save_pos = 1; } - vcn = ctx->target_vcn = (ofs >> COM_LOG_LEN) * (COM_SEC / ctx->comp.spc); + vcn = ctx->target_vcn = (ofs >> GRUB_NTFS_COM_LOG_LEN) * (GRUB_NTFS_COM_SEC / ctx->comp.spc); ctx->target_vcn &= ~0xF; } else - vcn = ctx->target_vcn = grub_divmod64 (ofs >> BLK_SHR, ctx->comp.spc, 0); + vcn = ctx->target_vcn = grub_divmod64 (ofs >> GRUB_NTFS_BLK_SHR, ctx->comp.spc, 0); ctx->next_vcn = u32at (pa, 0x10); ctx->curr_lcn = 0; @@ -426,12 +452,12 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest, return grub_errno; } - if (at->flags & AF_GPOS) + if (at->flags & GRUB_NTFS_AF_GPOS) { grub_disk_addr_t st0, st1; - grub_uint32_t m; + grub_uint64_t m; - grub_divmod64 (ofs >> BLK_SHR, ctx->comp.spc, &m); + grub_divmod64 (ofs >> GRUB_NTFS_BLK_SHR, ctx->comp.spc, &m); st0 = (ctx->target_vcn - ctx->curr_vcn + ctx->curr_lcn) * ctx->comp.spc + m; @@ -443,12 +469,12 @@ read_data (struct grub_ntfs_attr *at, char *pa, char *dest, return grub_errno; st1 = ctx->curr_lcn * ctx->comp.spc; } - v32at (dest, 0) = st0; - v32at (dest, 4) = st1; + grub_set_unaligned32 (dest, grub_cpu_to_le32 (st0)); + grub_set_unaligned32 (dest + 4, grub_cpu_to_le32 (st1)); return 0; } - if (!(ctx->flags & RF_COMP)) + if (!(ctx->flags & GRUB_NTFS_RF_COMP)) { unsigned int pow; @@ -479,12 +505,12 @@ read_attr (struct grub_ntfs_attr *at, char *dest, grub_disk_addr_t ofs, save_cur = at->attr_cur; at->attr_nxt = at->attr_cur; attr = (unsigned char) *at->attr_nxt; - if (at->flags & AF_ALST) + if (at->flags & GRUB_NTFS_AF_ALST) { char *pa; grub_disk_addr_t vcn; - vcn = grub_divmod64 (ofs, at->mft->data->spc << BLK_SHR, 0); + vcn = grub_divmod64 (ofs, at->mft->data->spc << GRUB_NTFS_BLK_SHR, 0); pa = at->attr_nxt + u16at (at->attr_nxt, 4); while (pa < at->attr_end) { @@ -511,10 +537,10 @@ static grub_err_t read_mft (struct grub_ntfs_data *data, char *buf, grub_uint32_t mftno) { if (read_attr - (&data->mmft.attr, buf, mftno * ((grub_disk_addr_t) data->mft_size << BLK_SHR), - data->mft_size << BLK_SHR, 0, 0)) + (&data->mmft.attr, buf, mftno * ((grub_disk_addr_t) data->mft_size << GRUB_NTFS_BLK_SHR), + data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0)) return grub_error (GRUB_ERR_BAD_FS, "read MFT 0x%X fails", mftno); - return fixup (data, buf, data->mft_size, "FILE"); + return fixup (buf, data->mft_size, "FILE"); } static grub_err_t @@ -524,7 +550,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint32_t mftno) mft->inode_read = 1; - mft->buf = grub_malloc (mft->data->mft_size << BLK_SHR); + mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR); if (mft->buf == NULL) return grub_errno; @@ -539,7 +565,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint32_t mftno) { char *pa; - pa = locate_attr (&mft->attr, mft, AT_DATA); + pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_DATA); if (pa == NULL) return grub_error (GRUB_ERR_BAD_FS, "no $DATA in MFT 0x%X", mftno); @@ -548,7 +574,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint32_t mftno) else mft->size = u64at (pa, 0x30); - if ((mft->attr.flags & AF_ALST) == 0) + if ((mft->attr.flags & GRUB_NTFS_AF_ALST) == 0) mft->attr.attr_end = 0; /* Don't jump to attribute list */ } else @@ -593,6 +619,7 @@ list_file (struct grub_ntfs_file *diro, char *pos, { enum grub_fshelp_filetype type; struct grub_ntfs_file *fdiro; + grub_uint32_t attr; if (u16at (pos, 4)) { @@ -600,9 +627,13 @@ list_file (struct grub_ntfs_file *diro, char *pos, return 0; } - type = - (u32at (pos, 0x48) & ATTR_DIRECTORY) ? GRUB_FSHELP_DIR : - GRUB_FSHELP_REG; + attr = u32at (pos, 0x48); + if (attr & GRUB_NTFS_ATTR_REPARSE) + type = GRUB_FSHELP_SYMLINK; + else if (attr & GRUB_NTFS_ATTR_DIRECTORY) + type = GRUB_FSHELP_DIR; + else + type = GRUB_FSHELP_REG; fdiro = grub_zalloc (sizeof (struct grub_ntfs_file)); if (!fdiro) @@ -610,13 +641,23 @@ list_file (struct grub_ntfs_file *diro, char *pos, fdiro->data = diro->data; fdiro->ino = u32at (pos, 0); + if (u64at (pos, 0x20) > u64at (pos, 0x28)) + fdiro->mtime = u64at (pos, 0x20); + else + fdiro->mtime = u64at (pos, 0x28); - ustr = grub_malloc (ns * 4 + 1); + ustr = grub_malloc (ns * GRUB_MAX_UTF8_PER_UTF16 + 1); if (ustr == NULL) return 0; - *grub_utf16_to_utf8 ((grub_uint8_t *) ustr, (grub_uint16_t *) np, - ns) = '\0'; + { + grub_uint16_t tmp[ns]; + int i; + for (i = 0; i < ns; i++) + tmp[i] = grub_le_to_cpu16 (grub_get_unaligned16 ((char *) np + + 2 * i)); + *grub_utf16_to_utf8 ((grub_uint8_t *) ustr, tmp, ns) = '\0'; + } if (namespace) type |= GRUB_FSHELP_CASE_INSENSITIVE; @@ -633,6 +674,102 @@ list_file (struct grub_ntfs_file *diro, char *pos, return 0; } +struct symlink_descriptor +{ + grub_uint32_t type; + grub_uint32_t total_len; + grub_uint16_t off1; + grub_uint16_t len1; + grub_uint16_t off2; + grub_uint16_t len2; +} __attribute__ ((packed)); + +static char * +grub_ntfs_read_symlink (grub_fshelp_node_t node) +{ + struct grub_ntfs_file *mft; + struct symlink_descriptor symdesc; + grub_err_t err; + grub_uint16_t *buf16; + char *buf, *end; + grub_size_t len; + grub_size_t i; + char *pa; + grub_size_t off; + + mft = (struct grub_ntfs_file *) node; + + mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (mft->buf == NULL) + return NULL; + + if (read_mft (mft->data, mft->buf, mft->ino)) + return NULL; + + pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_SYMLINK); + if (pa == NULL) + { + grub_error (GRUB_ERR_BAD_FS, "no $SYMLINK in MFT 0x%X", mft->ino); + return NULL; + } + + err = read_attr (&mft->attr, (char *) &symdesc, 0, + sizeof (struct symlink_descriptor), 1, 0); + if (err) + return NULL; + + switch (grub_cpu_to_le32 (symdesc.type)) + { + case 0xa000000c: + off = (sizeof (struct symlink_descriptor) + 4 + + grub_cpu_to_le32 (symdesc.off1)); + len = grub_cpu_to_le32 (symdesc.len1); + break; + case 0xa0000003: + off = (sizeof (struct symlink_descriptor) + + grub_cpu_to_le32 (symdesc.off1)); + len = grub_cpu_to_le32 (symdesc.len1); + break; + default: + grub_error (GRUB_ERR_BAD_FS, "symlink type invalid (%x)", + grub_cpu_to_le32 (symdesc.type)); + return NULL; + } + + buf16 = grub_malloc (len); + if (!buf16) + return NULL; + + err = read_attr (&mft->attr, (char *) buf16, off, len, 1, 0); + if (err) + return NULL; + + buf = grub_malloc (len * 2 + 1); + if (!buf) + { + grub_free (buf16); + return NULL; + } + + for (i = 0; i < len / 2; i++) + { + buf16[i] = grub_le_to_cpu16 (buf16[i]); + if (buf16[i] == '\\') + buf16[i] = '/'; + } + + end = (char *) grub_utf16_to_utf8 ((grub_uint8_t *) buf, buf16, len / 2); + *end = '\0'; + /* Split the sequence to avoid GCC thinking that this is a trigraph. */ + if (grub_memcmp (buf, "/?" "?/", 4) == 0 && buf[5] == ':' && buf[6] == '/' + && grub_isalpha (buf[4])) + { + grub_memmove (buf, buf + 6, end - buf + 1 - 6); + end -= 6; + } + return buf; +} + static int grub_ntfs_iterate_dir (grub_fshelp_node_t dir, int NESTED_FUNC_ATTR @@ -662,7 +799,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, init_attr (at, mft); while (1) { - if ((cur_pos = find_attr (at, AT_INDEX_ROOT)) == NULL) + if ((cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ROOT)) == NULL) { grub_error (GRUB_ERR_BAD_FS, "no $INDEX_ROOT"); goto done; @@ -688,7 +825,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, bitmap_len = 0; free_attr (at); init_attr (at, mft); - while ((cur_pos = find_attr (at, AT_BITMAP)) != NULL) + while ((cur_pos = find_attr (at, GRUB_NTFS_AT_BITMAP)) != NULL) { int ofs; @@ -729,7 +866,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, } free_attr (at); - cur_pos = locate_attr (at, mft, AT_INDEX_ALLOCATION); + cur_pos = locate_attr (at, mft, GRUB_NTFS_AT_INDEX_ALLOCATION); while (cur_pos != NULL) { /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */ @@ -737,7 +874,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, (u32at (cur_pos, 0x40) == 0x490024) && (u32at (cur_pos, 0x44) == 0x300033)) break; - cur_pos = find_attr (at, AT_INDEX_ALLOCATION); + cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ALLOCATION); } if ((!cur_pos) && (bitmap)) @@ -750,7 +887,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, { grub_disk_addr_t v, i; - indx = grub_malloc (mft->data->idx_size << BLK_SHR); + indx = grub_malloc (mft->data->idx_size << GRUB_NTFS_BLK_SHR); if (indx == NULL) goto done; @@ -760,9 +897,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, if (*bitmap & v) { if ((read_attr - (at, indx, i * (mft->data->idx_size << BLK_SHR), - (mft->data->idx_size << BLK_SHR), 0, 0)) - || (fixup (mft->data, indx, mft->data->idx_size, "INDX"))) + (at, indx, i * (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), 0, 0)) + || (fixup (indx, mft->data->idx_size, "INDX"))) goto done; ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], hook); if (ret) @@ -807,44 +944,45 @@ grub_ntfs_mount (grub_disk_t disk) if (grub_memcmp ((char *) &bpb.oem_name, "NTFS", 4)) goto fail; - data->blocksize = grub_le_to_cpu16 (bpb.bytes_per_sector); - data->spc = bpb.sectors_per_cluster * (data->blocksize >> BLK_SHR); + data->spc = (bpb.sectors_per_cluster + * (grub_le_to_cpu16 (bpb.bytes_per_sector) + >> GRUB_NTFS_BLK_SHR)); if (bpb.clusters_per_mft > 0) data->mft_size = data->spc * bpb.clusters_per_mft; else - data->mft_size = 1 << (-bpb.clusters_per_mft - BLK_SHR); + data->mft_size = 1 << (-bpb.clusters_per_mft - GRUB_NTFS_BLK_SHR); if (bpb.clusters_per_index > 0) data->idx_size = data->spc * bpb.clusters_per_index; else - data->idx_size = 1 << (-bpb.clusters_per_index - BLK_SHR); + data->idx_size = 1 << (-bpb.clusters_per_index - GRUB_NTFS_BLK_SHR); data->mft_start = grub_le_to_cpu64 (bpb.mft_lcn) * data->spc; - if ((data->mft_size > MAX_MFT) || (data->idx_size > MAX_IDX)) + if ((data->mft_size > GRUB_NTFS_MAX_MFT) || (data->idx_size > GRUB_NTFS_MAX_IDX)) goto fail; data->mmft.data = data; data->cmft.data = data; - data->mmft.buf = grub_malloc (data->mft_size << BLK_SHR); + data->mmft.buf = grub_malloc (data->mft_size << GRUB_NTFS_BLK_SHR); if (!data->mmft.buf) goto fail; if (grub_disk_read - (disk, data->mft_start, 0, data->mft_size << BLK_SHR, data->mmft.buf)) + (disk, data->mft_start, 0, data->mft_size << GRUB_NTFS_BLK_SHR, data->mmft.buf)) goto fail; data->uuid = grub_le_to_cpu64 (bpb.num_serial); - if (fixup (data, data->mmft.buf, data->mft_size, "FILE")) + if (fixup (data->mmft.buf, data->mft_size, "FILE")) goto fail; - if (!locate_attr (&data->mmft.attr, &data->mmft, AT_DATA)) + if (!locate_attr (&data->mmft.attr, &data->mmft, GRUB_NTFS_AT_DATA)) goto fail; - if (init_file (&data->cmft, FILE_ROOT)) + if (init_file (&data->cmft, GRUB_NTFS_FILE_ROOT)) goto fail; return data; @@ -880,6 +1018,10 @@ grub_ntfs_dir (grub_device_t device, const char *path, struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; + info.mtime = grub_divmod64 (node->mtime, 10000000, 0) + - 86400ULL * 365 * (1970 - 1601) + - 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100); grub_free (node); return hook (filename, &info); } @@ -891,7 +1033,7 @@ grub_ntfs_dir (grub_device_t device, const char *path, goto fail; grub_fshelp_find_file (path, &data->cmft, &fdiro, grub_ntfs_iterate_dir, - 0, GRUB_FSHELP_DIR); + grub_ntfs_read_symlink, GRUB_FSHELP_DIR); if (grub_errno) goto fail; @@ -929,7 +1071,7 @@ grub_ntfs_open (grub_file_t file, const char *name) goto fail; grub_fshelp_find_file (name, &data->cmft, &mft, grub_ntfs_iterate_dir, - 0, GRUB_FSHELP_REG); + grub_ntfs_read_symlink, GRUB_FSHELP_REG); if (grub_errno) goto fail; @@ -1020,7 +1162,7 @@ grub_ntfs_label (grub_device_t device, char **label) if (!mft->inode_read) { - mft->buf = grub_malloc (mft->data->mft_size << BLK_SHR); + mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR); if (mft->buf == NULL) goto fail; @@ -1029,7 +1171,7 @@ grub_ntfs_label (grub_device_t device, char **label) } init_attr (&mft->attr, mft); - pa = find_attr (&mft->attr, AT_VOLUME_NAME); + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) { char *buf; @@ -1038,8 +1180,14 @@ grub_ntfs_label (grub_device_t device, char **label) len = u32at (pa, 0x10) / 2; buf = grub_malloc (len * 4 + 1); pa += u16at (pa, 0x14); - *grub_utf16_to_utf8 ((grub_uint8_t *) buf, (grub_uint16_t *) pa, len) = - '\0'; + { + grub_uint16_t tmp[len]; + int i; + for (i = 0; i < len; i++) + tmp[i] = grub_le_to_cpu16 (grub_get_unaligned16 (pa + 2 * i)); + *grub_utf16_to_utf8 ((grub_uint8_t *) buf, tmp, len) = + '\0'; + } *label = buf; } @@ -1072,15 +1220,20 @@ grub_ntfs_uuid (grub_device_t device, char **uuid) data = grub_ntfs_mount (disk); if (data) { + char *ptr; *uuid = grub_xasprintf ("%016llx", (unsigned long long) data->uuid); + if (*uuid) + for (ptr = *uuid; *ptr; ptr++) + *ptr = grub_toupper (*ptr); + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); } else *uuid = NULL; grub_dl_unref (my_mod); - grub_free (data); - return grub_errno; } diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c index c29979edc..890faa3bf 100644 --- a/grub-core/fs/ntfscomp.c +++ b/grub-core/fs/ntfscomp.c @@ -21,9 +21,10 @@ #include #include #include -#include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t decomp_nextvcn (struct grub_ntfs_comp *cc) { @@ -33,7 +34,7 @@ decomp_nextvcn (struct grub_ntfs_comp *cc) (cc->disk, (cc->comp_table[cc->comp_head][1] - (cc->comp_table[cc->comp_head][0] - cc->cbuf_vcn)) * cc->spc, 0, - cc->spc << BLK_SHR, cc->cbuf)) + cc->spc << GRUB_NTFS_BLK_SHR, cc->cbuf)) return grub_errno; cc->cbuf_vcn++; if ((cc->cbuf_vcn >= cc->comp_table[cc->comp_head][0])) @@ -45,7 +46,7 @@ decomp_nextvcn (struct grub_ntfs_comp *cc) static grub_err_t decomp_getch (struct grub_ntfs_comp *cc, unsigned char *res) { - if (cc->cbuf_ofs >= (cc->spc << BLK_SHR)) + if (cc->cbuf_ofs >= (cc->spc << GRUB_NTFS_BLK_SHR)) { if (decomp_nextvcn (cc)) return grub_errno; @@ -85,7 +86,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) bits = copied = tag = 0; while (cnt > 0) { - if (copied > COM_LEN) + if (copied > GRUB_NTFS_COM_LEN) return grub_error (GRUB_ERR_BAD_FS, "compression block too large"); @@ -148,7 +149,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) } else { - if (cnt != COM_LEN) + if (cnt != GRUB_NTFS_COM_LEN) return grub_error (GRUB_ERR_BAD_FS, "invalid compression block size"); } @@ -158,7 +159,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) { int n; - n = (cc->spc << BLK_SHR) - cc->cbuf_ofs; + n = (cc->spc << GRUB_NTFS_BLK_SHR) - cc->cbuf_ofs; if (n > cnt) n = cnt; if ((dest) && (n)) @@ -177,7 +178,7 @@ decomp_block (struct grub_ntfs_comp *cc, char *dest) static grub_err_t read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) { - int cpb = COM_SEC / ctx->comp.spc; + int cpb = GRUB_NTFS_COM_SEC / ctx->comp.spc; while (num) { @@ -190,7 +191,7 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) return grub_error (GRUB_ERR_BAD_FS, "invalid compression block"); ctx->comp.comp_head = ctx->comp.comp_tail = 0; ctx->comp.cbuf_vcn = ctx->target_vcn; - ctx->comp.cbuf_ofs = (ctx->comp.spc << BLK_SHR); + ctx->comp.cbuf_ofs = (ctx->comp.spc << GRUB_NTFS_BLK_SHR); if (ctx->target_vcn >= ctx->next_vcn) { if (grub_ntfs_read_run_list (ctx)) @@ -198,7 +199,7 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) } while (ctx->target_vcn + 16 > ctx->next_vcn) { - if (ctx->flags & RF_BLNK) + if (ctx->flags & GRUB_NTFS_RF_BLNK) break; ctx->comp.comp_table[ctx->comp.comp_tail][0] = ctx->next_vcn; ctx->comp.comp_table[ctx->comp.comp_tail][1] = @@ -214,15 +215,15 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) nn = num; num -= nn; - if (ctx->flags & RF_BLNK) + if (ctx->flags & GRUB_NTFS_RF_BLNK) { ctx->target_vcn += nn * cpb; if (ctx->comp.comp_tail == 0) { if (buf) { - grub_memset (buf, 0, nn * COM_LEN); - buf += nn * COM_LEN; + grub_memset (buf, 0, nn * GRUB_NTFS_COM_LEN); + buf += nn * GRUB_NTFS_COM_LEN; } } else @@ -232,7 +233,7 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) if (decomp_block (&ctx->comp, buf)) return grub_errno; if (buf) - buf += COM_LEN; + buf += GRUB_NTFS_COM_LEN; nn--; } } @@ -257,9 +258,9 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) (ctx->comp.comp_table[ctx->comp.comp_head][1] - (ctx->comp.comp_table[ctx->comp.comp_head][0] - ctx->target_vcn)) * ctx->comp.spc, 0, - tt * (ctx->comp.spc << BLK_SHR), buf)) + tt * (ctx->comp.spc << GRUB_NTFS_BLK_SHR), buf)) return grub_errno; - buf += tt * (ctx->comp.spc << BLK_SHR); + buf += tt * (ctx->comp.spc << GRUB_NTFS_BLK_SHR); } nn -= tt; if (ctx->target_vcn >= @@ -274,9 +275,9 @@ read_block (struct grub_ntfs_rlst *ctx, char *buf, int num) (ctx->comp.disk, (ctx->target_vcn - ctx->curr_vcn + ctx->curr_lcn) * ctx->comp.spc, 0, - nn * (ctx->comp.spc << BLK_SHR), buf)) + nn * (ctx->comp.spc << GRUB_NTFS_BLK_SHR), buf)) return grub_errno; - buf += nn * (ctx->comp.spc << BLK_SHR); + buf += nn * (ctx->comp.spc << GRUB_NTFS_BLK_SHR); } ctx->target_vcn += nn; } @@ -292,7 +293,7 @@ ntfscomp (struct grub_ntfs_attr *at, char *dest, grub_uint32_t ofs, grub_err_t ret; ctx->comp.comp_head = ctx->comp.comp_tail = 0; - ctx->comp.cbuf = grub_malloc ((ctx->comp.spc) << BLK_SHR); + ctx->comp.cbuf = grub_malloc ((ctx->comp.spc) << GRUB_NTFS_BLK_SHR); if (!ctx->comp.cbuf) return 0; @@ -302,17 +303,17 @@ ntfscomp (struct grub_ntfs_attr *at, char *dest, grub_uint32_t ofs, if ((vcn > ctx->target_vcn) && (read_block - (ctx, NULL, ((vcn - ctx->target_vcn) * ctx->comp.spc) / COM_SEC))) + (ctx, NULL, ((vcn - ctx->target_vcn) * ctx->comp.spc) / GRUB_NTFS_COM_SEC))) { ret = grub_errno; goto quit; } - if (ofs % COM_LEN) + if (ofs % GRUB_NTFS_COM_LEN) { grub_uint32_t t, n, o; - t = ctx->target_vcn * (ctx->comp.spc << BLK_SHR); + t = ctx->target_vcn * (ctx->comp.spc << GRUB_NTFS_BLK_SHR); if (read_block (ctx, at->sbuf, 1)) { ret = grub_errno; @@ -321,8 +322,8 @@ ntfscomp (struct grub_ntfs_attr *at, char *dest, grub_uint32_t ofs, at->save_pos = t; - o = ofs % COM_LEN; - n = COM_LEN - o; + o = ofs % GRUB_NTFS_COM_LEN; + n = GRUB_NTFS_COM_LEN - o; if (n > len) n = len; grub_memcpy (dest, &at->sbuf[o], n); @@ -332,19 +333,19 @@ ntfscomp (struct grub_ntfs_attr *at, char *dest, grub_uint32_t ofs, len -= n; } - if (read_block (ctx, dest, len / COM_LEN)) + if (read_block (ctx, dest, len / GRUB_NTFS_COM_LEN)) { ret = grub_errno; goto quit; } - dest += (len / COM_LEN) * COM_LEN; - len = len % COM_LEN; + dest += (len / GRUB_NTFS_COM_LEN) * GRUB_NTFS_COM_LEN; + len = len % GRUB_NTFS_COM_LEN; if (len) { grub_uint32_t t; - t = ctx->target_vcn * (ctx->comp.spc << BLK_SHR); + t = ctx->target_vcn * (ctx->comp.spc << GRUB_NTFS_BLK_SHR); if (read_block (ctx, at->sbuf, 1)) { ret = grub_errno; diff --git a/grub-core/fs/odc.c b/grub-core/fs/odc.c new file mode 100644 index 000000000..5fa88e3f9 --- /dev/null +++ b/grub-core/fs/odc.c @@ -0,0 +1,2 @@ +#define MODE_ODC 1 +#include "cpio.c" diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c index e92279554..82541210d 100644 --- a/grub-core/fs/reiserfs.c +++ b/grub-core/fs/reiserfs.c @@ -39,6 +39,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define MIN(a, b) \ ({ typeof (a) _a = (a); \ typeof (b) _b = (b); \ @@ -55,8 +57,6 @@ #define REISERFS_MAGIC_DESC_BLOCK "ReIsErLB" /* If the 3rd bit of an item state is set, then it's visible. */ #define GRUB_REISERFS_VISIBLE_MASK ((grub_uint16_t) 0x04) -#define REISERFS_MAX_LABEL_LENGTH 16 -#define REISERFS_LABEL_OFFSET 0x64 #define S_IFLNK 0xA000 @@ -107,6 +107,7 @@ struct grub_reiserfs_superblock grub_uint32_t inode_generation; grub_uint8_t unused[4]; grub_uint16_t uuid[8]; + char label[16]; } __attribute__ ((packed)); struct grub_reiserfs_journal_header @@ -222,6 +223,7 @@ struct grub_fshelp_node grub_uint32_t block_number; /* 0 if node is not found. */ grub_uint16_t block_position; grub_uint64_t next_offset; + grub_int32_t mtime; enum grub_reiserfs_item_type type; /* To know how to read the header. */ struct grub_reiserfs_item_header header; }; @@ -868,6 +870,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, entry_v1_stat.rdev, entry_v1_stat.first_direct_byte); #endif + entry_item->mtime = grub_le_to_cpu32 (entry_v1_stat.mtime); if ((grub_le_to_cpu16 (entry_v1_stat.mode) & S_IFLNK) == S_IFLNK) entry_type = GRUB_FSHELP_SYMLINK; @@ -914,6 +917,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, entry_v2_stat.blocks, entry_v2_stat.first_direct_byte); #endif + entry_item->mtime = grub_le_to_cpu32 (entry_v2_stat.mtime); if ((grub_le_to_cpu16 (entry_v2_stat.mode) & S_IFLNK) == S_IFLNK) entry_type = GRUB_FSHELP_SYMLINK; @@ -1276,6 +1280,8 @@ grub_reiserfs_dir (grub_device_t device, const char *path, struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; + info.mtime = node->mtime; grub_free (node); return hook (filename, &info); } @@ -1316,14 +1322,24 @@ grub_reiserfs_dir (grub_device_t device, const char *path, static grub_err_t grub_reiserfs_label (grub_device_t device, char **label) { - *label = grub_malloc (REISERFS_MAX_LABEL_LENGTH); - if (*label) + struct grub_reiserfs_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_reiserfs_mount (disk); + if (data) { - grub_disk_read (device->disk, - REISERFS_SUPER_BLOCK_OFFSET / GRUB_DISK_SECTOR_SIZE, - REISERFS_LABEL_OFFSET, REISERFS_MAX_LABEL_LENGTH, - *label); + *label = grub_strndup (data->superblock.label, + sizeof (data->superblock.label)); } + else + *label = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + return grub_errno; } @@ -1335,21 +1351,25 @@ grub_reiserfs_uuid (grub_device_t device, char **uuid) grub_dl_ref (my_mod); + *uuid = NULL; data = grub_reiserfs_mount (disk); if (data) { - *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - grub_be_to_cpu16 (data->superblock.uuid[0]), - grub_be_to_cpu16 (data->superblock.uuid[1]), - grub_be_to_cpu16 (data->superblock.uuid[2]), - grub_be_to_cpu16 (data->superblock.uuid[3]), - grub_be_to_cpu16 (data->superblock.uuid[4]), - grub_be_to_cpu16 (data->superblock.uuid[5]), - grub_be_to_cpu16 (data->superblock.uuid[6]), - grub_be_to_cpu16 (data->superblock.uuid[7])); + unsigned i; + for (i = 0; i < ARRAY_SIZE (data->superblock.uuid); i++) + if (data->superblock.uuid[i]) + break; + if (i < ARRAY_SIZE (data->superblock.uuid)) + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->superblock.uuid[0]), + grub_be_to_cpu16 (data->superblock.uuid[1]), + grub_be_to_cpu16 (data->superblock.uuid[2]), + grub_be_to_cpu16 (data->superblock.uuid[3]), + grub_be_to_cpu16 (data->superblock.uuid[4]), + grub_be_to_cpu16 (data->superblock.uuid[5]), + grub_be_to_cpu16 (data->superblock.uuid[6]), + grub_be_to_cpu16 (data->superblock.uuid[7])); } - else - *uuid = NULL; grub_dl_unref (my_mod); diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c new file mode 100644 index 000000000..3ea90a214 --- /dev/null +++ b/grub-core/fs/romfs.c @@ -0,0 +1,470 @@ +/* + * 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_romfs_superblock +{ + char magic[8]; +#define GRUB_ROMFS_MAGIC "-rom1fs-" + grub_uint32_t total_size; + grub_uint32_t chksum; + char label[0]; +}; + +struct grub_romfs_file_header +{ + grub_uint32_t next_file; + grub_uint32_t spec; + grub_uint32_t size; + grub_uint32_t chksum; + char name[0]; +}; + +struct grub_romfs_data +{ + grub_disk_addr_t first_file; + grub_disk_t disk; +}; + +struct grub_fshelp_node +{ + grub_disk_addr_t addr; + struct grub_romfs_data *data; + grub_disk_addr_t data_addr; + /* Not filled for root. */ + struct grub_romfs_file_header file; +}; + +#define GRUB_ROMFS_ALIGN 16 +#define GRUB_ROMFS_TYPE_MASK 7 +#define GRUB_ROMFS_TYPE_HARDLINK 0 +#define GRUB_ROMFS_TYPE_DIRECTORY 1 +#define GRUB_ROMFS_TYPE_REGULAR 2 +#define GRUB_ROMFS_TYPE_SYMLINK 3 + +static grub_err_t +do_checksum (void *in, grub_size_t insize) +{ + grub_uint32_t *a = in; + grub_size_t sz = insize / 4; + grub_uint32_t *b = a + sz; + grub_uint32_t csum = 0; + + while (a < b) + csum += grub_be_to_cpu32 (*a++); + if (csum) + return grub_error (GRUB_ERR_BAD_FS, "invalid checksum"); + return GRUB_ERR_NONE; +} + +static struct grub_romfs_data * +grub_romfs_mount (grub_device_t dev) +{ + union { + struct grub_romfs_superblock sb; + char d[512]; + } sb; + grub_err_t err; + char *ptr; + grub_disk_addr_t sec = 0; + struct grub_romfs_data *data; + if (!dev->disk) + { + grub_error (GRUB_ERR_BAD_FS, "not a disk"); + return NULL; + } + err = grub_disk_read (dev->disk, 0, 0, sizeof (sb), &sb); + if (err == GRUB_ERR_OUT_OF_RANGE) + err = grub_errno = GRUB_ERR_BAD_FS; + if (err) + return NULL; + if (grub_be_to_cpu32 (sb.sb.total_size) < sizeof (sb)) + { + grub_error (GRUB_ERR_BAD_FS, "too short filesystem"); + return NULL; + } + err = do_checksum (&sb, sizeof (sb) < grub_be_to_cpu32 (sb.sb.total_size) ? + sizeof (sb) : grub_be_to_cpu32 (sb.sb.total_size)); + if (err) + return NULL; + for (ptr = sb.sb.label; (void *) ptr < (void *) (&sb + 1) + && ptr - sb.d < (grub_ssize_t) grub_be_to_cpu32 (sb.sb.total_size); ptr++) + if (!*ptr) + break; + while ((void *) ptr == &sb + 1) + { + sec++; + err = grub_disk_read (dev->disk, sec, 0, sizeof (sb), &sb); + if (err == GRUB_ERR_OUT_OF_RANGE) + err = grub_errno = GRUB_ERR_BAD_FS; + if (err) + return NULL; + for (ptr = sb.d; (void *) ptr < (void *) (&sb + 1) + && (ptr - sb.d + (sec << GRUB_DISK_SECTOR_BITS) + < grub_be_to_cpu32 (sb.sb.total_size)); + ptr++) + if (!*ptr) + break; + } + data = grub_malloc (sizeof (*data)); + if (!data) + return NULL; + data->first_file = ALIGN_UP (ptr + 1 - sb.d, GRUB_ROMFS_ALIGN) + + (sec << GRUB_DISK_SECTOR_BITS); + data->disk = dev->disk; + return data; +} + +static char * +grub_romfs_read_symlink (grub_fshelp_node_t node) +{ + char *ret; + grub_err_t err; + ret = grub_malloc (grub_be_to_cpu32 (node->file.size) + 1); + if (!ret) + return NULL; + err = grub_disk_read (node->data->disk, + (node->data_addr) >> GRUB_DISK_SECTOR_BITS, + (node->data_addr) & (GRUB_DISK_SECTOR_SIZE - 1), + grub_be_to_cpu32 (node->file.size), ret); + if (err) + { + grub_free (ret); + return NULL; + } + ret[grub_be_to_cpu32 (node->file.size)] = 0; + return ret; +} + +static int +grub_romfs_iterate_dir (grub_fshelp_node_t dir, + int NESTED_FUNC_ATTR + (*hook) (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node)) +{ + grub_disk_addr_t caddr; + struct grub_romfs_file_header hdr; + unsigned nptr; + unsigned i, j; + grub_size_t a = 0; + grub_properly_aligned_t *name = NULL; + + for (caddr = dir->data_addr; caddr; + caddr = grub_be_to_cpu32 (hdr.next_file) & ~(GRUB_ROMFS_ALIGN - 1)) + { + grub_disk_addr_t naddr = caddr + sizeof (hdr); + grub_uint32_t csum = 0; + enum grub_fshelp_filetype filetype = GRUB_FSHELP_UNKNOWN; + struct grub_fshelp_node *node = NULL; + grub_err_t err; + + err = grub_disk_read (dir->data->disk, caddr >> GRUB_DISK_SECTOR_BITS, + caddr & (GRUB_DISK_SECTOR_SIZE - 1), + sizeof (hdr), &hdr); + if (err) + { + grub_free (name); + return 1; + } + for (nptr = 0; ; nptr++, naddr += 16) + { + if (a <= nptr) + { + grub_properly_aligned_t *on; + a = 2 * (nptr + 1); + on = name; + name = grub_realloc (name, a * 16); + if (!name) + { + grub_free (on); + return 1; + } + } + COMPILE_TIME_ASSERT (16 % sizeof (name[0]) == 0); + err = grub_disk_read (dir->data->disk, naddr >> GRUB_DISK_SECTOR_BITS, + naddr & (GRUB_DISK_SECTOR_SIZE - 1), + 16, name + (16 / sizeof (name[0])) * nptr); + if (err) + return 1; + for (j = 0; j < 16; j++) + if (!((char *) name)[16 * nptr + j]) + break; + if (j != 16) + break; + } + for (i = 0; i < sizeof (hdr) / sizeof (grub_uint32_t); i++) + csum += grub_be_to_cpu32 (((grub_uint32_t *) &hdr)[i]); + for (i = 0; i < (nptr + 1) * 4; i++) + csum += grub_be_to_cpu32 (((grub_uint32_t *) name)[i]); + if (csum != 0) + { + grub_error (GRUB_ERR_BAD_FS, "invalid checksum"); + grub_free (name); + return 1; + } + node = grub_malloc (sizeof (*node)); + if (!node) + return 1; + node->addr = caddr; + node->data_addr = caddr + (nptr + 1) * 16 + sizeof (hdr); + node->data = dir->data; + node->file = hdr; + switch (grub_be_to_cpu32 (hdr.next_file) & GRUB_ROMFS_TYPE_MASK) + { + case GRUB_ROMFS_TYPE_REGULAR: + filetype = GRUB_FSHELP_REG; + break; + case GRUB_ROMFS_TYPE_SYMLINK: + filetype = GRUB_FSHELP_SYMLINK; + break; + case GRUB_ROMFS_TYPE_DIRECTORY: + node->data_addr = grub_be_to_cpu32 (hdr.spec); + filetype = GRUB_FSHELP_DIR; + break; + case GRUB_ROMFS_TYPE_HARDLINK: + { + grub_disk_addr_t laddr; + node->addr = laddr = grub_be_to_cpu32 (hdr.spec); + err = grub_disk_read (dir->data->disk, + laddr >> GRUB_DISK_SECTOR_BITS, + laddr & (GRUB_DISK_SECTOR_SIZE - 1), + sizeof (node->file), &node->file); + if (err) + return 1; + if ((grub_be_to_cpu32 (node->file.next_file) & GRUB_ROMFS_TYPE_MASK) + == GRUB_ROMFS_TYPE_REGULAR + || (grub_be_to_cpu32 (node->file.next_file) + & GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_SYMLINK) + { + laddr += sizeof (hdr); + while (1) + { + char buf[16]; + err = grub_disk_read (dir->data->disk, + laddr >> GRUB_DISK_SECTOR_BITS, + laddr & (GRUB_DISK_SECTOR_SIZE - 1), + 16, buf); + if (err) + return 1; + for (i = 0; i < 16; i++) + if (!buf[i]) + break; + if (i != 16) + break; + laddr += 16; + } + node->data_addr = laddr + 16; + } + if ((grub_be_to_cpu32 (node->file.next_file) + & GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_REGULAR) + filetype = GRUB_FSHELP_REG; + if ((grub_be_to_cpu32 (node->file.next_file) + & GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_SYMLINK) + filetype = GRUB_FSHELP_SYMLINK; + if ((grub_be_to_cpu32 (node->file.next_file) & GRUB_ROMFS_TYPE_MASK) + == GRUB_ROMFS_TYPE_DIRECTORY) + { + node->data_addr = grub_be_to_cpu32 (node->file.spec); + filetype = GRUB_FSHELP_DIR; + } + + break; + } + } + + if (hook ((char *) name, filetype, node)) + { + grub_free (name); + return 1; + } + } + grub_free (name); + return 0; +} + +static grub_err_t +grub_romfs_dir (grub_device_t device, const char *path, + int (*hook) (const char *filename, + const struct grub_dirhook_info *info)) +{ + struct grub_romfs_data *data = 0; + struct grub_fshelp_node *fdiro = 0, start; + + auto int NESTED_FUNC_ATTR iterate (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node); + + int NESTED_FUNC_ATTR iterate (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node) + { + struct grub_dirhook_info info; + grub_memset (&info, 0, sizeof (info)); + + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + grub_free (node); + return hook (filename, &info); + } + + data = grub_romfs_mount (device); + if (! data) + goto fail; + + start.addr = data->first_file; + start.data_addr = data->first_file; + start.data = data; + grub_fshelp_find_file (path, &start, &fdiro, grub_romfs_iterate_dir, + grub_romfs_read_symlink, GRUB_FSHELP_DIR); + if (grub_errno) + goto fail; + + grub_romfs_iterate_dir (fdiro, iterate); + + fail: + grub_free (data); + + return grub_errno; +} + +static grub_err_t +grub_romfs_open (struct grub_file *file, const char *name) +{ + struct grub_romfs_data *data = 0; + struct grub_fshelp_node *fdiro = 0, start; + + data = grub_romfs_mount (file->device); + if (! data) + goto fail; + + start.addr = data->first_file; + start.data_addr = data->first_file; + start.data = data; + + grub_fshelp_find_file (name, &start, &fdiro, grub_romfs_iterate_dir, + grub_romfs_read_symlink, GRUB_FSHELP_REG); + if (grub_errno) + goto fail; + + file->size = grub_be_to_cpu32 (fdiro->file.size); + file->data = fdiro; + return GRUB_ERR_NONE; + + fail: + grub_free (data); + + return grub_errno; +} + +static grub_ssize_t +grub_romfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_fshelp_node *data = file->data; + + /* XXX: The file is stored in as a single extent. */ + data->data->disk->read_hook = file->read_hook; + grub_disk_read (data->data->disk, + (data->data_addr + file->offset) >> GRUB_DISK_SECTOR_BITS, + (data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1), + len, buf); + data->data->disk->read_hook = NULL; + + if (grub_errno) + return -1; + + return len; +} + +static grub_err_t +grub_romfs_close (grub_file_t file) +{ + struct grub_fshelp_node *data = file->data; + + grub_free (data->data); + grub_free (data); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_romfs_label (grub_device_t device, char **label) +{ + struct grub_romfs_data *data; + grub_err_t err; + + *label = NULL; + + data = grub_romfs_mount (device); + if (!data) + return grub_errno; + *label = grub_malloc (data->first_file + 1 + - sizeof (struct grub_romfs_superblock)); + if (!*label) + { + grub_free (data); + return grub_errno; + } + err = grub_disk_read (device->disk, 0, sizeof (struct grub_romfs_superblock), + data->first_file + - sizeof (struct grub_romfs_superblock), + *label); + if (err) + { + grub_free (data); + grub_free (*label); + *label = NULL; + return err; + } + (*label)[data->first_file - sizeof (struct grub_romfs_superblock)] = 0; + grub_free (data); + return GRUB_ERR_NONE; +} + + +static struct grub_fs grub_romfs_fs = + { + .name = "romfs", + .dir = grub_romfs_dir, + .open = grub_romfs_open, + .read = grub_romfs_read, + .close = grub_romfs_close, + .label = grub_romfs_label, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, +#endif + .next = 0 + }; + +GRUB_MOD_INIT(romfs) +{ + grub_fs_register (&grub_romfs_fs); +} + +GRUB_MOD_FINI(romfs) +{ + grub_fs_unregister (&grub_romfs_fs); +} diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c index 68f8b3a6e..bc7258963 100644 --- a/grub-core/fs/sfs.c +++ b/grub-core/fs/sfs.c @@ -25,6 +25,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* The common header for a block. */ struct grub_sfs_bheader @@ -66,7 +69,7 @@ struct grub_sfs_obj grub_uint32_t dir_objc; } dir __attribute__ ((packed)); } file_dir; - grub_uint8_t unused3[4]; + grub_uint32_t mtime; grub_uint8_t type; grub_uint8_t filename[1]; grub_uint8_t comment[1]; @@ -119,6 +122,7 @@ struct grub_fshelp_node struct grub_sfs_data *data; int block; int size; + grub_uint32_t mtime; }; /* Information about a "mounted" sfs filesystem. */ @@ -149,7 +153,6 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block, struct grub_sfs_btree *tree; int i; int next; - int prev; treeblock = grub_malloc (data->blocksize); if (!block) @@ -161,8 +164,6 @@ grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block, /* Handle this level in the btree. */ do { - prev = 0; - grub_disk_read (data->disk, next, 0, data->blocksize, treeblock); if (grub_errno) { @@ -250,7 +251,7 @@ static grub_ssize_t grub_sfs_read_file (grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { return grub_fshelp_read_file (node->data->disk, node, read_hook, pos, len, buf, grub_sfs_read_block, @@ -303,6 +304,7 @@ grub_sfs_mount (grub_disk_t disk) data->disk = disk; data->label = grub_strdup ((char *) (rootobjc->objects[0].filename)); + grub_free (rootobjc_data); return data; fail: @@ -357,21 +359,39 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir, unsigned int next = dir->block; int pos; - auto int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name, int block, - int size, int type); + auto int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name, + int block, + int size, int type, + grub_uint32_t mtime); - int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name, int block, - int size, int type) + int NESTED_FUNC_ATTR grub_sfs_create_node (const char *name, + int block, + int size, int type, + grub_uint32_t mtime) { + grub_size_t len = grub_strlen (name); + grub_uint8_t *name_u8; + int ret; node = grub_malloc (sizeof (*node)); if (!node) return 1; + name_u8 = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1); + if (!name_u8) + { + grub_free (node); + return 1; + } node->data = data; node->size = size; node->block = block; + node->mtime = mtime; - return hook (name, type, node); + *grub_latin1_to_utf8 (name_u8, (const grub_uint8_t *) name, len) = '\0'; + + ret = hook ((char *) name_u8, type, node); + grub_free (name_u8); + return ret; } objc_data = grub_malloc (data->blocksize); @@ -395,7 +415,7 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir, { struct grub_sfs_obj *obj; obj = (struct grub_sfs_obj *) ((char *) objc + pos); - char *filename = (char *) (obj->filename); + const char *filename = (const char *) obj->filename; int len; enum grub_fshelp_filetype type; unsigned int block; @@ -409,7 +429,7 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir, /* Round up to a multiple of two bytes. */ pos = ((pos + 1) >> 1) << 1; - if (grub_strlen (filename) == 0) + if (filename[0] == 0) continue; /* First check if the file was not deleted. */ @@ -429,7 +449,7 @@ grub_sfs_iterate_dir (grub_fshelp_node_t dir, if (grub_sfs_create_node (filename, block, grub_be_to_cpu32 (obj->file_dir.file.size), - type)) + type, grub_be_to_cpu32 (obj->mtime))) { grub_free (objc_data); return 1; @@ -488,7 +508,10 @@ grub_sfs_open (struct grub_file *file, const char *name) static grub_err_t grub_sfs_close (grub_file_t file) { - grub_free (file->data); + struct grub_sfs_data *data = (struct grub_sfs_data *) file->data; + + grub_free (data->label); + grub_free (data); grub_dl_unref (my_mod); @@ -528,6 +551,8 @@ grub_sfs_dir (grub_device_t device, const char *path, struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtime = node->mtime + 8 * 365 * 86400 + 86400 * 2; + info.mtimeset = 1; grub_free (node); return hook (filename, &info); } @@ -566,8 +591,15 @@ grub_sfs_label (grub_device_t device, char **label) data = grub_sfs_mount (disk); if (data) - *label = data->label; - + { + grub_size_t len = grub_strlen (data->label); + *label = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1); + if (*label) + *grub_latin1_to_utf8 ((grub_uint8_t *) *label, + (const grub_uint8_t *) data->label, + len) = '\0'; + grub_free (data->label); + } grub_free (data); return grub_errno; @@ -582,6 +614,9 @@ static struct grub_fs grub_sfs_fs = .read = grub_sfs_read, .close = grub_sfs_close, .label = grub_sfs_label, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, +#endif .next = 0 }; diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c new file mode 100644 index 000000000..d012564a8 --- /dev/null +++ b/grub-core/fs/squash4.c @@ -0,0 +1,951 @@ +/* squash4.c - SquashFS */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xz.h" +#include "xz_stream.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* + object format Pointed by + superblock RAW Fixed offset (0) + data RAW ? Fixed offset (60) + inode table Chunk superblock + dir table Chunk superblock + fragment table Chunk unk1 + unk1 RAW, Chunk superblock + unk2 RAW superblock + UID/GID Chunk exttblptr + exttblptr RAW superblock + + UID/GID table is the array ot uint32_t + unk1 contains pointer to fragment table followed by some chunk. + unk2 containts one uint64_t +*/ + +struct grub_squash_super +{ + grub_uint32_t magic; +#define SQUASH_MAGIC 0x73717368 + grub_uint32_t dummy1; + grub_uint32_t creation_time; + grub_uint32_t block_size; + grub_uint32_t dummy2; + grub_uint16_t compression; + grub_uint16_t dummy3; + grub_uint64_t dummy4; + grub_uint16_t root_ino_offset; + grub_uint32_t root_ino_chunk; + grub_uint16_t dummy5; + grub_uint64_t total_size; + grub_uint64_t exttbloffset; + grub_uint64_t dummy6; + grub_uint64_t inodeoffset; + grub_uint64_t diroffset; + grub_uint64_t unk1offset; + grub_uint64_t unk2offset; +} __attribute__ ((packed)); + +/* Chunk-based */ +struct grub_squash_inode +{ + /* Same values as direlem types. */ + grub_uint16_t type; + grub_uint16_t dummy[3]; + grub_uint32_t mtime; + grub_uint32_t dummy2; + union + { + struct { + grub_uint32_t chunk; + grub_uint32_t fragment; + grub_uint16_t offset; + grub_uint16_t dummy; + grub_uint32_t size; + grub_uint32_t block_size[0]; + } __attribute__ ((packed)) file; + struct { + grub_uint64_t chunk; + grub_uint64_t size; + grub_uint32_t dummy1[3]; + grub_uint32_t fragment; + grub_uint16_t offset; + grub_uint16_t dummy2; + grub_uint32_t dummy3; + grub_uint32_t block_size[0]; + } __attribute__ ((packed)) long_file; + struct { + grub_uint32_t chunk; + grub_uint32_t dummy; + grub_uint16_t size; + grub_uint16_t offset; + } __attribute__ ((packed)) dir; + struct { + grub_uint32_t dummy1; + grub_uint32_t size; + grub_uint32_t chunk; + grub_uint32_t dummy2; + grub_uint16_t dummy3; + grub_uint16_t offset; + } __attribute__ ((packed)) long_dir; + struct { + grub_uint32_t dummy; + grub_uint32_t namelen; + char name[0]; + } __attribute__ ((packed)) symlink; + } __attribute__ ((packed)); +} __attribute__ ((packed)); + +struct grub_squash_cache_inode +{ + struct grub_squash_inode ino; + grub_disk_addr_t ino_chunk; + grub_uint16_t ino_offset; + grub_uint32_t *block_sizes; + grub_disk_addr_t *cumulated_block_sizes; +}; + +/* Chunk-based. */ +struct grub_squash_dirent_header +{ + /* Actually the value is the number of elements - 1. */ + grub_uint32_t nelems; + grub_uint32_t ino_chunk; + grub_uint32_t dummy; +} __attribute__ ((packed)); + +struct grub_squash_dirent +{ + grub_uint16_t ino_offset; + grub_uint16_t dummy; + grub_uint16_t type; + /* Actually the value is the length of name - 1. */ + grub_uint16_t namelen; + char name[0]; +} __attribute__ ((packed)); + +enum + { + SQUASH_TYPE_DIR = 1, + SQUASH_TYPE_REGULAR = 2, + SQUASH_TYPE_SYMLINK = 3, + SQUASH_TYPE_LONG_DIR = 8, + SQUASH_TYPE_LONG_REGULAR = 9, + }; + + +struct grub_squash_frag_desc +{ + grub_uint64_t offset; + grub_uint32_t size; + grub_uint32_t dummy; +} __attribute__ ((packed)); + +enum + { + SQUASH_CHUNK_FLAGS = 0x8000, + SQUASH_CHUNK_UNCOMPRESSED = 0x8000 + }; + +enum + { + SQUASH_BLOCK_FLAGS = 0x1000000, + SQUASH_BLOCK_UNCOMPRESSED = 0x1000000 + }; + +enum + { + COMPRESSION_ZLIB = 1, + COMPRESSION_LZO = 3, + COMPRESSION_XZ = 4, + }; + + +#define SQUASH_CHUNK_SIZE 0x2000 +#define XZBUFSIZ 0x2000 + +struct grub_squash_data +{ + grub_disk_t disk; + struct grub_squash_super sb; + struct grub_squash_cache_inode ino; + grub_uint64_t fragments; + int log2_blksz; + grub_size_t blksz; + grub_ssize_t (*decompress) (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize, + struct grub_squash_data *data); + struct xz_dec *xzdec; + char *xzbuf; +}; + +struct grub_fshelp_node +{ + struct grub_squash_data *data; + struct grub_squash_inode ino; + grub_disk_addr_t ino_chunk; + grub_uint16_t ino_offset; +}; + +static grub_err_t +read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + grub_uint64_t chunk_start, grub_off_t offset) +{ + while (len > 0) + { + grub_uint64_t csize; + grub_uint16_t d; + grub_err_t err; + while (1) + { + err = grub_disk_read (data->disk, + chunk_start >> GRUB_DISK_SECTOR_BITS, + chunk_start & (GRUB_DISK_SECTOR_SIZE - 1), + sizeof (d), &d); + if (err) + return err; + if (offset < SQUASH_CHUNK_SIZE) + break; + offset -= SQUASH_CHUNK_SIZE; + chunk_start += 2 + (grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS); + } + + csize = SQUASH_CHUNK_SIZE - offset; + if (csize > len) + csize = len; + + if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED) + { + grub_disk_addr_t a = chunk_start + 2 + offset; + err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS), + a & (GRUB_DISK_SECTOR_SIZE - 1), + csize, buf); + if (err) + return err; + } + else + { + char *tmp; + grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS; + grub_disk_addr_t a = chunk_start + 2; + tmp = grub_malloc (bsize); + if (!tmp) + return grub_errno; + /* FIXME: buffer uncompressed data. */ + err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS), + a & (GRUB_DISK_SECTOR_SIZE - 1), + bsize, tmp); + if (err) + { + grub_free (tmp); + return err; + } + + if (data->decompress (tmp, bsize, offset, + buf, csize, data) < 0) + { + grub_free (tmp); + return grub_errno; + } + grub_free (tmp); + } + len -= csize; + offset += csize; + buf = (char *) buf + csize; + } + return GRUB_ERR_NONE; +} + +static grub_ssize_t +zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize, + struct grub_squash_data *data __attribute__ ((unused))) +{ + return grub_zlib_decompress (inbuf, insize, off, outbuf, outsize); +} + +static grub_ssize_t +lzo_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t len, struct grub_squash_data *data) +{ + lzo_uint usize = data->blksz; + grub_uint8_t *udata; + + udata = grub_malloc (data->blksz); + if (!udata) + return -1; + + if (lzo1x_decompress_safe ((grub_uint8_t *) inbuf, + insize, udata, &usize, NULL) != LZO_E_OK) + { + grub_free (udata); + return -1; + } + grub_memcpy (outbuf, udata + off, len); + grub_free (udata); + return len; +} + +static grub_ssize_t +xz_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t len, struct grub_squash_data *data) +{ + grub_size_t ret = 0; + grub_off_t pos = 0; + struct xz_buf buf; + + xz_dec_reset (data->xzdec); + buf.in = (grub_uint8_t *) inbuf; + buf.in_pos = 0; + buf.in_size = insize; + buf.out = (grub_uint8_t *) data->xzbuf; + buf.out_pos = 0; + buf.out_size = XZBUFSIZ; + + while (len) + { + enum xz_ret xzret; + + buf.out_pos = 0; + + xzret = xz_dec_run (data->xzdec, &buf); + + if (xzret != XZ_OK && xzret != XZ_STREAM_END) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "invalid xz chunk"); + return -1; + } + if (pos + buf.out_pos >= off) + { + grub_ssize_t outoff = pos - off; + grub_size_t l; + if (outoff >= 0) + { + l = buf.out_pos; + if (l > len) + l = len; + grub_memcpy (outbuf + outoff, buf.out, l); + } + else + { + outoff = -outoff; + l = buf.out_pos - outoff; + if (l > len) + l = len; + grub_memcpy (outbuf, buf.out + outoff, l); + } + ret += l; + len -= l; + } + pos += buf.out_pos; + if (xzret == XZ_STREAM_END) + break; + } + return ret; +} + +static struct grub_squash_data * +squash_mount (grub_disk_t disk) +{ + struct grub_squash_super sb; + grub_err_t err; + struct grub_squash_data *data; + grub_uint64_t frag; + + err = grub_disk_read (disk, 0, 0, sizeof (sb), &sb); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not a squash4"); + if (err) + return NULL; + if (sb.magic != grub_cpu_to_le32_compile_time (SQUASH_MAGIC) + || sb.block_size == 0 + || ((sb.block_size - 1) & sb.block_size)) + { + grub_error (GRUB_ERR_BAD_FS, "not squash4"); + return NULL; + } + + err = grub_disk_read (disk, + grub_le_to_cpu64 (sb.unk1offset) + >> GRUB_DISK_SECTOR_BITS, + grub_le_to_cpu64 (sb.unk1offset) + & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not a squash4"); + if (err) + return NULL; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return NULL; + data->sb = sb; + data->disk = disk; + data->fragments = grub_le_to_cpu64 (frag); + + switch (sb.compression) + { + case grub_cpu_to_le16_compile_time (COMPRESSION_ZLIB): + data->decompress = zlib_decompress; + break; + case grub_cpu_to_le16_compile_time (COMPRESSION_LZO): + data->decompress = lzo_decompress; + break; + case grub_cpu_to_le16_compile_time (COMPRESSION_XZ): + data->decompress = xz_decompress; + data->xzbuf = grub_malloc (XZBUFSIZ); + if (!data->xzbuf) + { + grub_free (data); + return NULL; + } + data->xzdec = xz_dec_init (1 << 16); + if (!data->xzdec) + { + grub_free (data->xzbuf); + grub_free (data); + return NULL; + } + break; + default: + grub_free (data); + grub_error (GRUB_ERR_BAD_FS, "unsupported compression %d", + grub_le_to_cpu16 (sb.compression)); + return NULL; + } + + data->blksz = grub_le_to_cpu32 (data->sb.block_size); + for (data->log2_blksz = 0; + (1U << data->log2_blksz) < data->blksz; + data->log2_blksz++); + + return data; +} + +static char * +grub_squash_read_symlink (grub_fshelp_node_t node) +{ + char *ret; + grub_err_t err; + ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1); + + err = read_chunk (node->data, ret, + grub_le_to_cpu32 (node->ino.symlink.namelen), + grub_le_to_cpu64 (node->data->sb.inodeoffset) + + node->ino_chunk, + node->ino_offset + (node->ino.symlink.name + - (char *) &node->ino)); + if (err) + { + grub_free (ret); + return NULL; + } + ret[grub_le_to_cpu32 (node->ino.symlink.namelen)] = 0; + return ret; +} + +static int +grub_squash_iterate_dir (grub_fshelp_node_t dir, + int NESTED_FUNC_ATTR + (*hook) (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node)) +{ + grub_uint32_t off; + grub_uint32_t endoff; + grub_uint64_t chunk; + unsigned i; + + /* FIXME: why - 3 ? */ + switch (dir->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_DIR): + off = grub_le_to_cpu16 (dir->ino.dir.offset); + endoff = grub_le_to_cpu16 (dir->ino.dir.size) + off - 3; + chunk = grub_le_to_cpu32 (dir->ino.dir.chunk); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_DIR): + off = grub_le_to_cpu16 (dir->ino.long_dir.offset); + endoff = grub_le_to_cpu16 (dir->ino.long_dir.size) + off - 3; + chunk = grub_le_to_cpu32 (dir->ino.long_dir.chunk); + break; + default: + grub_error (GRUB_ERR_BAD_FS, "unexpected ino type 0x%x", + grub_le_to_cpu16 (dir->ino.type)); + return 0; + } + + while (off < endoff) + { + struct grub_squash_dirent_header dh; + grub_err_t err; + + err = read_chunk (dir->data, &dh, sizeof (dh), + grub_le_to_cpu64 (dir->data->sb.diroffset) + + chunk, off); + if (err) + return 0; + off += sizeof (dh); + for (i = 0; i < (unsigned) grub_le_to_cpu32 (dh.nelems) + 1; i++) + { + char *buf; + int r; + struct grub_fshelp_node *node; + enum grub_fshelp_filetype filetype = GRUB_FSHELP_REG; + struct grub_squash_dirent di; + struct grub_squash_inode ino; + + err = read_chunk (dir->data, &di, sizeof (di), + grub_le_to_cpu64 (dir->data->sb.diroffset) + + chunk, off); + if (err) + return 0; + off += sizeof (di); + + err = read_chunk (dir->data, &ino, sizeof (ino), + grub_le_to_cpu64 (dir->data->sb.inodeoffset) + + grub_le_to_cpu32 (dh.ino_chunk), + grub_cpu_to_le16 (di.ino_offset)); + if (err) + return 0; + + buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2); + if (!buf) + return 0; + err = read_chunk (dir->data, buf, + grub_le_to_cpu16 (di.namelen) + 1, + grub_le_to_cpu64 (dir->data->sb.diroffset) + + chunk, off); + if (err) + return 0; + + off += grub_le_to_cpu16 (di.namelen) + 1; + buf[grub_le_to_cpu16 (di.namelen) + 1] = 0; + if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_DIR) + filetype = GRUB_FSHELP_DIR; + if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_SYMLINK) + filetype = GRUB_FSHELP_SYMLINK; + + node = grub_malloc (sizeof (*node)); + if (! node) + return 0; + *node = *dir; + node->ino = ino; + node->ino_chunk = grub_le_to_cpu32 (dh.ino_chunk); + node->ino_offset = grub_le_to_cpu16 (di.ino_offset); + + r = hook (buf, filetype, node); + + grub_free (buf); + if (r) + return r; + } + } + return 0; +} + +static grub_err_t +make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root) +{ + grub_memset (root, 0, sizeof (*root)); + root->data = data; + + return read_chunk (data, &root->ino, sizeof (root->ino), + grub_le_to_cpu64 (data->sb.inodeoffset) + + grub_le_to_cpu32 (data->sb.root_ino_chunk), + grub_cpu_to_le16 (data->sb.root_ino_offset)); +} + +static void +squash_unmount (struct grub_squash_data *data) +{ + if (data->xzdec) + xz_dec_end (data->xzdec); + grub_free (data->xzbuf); + grub_free (data->ino.cumulated_block_sizes); + grub_free (data->ino.block_sizes); + grub_free (data); +} + + +static grub_err_t +grub_squash_dir (grub_device_t device, const char *path, + int (*hook) (const char *filename, + const struct grub_dirhook_info *info)) +{ + auto int NESTED_FUNC_ATTR iterate (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node); + + int NESTED_FUNC_ATTR iterate (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node) + { + struct grub_dirhook_info info; + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; + info.mtime = grub_le_to_cpu32 (node->ino.mtime); + grub_free (node); + return hook (filename, &info); + } + + struct grub_squash_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + struct grub_fshelp_node root; + grub_err_t err; + + data = squash_mount (device->disk); + if (! data) + return grub_errno; + + err = make_root_node (data, &root); + if (err) + return err; + + grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir, + grub_squash_read_symlink, GRUB_FSHELP_DIR); + if (!grub_errno) + grub_squash_iterate_dir (fdiro, iterate); + + squash_unmount (data); + + return grub_errno; +} + +static grub_err_t +grub_squash_open (struct grub_file *file, const char *name) +{ + struct grub_squash_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + struct grub_fshelp_node root; + grub_err_t err; + + data = squash_mount (file->device->disk); + if (! data) + return grub_errno; + + err = make_root_node (data, &root); + if (err) + return err; + + grub_fshelp_find_file (name, &root, &fdiro, grub_squash_iterate_dir, + grub_squash_read_symlink, GRUB_FSHELP_REG); + if (grub_errno) + { + squash_unmount (data); + return grub_errno; + } + + file->data = data; + data->ino.ino = fdiro->ino; + data->ino.block_sizes = NULL; + data->ino.cumulated_block_sizes = NULL; + data->ino.ino_chunk = fdiro->ino_chunk; + data->ino.ino_offset = fdiro->ino_offset; + + switch (fdiro->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + file->size = grub_le_to_cpu64 (fdiro->ino.long_file.size); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + file->size = grub_le_to_cpu32 (fdiro->ino.file.size); + break; + default: + { + grub_uint16_t type = grub_le_to_cpu16 (fdiro->ino.type); + grub_free (fdiro); + squash_unmount (data); + return grub_error (GRUB_ERR_BAD_FS, "unexpected ino type 0x%x", type); + } + } + + grub_free (fdiro); + + return GRUB_ERR_NONE; +} + +static grub_ssize_t +direct_read (struct grub_squash_data *data, + struct grub_squash_cache_inode *ino, + grub_off_t off, char *buf, grub_size_t len) +{ + grub_err_t err; + grub_off_t cumulated_uncompressed_size = 0; + grub_uint64_t a = 0; + grub_size_t i; + grub_size_t origlen = len; + + switch (ino->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + a = grub_le_to_cpu64 (ino->ino.long_file.chunk); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + a = grub_le_to_cpu32 (ino->ino.file.chunk); + break; + } + + if (!ino->block_sizes) + { + grub_off_t total_size = 0; + grub_size_t total_blocks; + grub_size_t block_offset = 0; + switch (ino->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + total_size = grub_le_to_cpu64 (ino->ino.long_file.size); + block_offset = ((char *) &ino->ino.long_file.block_size + - (char *) &ino->ino); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + total_size = grub_le_to_cpu32 (ino->ino.file.size); + block_offset = ((char *) &ino->ino.file.block_size + - (char *) &ino->ino); + break; + } + total_blocks = ((total_size + data->blksz - 1) >> data->log2_blksz); + ino->block_sizes = grub_malloc (total_blocks + * sizeof (ino->block_sizes[0])); + ino->cumulated_block_sizes = grub_malloc (total_blocks + * sizeof (ino->cumulated_block_sizes[0])); + if (!ino->block_sizes || !ino->cumulated_block_sizes) + { + grub_free (ino->block_sizes); + grub_free (ino->cumulated_block_sizes); + ino->block_sizes = 0; + ino->cumulated_block_sizes = 0; + return -1; + } + err = read_chunk (data, ino->block_sizes, + total_blocks * sizeof (ino->block_sizes[0]), + grub_le_to_cpu64 (data->sb.inodeoffset) + + ino->ino_chunk, + ino->ino_offset + block_offset); + if (err) + { + grub_free (ino->block_sizes); + grub_free (ino->cumulated_block_sizes); + ino->block_sizes = 0; + ino->cumulated_block_sizes = 0; + return -1; + } + ino->cumulated_block_sizes[0] = 0; + for (i = 1; i < total_blocks; i++) + ino->cumulated_block_sizes[i] = ino->cumulated_block_sizes[i - 1] + + (grub_le_to_cpu32 (ino->block_sizes[i - 1]) & ~SQUASH_BLOCK_FLAGS); + } + + if (a == 0) + a = sizeof (struct grub_squash_super); + i = off >> data->log2_blksz; + cumulated_uncompressed_size = data->blksz * (grub_disk_addr_t) i; + while (cumulated_uncompressed_size < off + len) + { + grub_size_t boff, read; + boff = off - cumulated_uncompressed_size; + read = data->blksz - boff; + if (read > len) + read = len; + if (!(ino->block_sizes[i] + & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED))) + { + char *block; + grub_size_t csize; + csize = grub_le_to_cpu32 (ino->block_sizes[i]) & ~SQUASH_BLOCK_FLAGS; + block = grub_malloc (csize); + if (!block) + return -1; + err = grub_disk_read (data->disk, + (ino->cumulated_block_sizes[i] + a) + >> GRUB_DISK_SECTOR_BITS, + (ino->cumulated_block_sizes[i] + a) + & (GRUB_DISK_SECTOR_SIZE - 1), + csize, block); + if (err) + { + grub_free (block); + return -1; + } + if (data->decompress (block, csize, boff, buf, read, data) + != (grub_ssize_t) read) + { + grub_free (block); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk"); + return -1; + } + grub_free (block); + } + else + err = grub_disk_read (data->disk, + (ino->cumulated_block_sizes[i] + a + boff) + >> GRUB_DISK_SECTOR_BITS, + (ino->cumulated_block_sizes[i] + a + boff) + & (GRUB_DISK_SECTOR_SIZE - 1), + read, buf); + if (err) + return -1; + off += read; + len -= read; + buf += read; + cumulated_uncompressed_size += grub_le_to_cpu32 (data->sb.block_size); + i++; + } + return origlen; +} + + +static grub_ssize_t +grub_squash_read_data (struct grub_squash_data *data, + struct grub_squash_cache_inode *ino, + grub_off_t off, char *buf, grub_size_t len) +{ + grub_err_t err; + grub_uint64_t a = 0, b; + grub_uint32_t fragment = 0; + int compressed = 0; + struct grub_squash_frag_desc frag; + + switch (ino->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + a = grub_le_to_cpu64 (ino->ino.long_file.chunk); + fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + a = grub_le_to_cpu32 (ino->ino.file.chunk); + fragment = grub_le_to_cpu32 (ino->ino.file.fragment); + break; + } + + if (fragment == 0xffffffff) + return direct_read (data, ino, off, buf, len); + + err = read_chunk (data, &frag, sizeof (frag), + data->fragments, sizeof (frag) * fragment); + if (err) + return -1; + a += grub_le_to_cpu64 (frag.offset); + compressed = !(frag.size & SQUASH_BLOCK_UNCOMPRESSED); + if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR)) + b = grub_le_to_cpu64 (ino->ino.long_file.offset) + off; + else + b = grub_le_to_cpu32 (ino->ino.file.offset) + off; + + /* FIXME: cache uncompressed chunks. */ + if (compressed) + { + char *block; + block = grub_malloc (frag.size); + if (!block) + return -1; + err = grub_disk_read (data->disk, + a >> GRUB_DISK_SECTOR_BITS, + a & (GRUB_DISK_SECTOR_SIZE - 1), + frag.size, block); + if (err) + { + grub_free (block); + return -1; + } + if (data->decompress (block, frag.size, b, buf, len, data) + != (grub_ssize_t) len) + { + grub_free (block); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk"); + return -1; + } + grub_free (block); + } + else + { + err = grub_disk_read (data->disk, (a + b) >> GRUB_DISK_SECTOR_BITS, + (a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf); + if (err) + return -1; + } + return len; +} + +static grub_ssize_t +grub_squash_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_squash_data *data = file->data; + + return grub_squash_read_data (data, &data->ino, + file->offset, buf, len); +} + +static grub_err_t +grub_squash_close (grub_file_t file) +{ + squash_unmount (file->data); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_squash_mtime (grub_device_t dev, grub_int32_t *tm) +{ + struct grub_squash_data *data = 0; + + data = squash_mount (dev->disk); + if (! data) + return grub_errno; + *tm = grub_le_to_cpu32 (data->sb.creation_time); + squash_unmount (data); + return GRUB_ERR_NONE; +} + +static struct grub_fs grub_squash_fs = + { + .name = "squash4", + .dir = grub_squash_dir, + .open = grub_squash_open, + .read = grub_squash_read, + .close = grub_squash_close, + .mtime = grub_squash_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, +#endif + .next = 0 + }; + +GRUB_MOD_INIT(squash4) +{ + grub_fs_register (&grub_squash_fs); +} + +GRUB_MOD_FINI(squash4) +{ + grub_fs_unregister (&grub_squash_fs); +} + diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c index ad109bed9..537bb37f0 100644 --- a/grub-core/fs/udf.c +++ b/grub-core/fs/udf.c @@ -26,6 +26,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_UDF_MAX_PDS 2 #define GRUB_UDF_MAX_PMS 6 @@ -34,9 +37,6 @@ #define U32 grub_le_to_cpu32 #define U64 grub_le_to_cpu64 -#define GRUB_UDF_LOG2_BLKSZ 2 -#define GRUB_UDF_BLKSZ 2048 - #define GRUB_UDF_TAG_IDENT_PVD 0x0001 #define GRUB_UDF_TAG_IDENT_AVDP 0x0002 #define GRUB_UDF_TAG_IDENT_VDP 0x0003 @@ -317,7 +317,7 @@ struct grub_udf_partmap grub_uint8_t ident[62]; } type2; }; -}; +} __attribute__ ((packed)); struct grub_udf_lvd { @@ -336,6 +336,13 @@ struct grub_udf_lvd grub_uint8_t part_maps[1608]; } __attribute__ ((packed)); +struct grub_udf_aed +{ + struct grub_udf_tag tag; + grub_uint32_t prev_ae; + grub_uint32_t ae_len; +} __attribute__ ((packed)); + struct grub_udf_data { grub_disk_t disk; @@ -343,7 +350,7 @@ struct grub_udf_data struct grub_udf_pd pds[GRUB_UDF_MAX_PDS]; struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS]; struct grub_udf_long_ad root_icb; - int npd, npm; + int npd, npm, lbshift; }; struct grub_fshelp_node @@ -389,7 +396,7 @@ grub_udf_read_icb (struct grub_udf_data *data, if (grub_errno) return grub_errno; - if (grub_disk_read (data->disk, block << GRUB_UDF_LOG2_BLKSZ, 0, + if (grub_disk_read (data->disk, block << data->lbshift, 0, sizeof (struct grub_udf_file_entry), &node->fe)) return grub_errno; @@ -406,19 +413,26 @@ grub_udf_read_icb (struct grub_udf_data *data, static grub_disk_addr_t grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { + char *buf = NULL; char *ptr; - int len; + grub_ssize_t len; grub_disk_addr_t filebytes; - if (U16 (node->fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE) + switch (U16 (node->fe.tag.tag_ident)) { + case GRUB_UDF_TAG_IDENT_FE: ptr = (char *) &node->fe.ext_attr[0] + U32 (node->fe.ext_attr_length); len = U32 (node->fe.alloc_descs_length); - } - else - { + break; + + case GRUB_UDF_TAG_IDENT_EFE: ptr = (char *) &node->efe.ext_attr[0] + U32 (node->efe.ext_attr_length); len = U32 (node->efe.alloc_descs_length); + break; + + default: + grub_error (GRUB_ERR_BAD_FS, "invalid file entry"); + return 0; } if ((U16 (node->fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK) @@ -426,43 +440,114 @@ grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) { struct grub_udf_short_ad *ad = (struct grub_udf_short_ad *) ptr; - len /= sizeof (struct grub_udf_short_ad); - filebytes = fileblock * GRUB_UDF_BLKSZ; - while (len > 0) + filebytes = fileblock * U32 (node->data->lvd.bsize); + while (len >= (grub_ssize_t) sizeof (struct grub_udf_short_ad)) { - if (filebytes < U32 (ad->length)) - return ((U32 (ad->position) & GRUB_UDF_EXT_MASK) ? 0 : - (grub_udf_get_block (node->data, - node->part_ref, - ad->position) - + (filebytes / GRUB_UDF_BLKSZ))); + grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff; + grub_uint32_t adtype = U32 (ad->length) >> 30; + if (adtype == 3) + { + struct grub_udf_aed *extension; + grub_disk_addr_t sec = grub_udf_get_block(node->data, + node->part_ref, + ad->position); + if (!buf) + { + buf = grub_malloc (U32 (node->data->lvd.bsize)); + if (!buf) + return 0; + } + if (grub_disk_read (node->data->disk, sec << node->data->lbshift, + 0, adlen, buf)) + goto fail; - filebytes -= U32 (ad->length); + extension = (struct grub_udf_aed *) buf; + if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED) + { + grub_error (GRUB_ERR_BAD_FS, "invalid aed tag"); + goto fail; + } + + len = U32 (extension->ae_len); + ad = (struct grub_udf_short_ad *) + (buf + sizeof (struct grub_udf_aed)); + continue; + } + + if (filebytes < adlen) + { + grub_uint32_t ad_pos = ad->position; + grub_free (buf); + return ((U32 (ad_pos) & GRUB_UDF_EXT_MASK) ? 0 : + (grub_udf_get_block (node->data, node->part_ref, ad_pos) + + (filebytes >> (GRUB_DISK_SECTOR_BITS + + node->data->lbshift)))); + } + + filebytes -= adlen; ad++; - len--; + len -= sizeof (struct grub_udf_short_ad); } } else { struct grub_udf_long_ad *ad = (struct grub_udf_long_ad *) ptr; - len /= sizeof (struct grub_udf_long_ad); - filebytes = fileblock * GRUB_UDF_BLKSZ; - while (len > 0) + filebytes = fileblock * U32 (node->data->lvd.bsize); + while (len >= (grub_ssize_t) sizeof (struct grub_udf_long_ad)) { - if (filebytes < U32 (ad->length)) - return ((U32 (ad->block.block_num) & GRUB_UDF_EXT_MASK) ? 0 : - (grub_udf_get_block (node->data, - ad->block.part_ref, - ad->block.block_num) - + (filebytes / GRUB_UDF_BLKSZ))); + grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff; + grub_uint32_t adtype = U32 (ad->length) >> 30; + if (adtype == 3) + { + struct grub_udf_aed *extension; + grub_disk_addr_t sec = grub_udf_get_block(node->data, + ad->block.part_ref, + ad->block.block_num); + if (!buf) + { + buf = grub_malloc (U32 (node->data->lvd.bsize)); + if (!buf) + return 0; + } + if (grub_disk_read (node->data->disk, sec << node->data->lbshift, + 0, adlen, buf)) + goto fail; - filebytes -= U32 (ad->length); + extension = (struct grub_udf_aed *) buf; + if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED) + { + grub_error (GRUB_ERR_BAD_FS, "invalid aed tag"); + goto fail; + } + + len = U32 (extension->ae_len); + ad = (struct grub_udf_long_ad *) + (buf + sizeof (struct grub_udf_aed)); + continue; + } + + if (filebytes < adlen) + { + grub_uint32_t ad_block_num = ad->block.block_num; + grub_uint32_t ad_part_ref = ad->block.part_ref; + grub_free (buf); + return ((U32 (ad_block_num) & GRUB_UDF_EXT_MASK) ? 0 : + (grub_udf_get_block (node->data, ad_part_ref, + ad_block_num) + + (filebytes >> (GRUB_DISK_SECTOR_BITS + + node->data->lbshift)))); + } + + filebytes -= adlen; ad++; - len--; + len -= sizeof (struct grub_udf_long_ad); } } +fail: + grub_free (buf); + return 0; } @@ -471,7 +556,7 @@ grub_udf_read_file (grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { switch (U16 (node->fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK) { @@ -496,21 +581,21 @@ grub_udf_read_file (grub_fshelp_node_t node, } return grub_fshelp_read_file (node->data->disk, node, read_hook, - pos, len, buf, grub_udf_read_block, - U64 (node->fe.file_size), - GRUB_UDF_LOG2_BLKSZ); + pos, len, buf, grub_udf_read_block, + U64 (node->fe.file_size), + node->data->lbshift); } -static int sblocklist[] = { 256, 512, 0 }; +static unsigned sblocklist[] = { 256, 512, 0 }; static struct grub_udf_data * grub_udf_mount (grub_disk_t disk) { struct grub_udf_data *data = 0; struct grub_udf_fileset root_fs; - int *sblklist = sblocklist; - grub_uint32_t block; - int i; + unsigned *sblklist; + grub_uint32_t block, vblock; + int i, lbshift; data = grub_malloc (sizeof (struct grub_udf_data)); if (!data) @@ -518,12 +603,48 @@ grub_udf_mount (grub_disk_t disk) data->disk = disk; + /* Search for Anchor Volume Descriptor Pointer (AVDP) + * and determine logical block size. */ + block = 0; + for (lbshift = 0; lbshift < 4; lbshift++) + { + for (sblklist = sblocklist; *sblklist; sblklist++) + { + struct grub_udf_avdp avdp; + + if (grub_disk_read (disk, *sblklist << lbshift, 0, + sizeof (struct grub_udf_avdp), &avdp)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + if (U16 (avdp.tag.tag_ident) == GRUB_UDF_TAG_IDENT_AVDP && + U32 (avdp.tag.tag_location) == *sblklist) + { + block = U32 (avdp.vds.start); + break; + } + } + + if (block) + break; + } + + if (!block) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + data->lbshift = lbshift; + /* Search for Volume Recognition Sequence (VRS). */ - for (block = 16;; block++) + for (vblock = (32767 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1;; + vblock += (2047 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1) { struct grub_udf_vrs vrs; - if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, + if (grub_disk_read (disk, vblock << lbshift, 0, sizeof (struct grub_udf_vrs), &vrs)) { grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); @@ -545,39 +666,13 @@ grub_udf_mount (grub_disk_t disk) } } - /* Search for Anchor Volume Descriptor Pointer (AVDP). */ - while (1) - { - struct grub_udf_avdp avdp; - - if (grub_disk_read (disk, *sblklist << GRUB_UDF_LOG2_BLKSZ, 0, - sizeof (struct grub_udf_avdp), &avdp)) - { - grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); - goto fail; - } - - if (U16 (avdp.tag.tag_ident) == GRUB_UDF_TAG_IDENT_AVDP) - { - block = U32 (avdp.vds.start); - break; - } - - sblklist++; - if (*sblklist == 0) - { - grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); - goto fail; - } - } - data->npd = data->npm = 0; /* Locate Partition Descriptor (PD) and Logical Volume Descriptor (LVD). */ while (1) { struct grub_udf_tag tag; - if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, + if (grub_disk_read (disk, block << lbshift, 0, sizeof (struct grub_udf_tag), &tag)) { grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); @@ -593,7 +688,7 @@ grub_udf_mount (grub_disk_t disk) goto fail; } - if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, + if (grub_disk_read (disk, block << lbshift, 0, sizeof (struct grub_udf_pd), &data->pds[data->npd])) { @@ -609,7 +704,7 @@ grub_udf_mount (grub_disk_t disk) struct grub_udf_partmap *ppm; - if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, + if (grub_disk_read (disk, block << lbshift, 0, sizeof (struct grub_udf_lvd), &data->lvd)) { @@ -673,7 +768,7 @@ grub_udf_mount (grub_disk_t disk) if (grub_errno) goto fail; - if (grub_disk_read (disk, block << GRUB_UDF_LOG2_BLKSZ, 0, + if (grub_disk_read (disk, block << lbshift, 0, sizeof (struct grub_udf_fileset), &root_fs)) { grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); @@ -695,6 +790,43 @@ fail: return 0; } +static char * +read_string (grub_uint8_t *raw, grub_size_t sz) +{ + grub_uint16_t *utf16 = NULL; + char *ret; + grub_size_t utf16len = 0; + + if (raw[0] != 8 && raw[0] != 16) + return NULL; + + if (raw[0] == 8) + { + unsigned i; + utf16len = sz - 1; + utf16 = grub_malloc (utf16len * sizeof (utf16[0])); + if (!utf16) + return NULL; + for (i = 0; i < utf16len; i++) + utf16[i] = raw[i + 1]; + } + if (raw[0] == 16) + { + unsigned i; + utf16len = (sz - 1) / 2; + utf16 = grub_malloc (utf16len * sizeof (utf16[0])); + if (!utf16) + return NULL; + for (i = 0; i < utf16len; i++) + utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2]; + } + ret = grub_malloc (utf16len * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (ret) + *grub_utf16_to_utf8 ((grub_uint8_t *) ret, utf16, utf16len) = '\0'; + grub_free (utf16); + return ret; +} + static int grub_udf_iterate_dir (grub_fshelp_node_t dir, int NESTED_FUNC_ATTR @@ -704,7 +836,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir, { grub_fshelp_node_t child; struct grub_udf_file_ident dirent; - grub_uint32_t offset = 0; + grub_off_t offset = 0; child = grub_malloc (sizeof (struct grub_fshelp_node)); if (!child) @@ -729,57 +861,49 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir, return 0; } - child = grub_malloc (sizeof (struct grub_fshelp_node)); - if (!child) - return 0; - - if (grub_udf_read_icb (dir->data, &dirent.icb, child)) - return 0; - offset += sizeof (dirent) + U16 (dirent.imp_use_length); - if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT) + if (!(dirent.characteristics & GRUB_UDF_FID_CHAR_DELETED)) { - /* This is the parent directory. */ - if (hook ("..", GRUB_FSHELP_DIR, child)) - return 1; - } - else - { - enum grub_fshelp_filetype type; - grub_uint8_t raw[dirent.file_ident_length]; - grub_uint16_t utf16[dirent.file_ident_length - 1]; - grub_uint8_t filename[dirent.file_ident_length * 2]; - grub_size_t utf16len = 0; - - type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ? - (GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG)); - - if ((grub_udf_read_file (dir, 0, offset, - dirent.file_ident_length, - (char *) raw)) - != dirent.file_ident_length) + child = grub_malloc (sizeof (struct grub_fshelp_node)); + if (!child) return 0; - if (raw[0] == 8) + if (grub_udf_read_icb (dir->data, &dirent.icb, child)) + return 0; + + if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT) { - unsigned i; - utf16len = dirent.file_ident_length - 1; - for (i = 0; i < utf16len; i++) - utf16[i] = raw[i + 1]; + /* This is the parent directory. */ + if (hook ("..", GRUB_FSHELP_DIR, child)) + return 1; } - if (raw[0] == 16) + else { - unsigned i; - utf16len = (dirent.file_ident_length - 1) / 2; - for (i = 0; i < utf16len; i++) - utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2]; - } - if (raw[0] == 8 || raw[0] == 16) - { - *grub_utf16_to_utf8 (filename, utf16, utf16len) = '\0'; - - if (hook ((char *) filename, type, child)) - return 1; + enum grub_fshelp_filetype type; + char *filename; + grub_uint8_t raw[dirent.file_ident_length]; + + type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ? + (GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG)); + if (child->fe.icbtag.file_type == GRUB_UDF_ICBTAG_TYPE_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + + if ((grub_udf_read_file (dir, 0, offset, + dirent.file_ident_length, + (char *) raw)) + != dirent.file_ident_length) + return 0; + + filename = read_string (raw, dirent.file_ident_length); + if (!filename) + grub_print_error (); + + if (filename && hook (filename, type, child)) + { + grub_free (filename); + return 1; + } + grub_free (filename); } } @@ -790,6 +914,25 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir, return 0; } +static char * +grub_ufs_read_symlink (grub_fshelp_node_t node) +{ + grub_size_t sz = U64 (node->fe.file_size); + grub_uint8_t *raw; + char *ret; + + if (sz < 4) + return NULL; + raw = grub_malloc (sz - 4); + if (!raw) + return NULL; + if (grub_udf_read_file (node, NULL, 4, sz - 4, (char *) raw) < 0) + return NULL; + ret = read_string (raw, sz - 4); + grub_free (raw); + return ret; +} + static grub_err_t grub_udf_dir (grub_device_t device, const char *path, int (*hook) (const char *filename, @@ -808,8 +951,36 @@ grub_udf_dir (grub_device_t device, const char *path, grub_fshelp_node_t node) { struct grub_dirhook_info info; + const struct grub_udf_timestamp *tstamp = NULL; grub_memset (&info, 0, sizeof (info)); info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + if (U16 (node->fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE) + tstamp = &node->fe.modification_time; + else if (U16 (node->fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_EFE) + tstamp = &node->efe.modification_time; + + if (tstamp && (U16 (tstamp->type_and_timezone) & 0xf000) == 0x1000) + { + grub_int16_t tz; + struct grub_datetime datetime; + + datetime.year = U16 (tstamp->year); + datetime.month = tstamp->month; + datetime.day = tstamp->day; + datetime.hour = tstamp->hour; + datetime.minute = tstamp->minute; + datetime.second = tstamp->second; + + tz = U16 (tstamp->type_and_timezone) & 0xfff; + if (tz & 0x800) + tz |= 0xf000; + if (tz == -2047) + tz = 0; + + info.mtimeset = !!grub_datetime2unixtime (&datetime, &info.mtime); + + info.mtime -= 60 * tz; + } grub_free (node); return hook (filename, &info); } @@ -825,7 +996,8 @@ grub_udf_dir (grub_device_t device, const char *path, if (grub_fshelp_find_file (path, &rootnode, &foundnode, - grub_udf_iterate_dir, 0, GRUB_FSHELP_DIR)) + grub_udf_iterate_dir, grub_ufs_read_symlink, + GRUB_FSHELP_DIR)) goto fail; grub_udf_iterate_dir (foundnode, iterate); @@ -859,7 +1031,8 @@ grub_udf_open (struct grub_file *file, const char *name) if (grub_fshelp_find_file (name, &rootnode, &foundnode, - grub_udf_iterate_dir, 0, GRUB_FSHELP_REG)) + grub_udf_iterate_dir, grub_ufs_read_symlink, + GRUB_FSHELP_REG)) goto fail; file->data = foundnode; @@ -908,7 +1081,7 @@ grub_udf_label (grub_device_t device, char **label) if (data) { - *label = grub_strdup ((char *) &data->lvd.ident[1]); + *label = read_string (data->lvd.ident, sizeof (data->lvd.ident)); grub_free (data); } else diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c index 40cf068e6..cd2994895 100644 --- a/grub-core/fs/ufs.c +++ b/grub-core/fs/ufs.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #ifdef MODE_UFS2 #define GRUB_UFS_MAGIC 0x19540119 #else @@ -48,6 +50,7 @@ /* Calculate in which group the inode can be found. */ #define UFS_BLKSZ(sblock) (grub_le_to_cpu32 (sblock->bsize)) +#define UFS_LOG_BLKSZ(sblock) (data->log2_blksz) #define INODE(data,field) data->inode. field #ifdef MODE_UFS2 @@ -212,6 +215,7 @@ struct grub_ufs_data struct grub_ufs_inode inode; int ino; int linknest; + int log2_blksz; }; static grub_dl_t my_mod; @@ -283,26 +287,28 @@ static grub_ssize_t grub_ufs_read_file (struct grub_ufs_data *data, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { struct grub_ufs_sblock *sblock = &data->sblock; - int i; - int blockcnt; + grub_off_t i; + grub_off_t blockcnt; /* Adjust len so it we can't read past the end of the file. */ if (len + pos > INODE_SIZE (data)) len = INODE_SIZE (data) - pos; - blockcnt = (len + pos + UFS_BLKSZ (sblock) - 1) / UFS_BLKSZ (sblock); + blockcnt = (len + pos + UFS_BLKSZ (sblock) - 1) >> UFS_LOG_BLKSZ (sblock); - for (i = pos / UFS_BLKSZ (sblock); i < blockcnt; i++) + for (i = pos >> UFS_LOG_BLKSZ (sblock); i < blockcnt; i++) { - int blknr; - int blockoff = pos % UFS_BLKSZ (sblock); - int blockend = UFS_BLKSZ (sblock); + grub_disk_addr_t blknr; + grub_off_t blockoff; + grub_off_t blockend = UFS_BLKSZ (sblock); int skipfirst = 0; + blockoff = pos & (UFS_BLKSZ (sblock) - 1); + blknr = grub_ufs_get_file_block (data, i); if (grub_errno) return -1; @@ -310,14 +316,14 @@ grub_ufs_read_file (struct grub_ufs_data *data, /* Last block. */ if (i == blockcnt - 1) { - blockend = (len + pos) % UFS_BLKSZ (sblock); + blockend = (len + pos) & (UFS_BLKSZ (sblock) - 1); if (!blockend) blockend = UFS_BLKSZ (sblock); } /* First block. */ - if (i == (pos / (int) UFS_BLKSZ (sblock))) + if (i == (pos >> UFS_LOG_BLKSZ (sblock))) { skipfirst = blockoff; blockend -= skipfirst; @@ -389,21 +395,16 @@ grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode) static grub_err_t grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) { - char symlink[INODE_SIZE (data)]; + char symlink[INODE_SIZE (data) + 1]; if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT) return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks"); - if (INODE_NBLOCKS (data) == 0) + if (INODE_SIZE (data) <= sizeof (data->inode.symlink)) grub_strcpy (symlink, (char *) INODE (data, symlink)); else - { - grub_disk_read (data->disk, - (INODE_DIRBLOCKS (data, 0) - << grub_le_to_cpu32 (data->sblock.log2_blksz)), - 0, INODE_SIZE (data), symlink); - symlink[INODE_SIZE (data)] = '\0'; - } + grub_ufs_read_file (data, 0, 0, INODE_SIZE (data), symlink); + symlink[INODE_SIZE (data)] = '\0'; /* The symlink is an absolute path, go back to the root inode. */ if (symlink[0] == '/') @@ -512,7 +513,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path) pos += grub_le_to_cpu16 (dirent.direntlen); } while (pos < INODE_SIZE (data)); - grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path); return grub_errno; } @@ -536,8 +537,16 @@ grub_ufs_mount (grub_disk_t disk) if (grub_errno) goto fail; - if (grub_le_to_cpu32 (data->sblock.magic) == GRUB_UFS_MAGIC) + /* No need to byteswap bsize in this check. It works the same on both + endiannesses. */ + if (grub_le_to_cpu32 (data->sblock.magic) == GRUB_UFS_MAGIC + && data->sblock.bsize != 0 + && ((data->sblock.bsize & (data->sblock.bsize - 1)) == 0)) { + for (data->log2_blksz = 0; + (1U << data->log2_blksz) < grub_le_to_cpu32 (data->sblock.bsize); + data->log2_blksz++); + data->disk = disk; data->linknest = 0; return data; @@ -568,7 +577,6 @@ grub_ufs_dir (grub_device_t device, const char *path, const struct grub_dirhook_info *info)) { struct grub_ufs_data *data; - struct grub_ufs_sblock *sblock; unsigned int pos = 0; data = grub_ufs_mount (device->disk); @@ -579,8 +587,6 @@ grub_ufs_dir (grub_device_t device, const char *path, if (grub_errno) return grub_errno; - sblock = &data->sblock; - if (!path || path[0] != '/') { grub_error (GRUB_ERR_BAD_FILENAME, "bad filename"); @@ -699,8 +705,6 @@ grub_ufs_close (grub_file_t file) return GRUB_ERR_NONE; } - -#ifdef MODE_UFS2 static grub_err_t grub_ufs_label (grub_device_t device, char **label) { @@ -720,7 +724,6 @@ grub_ufs_label (grub_device_t device, char **label) return grub_errno; } -#endif static grub_err_t grub_ufs_uuid (grub_device_t device, char **uuid) @@ -758,11 +761,13 @@ grub_ufs_mtime (grub_device_t device, grub_int32_t *tm) if (!data) *tm = 0; else + { + *tm = grub_le_to_cpu32 (data->sblock.mtime); #ifdef MODE_UFS2 - *tm = grub_le_to_cpu64 (data->sblock.mtime2); -#else - *tm = grub_le_to_cpu32 (data->sblock.mtime); + if (*tm < (grub_int64_t) grub_le_to_cpu64 (data->sblock.mtime2)) + *tm = grub_le_to_cpu64 (data->sblock.mtime2); #endif + } grub_dl_unref (my_mod); @@ -784,9 +789,7 @@ static struct grub_fs grub_ufs_fs = .open = grub_ufs_open, .read = grub_ufs_read, .close = grub_ufs_close, -#ifdef MODE_UFS2 .label = grub_ufs_label, -#endif .uuid = grub_ufs_uuid, .mtime = grub_ufs_mtime, .next = 0 diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c index 9dffe31d1..fbadc8fa5 100644 --- a/grub-core/fs/xfs.c +++ b/grub-core/fs/xfs.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define XFS_INODE_EXTENTS 9 #define XFS_INODE_FORMAT_INO 1 @@ -98,18 +100,29 @@ struct grub_xfs_btree_root grub_uint64_t keys[1]; } __attribute__ ((packed)); +struct grub_xfs_time +{ + grub_uint32_t sec; + grub_uint32_t nanosec; +} __attribute__ ((packed)); + struct grub_xfs_inode { grub_uint8_t magic[2]; grub_uint16_t mode; grub_uint8_t version; grub_uint8_t format; - grub_uint8_t unused2[50]; + grub_uint8_t unused2[26]; + struct grub_xfs_time atime; + struct grub_xfs_time mtime; + struct grub_xfs_time ctime; grub_uint64_t size; grub_uint64_t nblocks; grub_uint32_t extsize; grub_uint32_t nextents; - grub_uint8_t unused3[20]; + grub_uint16_t unused3; + grub_uint8_t fork_offset; + grub_uint8_t unused4[17]; union { char raw[156]; @@ -143,7 +156,7 @@ struct grub_xfs_data grub_disk_t disk; int pos; int bsize; - int agsize; + grub_uint32_t agsize; struct grub_fshelp_node diropen; }; @@ -157,33 +170,67 @@ static grub_dl_t my_mod; #define FILETYPE_INO_DIRECTORY 0040000 #define FILETYPE_INO_SYMLINK 0120000 -#define GRUB_XFS_INO_AGBITS(data) \ - ((data)->sblock.log2_agblk + (data)->sblock.log2_inop) -#define GRUB_XFS_INO_INOINAG(data, ino) \ - (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1)) -#define GRUB_XFS_INO_AG(data,ino) \ - (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data)) +static inline int +GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data) +{ + return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop); +} -#define GRUB_XFS_FSB_TO_BLOCK(data, fsb) \ - (((fsb) >> (data)->sblock.log2_agblk) * (data)->agsize \ - + ((fsb) & ((1LL << (data)->sblock.log2_agblk) - 1))) +static inline grub_uint64_t +GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data, + grub_uint64_t ino) +{ + return (grub_be_to_cpu64 (ino) & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1)); +} -#define GRUB_XFS_EXTENT_OFFSET(exts,ex) \ - ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 \ - | grub_be_to_cpu32 (exts[ex][1]) >> 9) +static inline grub_uint64_t +GRUB_XFS_INO_AG (struct grub_xfs_data *data, + grub_uint64_t ino) +{ + return (grub_be_to_cpu64 (ino) >> GRUB_XFS_INO_AGBITS (data)); +} -#define GRUB_XFS_EXTENT_BLOCK(exts,ex) \ - ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) \ - & (0x1ff)) << 43 \ - | (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 \ - | grub_be_to_cpu32 (exts[ex][3]) >> 21) +static inline grub_disk_addr_t +GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb) +{ + return ((fsb >> data->sblock.log2_agblk) * data->agsize + + (fsb & ((1LL << data->sblock.log2_agblk) - 1))); +} -#define GRUB_XFS_EXTENT_SIZE(exts,ex) \ - (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1)) +static inline grub_uint64_t +GRUB_XFS_EXTENT_OFFSET (grub_xfs_extent *exts, int ex) +{ + return ((grub_be_to_cpu32 (exts[ex][0]) & ~(1 << 31)) << 23 + | grub_be_to_cpu32 (exts[ex][1]) >> 9); +} + +static inline grub_uint64_t +GRUB_XFS_EXTENT_BLOCK (grub_xfs_extent *exts, int ex) +{ + return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex][1]) + & (0x1ff)) << 43 + | (grub_uint64_t) grub_be_to_cpu32 (exts[ex][2]) << 11 + | grub_be_to_cpu32 (exts[ex][3]) >> 21); +} + +static inline grub_uint64_t +GRUB_XFS_EXTENT_SIZE (grub_xfs_extent *exts, int ex) +{ + return (grub_be_to_cpu32 (exts[ex][3]) & ((1 << 20) - 1)); +} + +static inline int +GRUB_XFS_ROUND_TO_DIRENT (int pos) +{ + return ((((pos) + 8 - 1) / 8) * 8); +} + +static inline int +GRUB_XFS_NEXT_DIRENT (int pos, int len) +{ + return (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2); +} -#define GRUB_XFS_ROUND_TO_DIRENT(pos) ((((pos) + 8 - 1) / 8) * 8) -#define GRUB_XFS_NEXT_DIRENT(pos,len) \ - (pos) + GRUB_XFS_ROUND_TO_DIRENT (8 + 1 + len + 2) static inline grub_uint64_t grub_xfs_inode_block (struct grub_xfs_data *data, @@ -239,13 +286,23 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) if (node->inode.format == XFS_INODE_FORMAT_BTREE) { grub_uint64_t *keys; + int recoffset; - leaf = grub_malloc (node->data->sblock.bsize); + leaf = grub_malloc (node->data->bsize); if (leaf == 0) return 0; nrec = grub_be_to_cpu16 (node->inode.data.btree.numrecs); keys = &node->inode.data.btree.keys[0]; + if (node->inode.fork_offset) + recoffset = (node->inode.fork_offset + - ((char *) &node->inode.data.btree.keys - (char *) &node->inode)) + / (2 * sizeof (grub_uint64_t)); + else + recoffset = ((1 << node->data->sblock.log2_inode) + - ((char *) &node->inode.data.btree.keys + - (char *) &node->inode)) + / (2 * sizeof (grub_uint64_t)); do { int i; @@ -262,12 +319,9 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) grub_free (leaf); return 0; } - if (grub_disk_read (node->data->disk, - grub_be_to_cpu64 (keys[i - 1 + nrec]) - << (node->data->sblock.log2_bsize - - GRUB_DISK_SECTOR_BITS), - 0, node->data->sblock.bsize, leaf)) + GRUB_XFS_FSB_TO_BLOCK (node->data, grub_be_to_cpu64 (keys[i - 1 + recoffset])) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS), + 0, node->data->bsize, leaf)) return 0; if (grub_strncmp ((char *) leaf->magic, "BMAP", 4)) @@ -279,7 +333,11 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) nrec = grub_be_to_cpu16 (leaf->numrecs); keys = &leaf->keys[0]; - } while (leaf->level); + recoffset = ((node->data->bsize - ((char *) &leaf->keys + - (char *) leaf)) + / (2 * sizeof (grub_uint64_t))); + } + while (leaf->level); exts = (grub_xfs_extent *) keys; } else if (node->inode.format == XFS_INODE_FORMAT_EXT) @@ -313,8 +371,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) } } - if (leaf) - grub_free (leaf); + grub_free (leaf); return GRUB_XFS_FSB_TO_BLOCK(node->data, ret); } @@ -326,7 +383,7 @@ static grub_ssize_t grub_xfs_read_file (grub_fshelp_node_t node, void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, unsigned offset, unsigned length), - int pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { return grub_fshelp_read_file (node->data->disk, node, read_hook, pos, len, buf, grub_xfs_read_block, @@ -394,9 +451,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, grub_fshelp_node_t node)) { struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; - auto int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, char *filename); + auto int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, const char *filename); - int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, char *filename) + int NESTED_FUNC_ATTR call_hook (grub_uint64_t ino, const char *filename) { struct grub_fshelp_node *fdiro; @@ -451,18 +508,27 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, for (i = 0; i < diro->inode.data.dir.dirhead.count; i++) { grub_uint64_t ino; - void *inopos = (((char *) de) + grub_uint8_t *inopos = (((grub_uint8_t *) de) + sizeof (struct grub_xfs_dir_entry) + de->len - 1); char name[de->len + 1]; + /* inopos might be unaligned. */ if (smallino) - { - ino = grub_be_to_cpu32 (*(grub_uint32_t *) inopos); - ino = grub_cpu_to_be64 (ino); - } + ino = (((grub_uint32_t) inopos[0]) << 24) + | (((grub_uint32_t) inopos[1]) << 16) + | (((grub_uint32_t) inopos[2]) << 8) + | (((grub_uint32_t) inopos[3]) << 0); else - ino = *(grub_uint64_t *) inopos; + ino = (((grub_uint64_t) inopos[0]) << 56) + | (((grub_uint64_t) inopos[1]) << 48) + | (((grub_uint64_t) inopos[2]) << 40) + | (((grub_uint64_t) inopos[3]) << 32) + | (((grub_uint64_t) inopos[4]) << 24) + | (((grub_uint64_t) inopos[5]) << 16) + | (((grub_uint64_t) inopos[6]) << 8) + | (((grub_uint64_t) inopos[7]) << 0); + ino = grub_cpu_to_be64 (ino); grub_memcpy (name, de->name, de->len); name[de->len] = '\0'; @@ -523,18 +589,18 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, - (int) sizeof (struct grub_xfs_dir2_entry))) { struct grub_xfs_dir2_entry *direntry; - grub_uint16_t *freetag; + grub_uint8_t *freetag; char *filename; direntry = (struct grub_xfs_dir2_entry *) &dirblock[pos]; - freetag = (grub_uint16_t *) direntry; + freetag = (grub_uint8_t *) direntry; - if (*freetag == 0XFFFF) + if (grub_get_unaligned16 (freetag) == 0XFFFF) { - grub_uint16_t *skip = (grub_uint16_t *) (freetag + 1); + grub_uint8_t *skip = (freetag + sizeof (grub_uint16_t)); /* This entry is not used, go to the next one. */ - pos += grub_be_to_cpu16 (*skip); + pos += grub_be_to_cpu16 (grub_get_unaligned16 (skip)); continue; } @@ -643,6 +709,11 @@ grub_xfs_dir (grub_device_t device, const char *path, { struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); + if (node->inode_read) + { + info.mtimeset = 1; + info.mtime = grub_be_to_cpu32 (node->inode.mtime.sec); + } info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); grub_free (node); return hook (filename, &info); @@ -700,10 +771,13 @@ grub_xfs_open (struct grub_file *file, const char *name) } if (fdiro != &data->diropen) - grub_memcpy (&data->diropen, fdiro, - sizeof (struct grub_fshelp_node) - - sizeof (struct grub_xfs_inode) - + (1 << data->sblock.log2_inode)); + { + grub_memcpy (&data->diropen, fdiro, + sizeof (struct grub_fshelp_node) + - sizeof (struct grub_xfs_inode) + + (1 << data->sblock.log2_inode)); + grub_free (fdiro); + } file->size = grub_be_to_cpu64 (data->diropen.inode.size); file->data = data; @@ -808,6 +882,9 @@ static struct grub_fs grub_xfs_fs = .close = grub_xfs_close, .label = grub_xfs_label, .uuid = grub_xfs_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, +#endif .next = 0 }; diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c new file mode 100644 index 000000000..897a50165 --- /dev/null +++ b/grub-core/fs/zfs/zfs.c @@ -0,0 +1,3950 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc. + * Copyright 2010 Sun Microsystems, 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 zfs plug-in routines for GRUB are: + * + * zfs_mount() - locates a valid uberblock of the root pool and reads + * in its MOS at the memory address MOS. + * + * zfs_open() - locates a plain file object by following the MOS + * and places its dnode at the memory address DNODE. + * + * zfs_read() - read in the data blocks pointed by the DNODE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define ZPOOL_PROP_BOOTFS "bootfs" + +/* + * For nvlist manipulation. (from nvpair.h) + */ +#define NV_ENCODE_NATIVE 0 +#define NV_ENCODE_XDR 1 +#define NV_BIG_ENDIAN 0 +#define NV_LITTLE_ENDIAN 1 +#define DATA_TYPE_UINT64 8 +#define DATA_TYPE_STRING 9 +#define DATA_TYPE_NVLIST 19 +#define DATA_TYPE_NVLIST_ARRAY 20 + +#ifndef GRUB_UTIL +static grub_dl_t my_mod; +#endif + +#define P2PHASE(x, align) ((x) & ((align) - 1)) + +static inline grub_disk_addr_t +DVA_OFFSET_TO_PHYS_SECTOR (grub_disk_addr_t offset) +{ + return ((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT); +} + +/* + * FAT ZAP data structures + */ +#define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */ +static inline grub_uint64_t +ZAP_HASH_IDX (grub_uint64_t hash, grub_uint64_t n) +{ + return (((n) == 0) ? 0 : ((hash) >> (64 - (n)))); +} + +#define CHAIN_END 0xffff /* end of the chunk chain */ + +/* + * The amount of space within the chunk available for the array is: + * chunk size - space for type (1) - space for next pointer (2) + */ +#define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3) + +static inline int +ZAP_LEAF_HASH_SHIFT (int bs) +{ + return bs - 5; +} + +static inline int +ZAP_LEAF_HASH_NUMENTRIES (int bs) +{ + return 1 << ZAP_LEAF_HASH_SHIFT(bs); +} + +static inline grub_size_t +LEAF_HASH (int bs, grub_uint64_t h, zap_leaf_phys_t *l) +{ + return ((ZAP_LEAF_HASH_NUMENTRIES (bs)-1) + & ((h) >> (64 - ZAP_LEAF_HASH_SHIFT (bs) - l->l_hdr.lh_prefix_len))); +} + +/* + * The amount of space available for chunks is: + * block size shift - hash entry size (2) * number of hash + * entries - header space (2*chunksize) + */ +static inline int +ZAP_LEAF_NUMCHUNKS (int bs) +{ + return (((1 << bs) - 2 * ZAP_LEAF_HASH_NUMENTRIES (bs)) / + ZAP_LEAF_CHUNKSIZE - 2); +} + +/* + * The chunks start immediately after the hash table. The end of the + * hash table is at l_hash + HASH_NUMENTRIES, which we simply cast to a + * chunk_t. + */ +static inline zap_leaf_chunk_t * +ZAP_LEAF_CHUNK (zap_leaf_phys_t *l, int bs, int idx) +{ + return &((zap_leaf_chunk_t *) (l->l_entries + + (ZAP_LEAF_HASH_NUMENTRIES(bs) * 2) + / sizeof (grub_properly_aligned_t)))[idx]; +} + +static inline struct zap_leaf_entry * +ZAP_LEAF_ENTRY(zap_leaf_phys_t *l, int bs, int idx) +{ + return &ZAP_LEAF_CHUNK(l, bs, idx)->l_entry; +} + + +/* + * Decompression Entry - lzjb + */ + +extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t); + +typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start, + grub_size_t s_len, grub_size_t d_len); +typedef struct decomp_entry +{ + const char *name; + zfs_decomp_func_t *decomp_func; +} decomp_entry_t; + +/* + * Signature for checksum functions. + */ +typedef void zio_checksum_t(const void *data, grub_uint64_t size, + grub_zfs_endian_t endian, zio_cksum_t *zcp); + +/* + * Information about each checksum function. + */ +typedef struct zio_checksum_info { + zio_checksum_t *ci_func; /* checksum function for each byteorder */ + int ci_correctable; /* number of correctable bits */ + int ci_eck; /* uses zio embedded checksum? */ + const char *ci_name; /* descriptive name */ +} zio_checksum_info_t; + +typedef struct dnode_end +{ + dnode_phys_t dn; + grub_zfs_endian_t endian; +} dnode_end_t; + +struct grub_zfs_device_desc +{ + enum { DEVICE_LEAF, DEVICE_MIRROR, DEVICE_RAIDZ } type; + grub_uint64_t id; + grub_uint64_t guid; + unsigned ashift; + + /* Valid only for non-leafs. */ + unsigned n_children; + struct grub_zfs_device_desc *children; + + /* Valid only for RAIDZ. */ + unsigned nparity; + + /* Valid only for leaf devices. */ + grub_device_t dev; + grub_disk_addr_t vdev_phys_sector; + uberblock_t current_uberblock; + int original; +}; + +struct subvolume +{ + dnode_end_t mdn; + grub_uint64_t obj; + grub_uint64_t case_insensitive; + grub_size_t nkeys; + struct + { + grub_crypto_cipher_handle_t cipher; + grub_uint64_t txg; + grub_uint64_t algo; + } *keyring; +}; + +struct grub_zfs_data +{ + /* cache for a file block of the currently zfs_open()-ed file */ + char *file_buf; + grub_uint64_t file_start; + grub_uint64_t file_end; + + /* cache for a dnode block */ + dnode_phys_t *dnode_buf; + dnode_phys_t *dnode_mdn; + grub_uint64_t dnode_start; + grub_uint64_t dnode_end; + grub_zfs_endian_t dnode_endian; + + dnode_end_t mos; + dnode_end_t dnode; + struct subvolume subvol; + + struct grub_zfs_device_desc *devices_attached; + unsigned n_devices_attached; + unsigned n_devices_allocated; + struct grub_zfs_device_desc *device_original; + + uberblock_t current_uberblock; + + int mounted; + grub_uint64_t guid; +}; + +grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher, + grub_uint64_t algo, + void *nonce, + char *buf, grub_size_t size, + const grub_uint32_t *expected_mac, + grub_zfs_endian_t endian) = NULL; +grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key, + grub_size_t keysize, + grub_uint64_t salt, + grub_uint64_t algo) = NULL; + +static grub_err_t +zlib_decompress (void *s, void *d, + grub_size_t slen, grub_size_t dlen) +{ + if (grub_zlib_decompress (s, slen, 0, d, dlen) < 0) + return grub_errno; + return GRUB_ERR_NONE; +} + +static grub_err_t +zle_decompress (void *s, void *d, + grub_size_t slen, grub_size_t dlen) +{ + grub_uint8_t *iptr, *optr; + grub_size_t clen; + for (iptr = s, optr = d; iptr < (grub_uint8_t *) s + slen + && optr < (grub_uint8_t *) d + dlen;) + { + if (*iptr & 0x80) + clen = ((*iptr) & 0x7f) + 0x41; + else + clen = ((*iptr) & 0x3f) + 1; + if ((grub_ssize_t) clen > (grub_uint8_t *) d + dlen - optr) + clen = (grub_uint8_t *) d + dlen - optr; + if (*iptr & 0x40 || *iptr & 0x80) + { + grub_memset (optr, 0, clen); + iptr++; + optr += clen; + continue; + } + if ((grub_ssize_t) clen > (grub_uint8_t *) s + slen - iptr - 1) + clen = (grub_uint8_t *) s + slen - iptr - 1; + grub_memcpy (optr, iptr + 1, clen); + optr += clen; + iptr += clen + 1; + } + if (optr < (grub_uint8_t *) d + dlen) + grub_memset (optr, 0, (grub_uint8_t *) d + dlen - optr); + return GRUB_ERR_NONE; +} + +static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = { + {"inherit", NULL}, /* ZIO_COMPRESS_INHERIT */ + {"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */ + {"off", NULL}, /* ZIO_COMPRESS_OFF */ + {"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */ + {"empty", NULL}, /* ZIO_COMPRESS_EMPTY */ + {"gzip-1", zlib_decompress}, /* ZIO_COMPRESS_GZIP1 */ + {"gzip-2", zlib_decompress}, /* ZIO_COMPRESS_GZIP2 */ + {"gzip-3", zlib_decompress}, /* ZIO_COMPRESS_GZIP3 */ + {"gzip-4", zlib_decompress}, /* ZIO_COMPRESS_GZIP4 */ + {"gzip-5", zlib_decompress}, /* ZIO_COMPRESS_GZIP5 */ + {"gzip-6", zlib_decompress}, /* ZIO_COMPRESS_GZIP6 */ + {"gzip-7", zlib_decompress}, /* ZIO_COMPRESS_GZIP7 */ + {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */ + {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */ + {"zle", zle_decompress}, /* ZIO_COMPRESS_ZLE */ +}; + +static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, + void *buf, struct grub_zfs_data *data); + +/* + * Our own version of log2(). Same thing as highbit()-1. + */ +static int +zfs_log2 (grub_uint64_t num) +{ + int i = 0; + + while (num > 1) + { + i++; + num = num >> 1; + } + + return (i); +} + +/* Checksum Functions */ +static void +zio_checksum_off (const void *buf __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_zfs_endian_t endian __attribute__ ((unused)), + zio_cksum_t * zcp) +{ + ZIO_SET_CHECKSUM (zcp, 0, 0, 0, 0); +} + +/* Checksum Table and Values */ +static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { + {NULL, 0, 0, "inherit"}, + {NULL, 0, 0, "on"}, + {zio_checksum_off, 0, 0, "off"}, + {zio_checksum_SHA256, 1, 1, "label"}, + {zio_checksum_SHA256, 1, 1, "gang_header"}, + {NULL, 0, 0, "zilog"}, + {fletcher_2, 0, 0, "fletcher2"}, + {fletcher_4, 1, 0, "fletcher4"}, + {zio_checksum_SHA256, 1, 0, "SHA256"}, + {NULL, 0, 0, "zilog2"}, + {zio_checksum_SHA256, 1, 0, "SHA256+MAC"}, +}; + +/* + * zio_checksum_verify: Provides support for checksum verification. + * + * Fletcher2, Fletcher4, and SHA256 are supported. + * + */ +static grub_err_t +zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, + grub_zfs_endian_t endian, + char *buf, grub_size_t size) +{ + zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1; + zio_checksum_info_t *ci = &zio_checksum_table[checksum]; + zio_cksum_t actual_cksum, expected_cksum; + + if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func == NULL) + { + grub_dprintf ("zfs", "unknown checksum function %d\n", checksum); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unknown checksum function %d", checksum); + } + + if (ci->ci_eck) + { + expected_cksum = zec->zec_cksum; + zec->zec_cksum = zc; + ci->ci_func (buf, size, endian, &actual_cksum); + zec->zec_cksum = expected_cksum; + zc = expected_cksum; + } + else + ci->ci_func (buf, size, endian, &actual_cksum); + + if (grub_memcmp (&actual_cksum, &zc, + checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0) + { + grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name); + grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n", + (unsigned long long) actual_cksum.zc_word[0], + (unsigned long long) actual_cksum.zc_word[1], + (unsigned long long) actual_cksum.zc_word[2], + (unsigned long long) actual_cksum.zc_word[3]); + grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n", + (unsigned long long) zc.zc_word[0], + (unsigned long long) zc.zc_word[1], + (unsigned long long) zc.zc_word[2], + (unsigned long long) zc.zc_word[3]); + return grub_error (GRUB_ERR_BAD_FS, "checksum verification failed"); + } + + return GRUB_ERR_NONE; +} + +/* + * vdev_uberblock_compare takes two uberblock structures and returns an integer + * indicating the more recent of the two. + * Return Value = 1 if ub2 is more recent + * Return Value = -1 if ub1 is more recent + * The most recent uberblock is determined using its transaction number and + * timestamp. The uberblock with the highest transaction number is + * considered "newer". If the transaction numbers of the two blocks match, the + * timestamps are compared to determine the "newer" of the two. + */ +static int +vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2) +{ + grub_zfs_endian_t ub1_endian, ub2_endian; + if (grub_zfs_to_cpu64 (ub1->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC) + ub1_endian = GRUB_ZFS_LITTLE_ENDIAN; + else + ub1_endian = GRUB_ZFS_BIG_ENDIAN; + if (grub_zfs_to_cpu64 (ub2->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC) + ub2_endian = GRUB_ZFS_LITTLE_ENDIAN; + else + ub2_endian = GRUB_ZFS_BIG_ENDIAN; + + if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) + < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) + return (-1); + if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) + > grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) + return (1); + + if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) + < grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) + return (-1); + if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) + > grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) + return (1); + + return (0); +} + +/* + * Three pieces of information are needed to verify an uberblock: the magic + * number, the version number, and the checksum. + * + * Currently Implemented: version number, magic number, checksum + * + */ +static grub_err_t +uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset, + grub_size_t s) +{ + uberblock_t *uber = &ub->ubp_uberblock; + grub_err_t err; + grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN; + zio_cksum_t zc; + + if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0 + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) + <= SPA_VERSION) + endian = GRUB_ZFS_LITTLE_ENDIAN; + + if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0 + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) + <= SPA_VERSION) + endian = GRUB_ZFS_BIG_ENDIAN; + + if (endian == GRUB_ZFS_UNKNOWN_ENDIAN) + return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic"); + + grub_memset (&zc, 0, sizeof (zc)); + + zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian); + err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian, + (char *) ub, s); + + return err; +} + +/* + * Find the best uberblock. + * Return: + * Success - Pointer to the best uberblock. + * Failure - NULL + */ +static uberblock_phys_t * +find_bestub (uberblock_phys_t * ub_array, + const struct grub_zfs_device_desc *desc) +{ + uberblock_phys_t *ubbest = NULL, *ubptr; + int i; + grub_disk_addr_t offset; + grub_err_t err = GRUB_ERR_NONE; + int ub_shift; + + ub_shift = desc->ashift; + if (ub_shift < VDEV_UBERBLOCK_SHIFT) + ub_shift = VDEV_UBERBLOCK_SHIFT; + + for (i = 0; i < (VDEV_UBERBLOCK_RING >> ub_shift); i++) + { + offset = (desc->vdev_phys_sector << SPA_MINBLOCKSHIFT) + VDEV_PHYS_SIZE + + (i << ub_shift); + + ubptr = (uberblock_phys_t *) ((grub_properly_aligned_t *) ub_array + + ((i << ub_shift) + / sizeof (grub_properly_aligned_t))); + err = uberblock_verify (ubptr, offset, 1 << ub_shift); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + if (ubbest == NULL + || vdev_uberblock_compare (&(ubptr->ubp_uberblock), + &(ubbest->ubp_uberblock)) > 0) + ubbest = ubptr; + } + if (!ubbest) + grub_errno = err; + + return (ubbest); +} + +static inline grub_size_t +get_psize (blkptr_t * bp, grub_zfs_endian_t endian) +{ + return ((((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) >> 16) & 0xffff) + 1) + << SPA_MINBLOCKSHIFT); +} + +static grub_uint64_t +dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian) +{ + grub_dprintf ("zfs", "dva=%llx, %llx\n", + (unsigned long long) dva->dva_word[0], + (unsigned long long) dva->dva_word[1]); + return grub_zfs_to_cpu64 ((dva)->dva_word[1], + endian) << SPA_MINBLOCKSHIFT; +} + +static grub_err_t +zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist) +{ + grub_err_t err; + + *nvlist = grub_malloc (VDEV_PHYS_SIZE); + if (!diskdesc->dev) + return grub_error (GRUB_ERR_BAD_FS, "member drive unknown"); + + /* Read in the vdev name-value pair list (112K). */ + err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0, + VDEV_PHYS_SIZE, *nvlist); + if (err) + { + grub_free (*nvlist); + *nvlist = 0; + return err; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +fill_vdev_info_real (struct grub_zfs_data *data, + const char *nvlist, + struct grub_zfs_device_desc *fill, + struct grub_zfs_device_desc *insert, + int *inserted, + unsigned ashift) +{ + char *type; + + type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE); + + if (!type) + return grub_errno; + + if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &(fill->id))) + { + grub_free (type); + return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); + } + + if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &(fill->guid))) + { + grub_free (type); + return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); + } + + { + grub_uint64_t par; + if (grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par)) + fill->ashift = par; + else if (ashift != 0xffffffff) + fill->ashift = ashift; + else + { + grub_free (type); + return grub_error (GRUB_ERR_BAD_FS, "couldn't find ashift"); + } + } + + if (grub_strcmp (type, VDEV_TYPE_DISK) == 0 + || grub_strcmp (type, VDEV_TYPE_FILE) == 0) + { + fill->type = DEVICE_LEAF; + + if (!fill->dev && fill->guid == insert->guid) + { + fill->dev = insert->dev; + fill->vdev_phys_sector = insert->vdev_phys_sector; + fill->current_uberblock = insert->current_uberblock; + fill->original = insert->original; + if (!data->device_original) + data->device_original = fill; + insert->ashift = fill->ashift; + *inserted = 1; + } + + grub_free (type); + + return GRUB_ERR_NONE; + } + + if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0 + || grub_strcmp (type, VDEV_TYPE_RAIDZ) == 0) + { + int nelm, i; + + if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) + fill->type = DEVICE_MIRROR; + else + { + grub_uint64_t par; + fill->type = DEVICE_RAIDZ; + if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "nparity", &par)) + { + grub_free (type); + return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz parity"); + } + fill->nparity = par; + } + + nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm (nvlist, + ZPOOL_CONFIG_CHILDREN); + + if (nelm <= 0) + { + grub_free (type); + return grub_error (GRUB_ERR_BAD_FS, "incorrect mirror VDEV"); + } + + if (!fill->children) + { + fill->n_children = nelm; + + fill->children = grub_zalloc (fill->n_children + * sizeof (fill->children[0])); + } + + for (i = 0; i < nelm; i++) + { + char *child; + grub_err_t err; + + child = grub_zfs_nvlist_lookup_nvlist_array + (nvlist, ZPOOL_CONFIG_CHILDREN, i); + + err = fill_vdev_info_real (data, child, &fill->children[i], insert, + inserted, fill->ashift); + + grub_free (child); + + if (err) + { + grub_free (type); + return err; + } + } + grub_free (type); + return GRUB_ERR_NONE; + } + + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "vdev %s isn't supported", type); + grub_free (type); + return grub_errno; +} + +static grub_err_t +fill_vdev_info (struct grub_zfs_data *data, + char *nvlist, struct grub_zfs_device_desc *diskdesc, + int *inserted) +{ + grub_uint64_t id; + unsigned i; + + *inserted = 0; + + if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "id", &id)) + return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev id"); + + for (i = 0; i < data->n_devices_attached; i++) + if (data->devices_attached[i].id == id) + return fill_vdev_info_real (data, nvlist, &data->devices_attached[i], + diskdesc, inserted, 0xffffffff); + + data->n_devices_attached++; + if (data->n_devices_attached > data->n_devices_allocated) + { + void *tmp; + data->n_devices_allocated = 2 * data->n_devices_attached + 1; + data->devices_attached + = grub_realloc (tmp = data->devices_attached, + data->n_devices_allocated + * sizeof (data->devices_attached[0])); + if (!data->devices_attached) + { + data->devices_attached = tmp; + return grub_errno; + } + } + + grub_memset (&data->devices_attached[data->n_devices_attached - 1], + 0, sizeof (data->devices_attached[data->n_devices_attached - 1])); + + return fill_vdev_info_real (data, nvlist, + &data->devices_attached[data->n_devices_attached - 1], + diskdesc, inserted, 0xffffffff); +} + +/* + * Check the disk label information and retrieve needed vdev name-value pairs. + * + */ +static grub_err_t +check_pool_label (struct grub_zfs_data *data, + struct grub_zfs_device_desc *diskdesc, + int *inserted) +{ + grub_uint64_t pool_state, txg = 0; + char *nvlist; +#if 0 + char *nv; +#endif + grub_uint64_t poolguid; + grub_uint64_t version; + int found; + grub_err_t err; + + *inserted = 0; + + err = zfs_fetch_nvlist (diskdesc, &nvlist); + if (err) + return err; + + grub_dprintf ("zfs", "check 2 passed\n"); + + found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE, + &pool_state); + if (! found) + { + grub_free (nvlist); + if (! grub_errno) + grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_STATE " not found"); + return grub_errno; + } + grub_dprintf ("zfs", "check 3 passed\n"); + + if (pool_state == POOL_STATE_DESTROYED) + { + grub_free (nvlist); + return grub_error (GRUB_ERR_BAD_FS, "zpool is marked as destroyed"); + } + grub_dprintf ("zfs", "check 4 passed\n"); + + found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &txg); + if (!found) + { + grub_free (nvlist); + if (! grub_errno) + grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_TXG " not found"); + return grub_errno; + } + grub_dprintf ("zfs", "check 6 passed\n"); + + /* not an active device */ + if (txg == 0) + { + grub_free (nvlist); + return grub_error (GRUB_ERR_BAD_FS, "zpool isn't active"); + } + grub_dprintf ("zfs", "check 7 passed\n"); + + found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_VERSION, + &version); + if (! found) + { + grub_free (nvlist); + if (! grub_errno) + grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_VERSION " not found"); + return grub_errno; + } + grub_dprintf ("zfs", "check 8 passed\n"); + + if (version > SPA_VERSION) + { + grub_free (nvlist); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "too new version %llu > %llu", + (unsigned long long) version, + (unsigned long long) SPA_VERSION); + } + grub_dprintf ("zfs", "check 9 passed\n"); + + found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, + &(diskdesc->guid)); + if (! found) + { + grub_free (nvlist); + if (! grub_errno) + grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found"); + return grub_errno; + } + + found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, + &poolguid); + if (! found) + { + grub_free (nvlist); + if (! grub_errno) + grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_POOL_GUID " not found"); + return grub_errno; + } + + grub_dprintf ("zfs", "check 11 passed\n"); + + if (data->mounted && data->guid != poolguid) + return grub_error (GRUB_ERR_BAD_FS, "another zpool"); + else + data->guid = poolguid; + + { + char *nv; + nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE); + + if (!nv) + { + grub_free (nvlist); + return grub_error (GRUB_ERR_BAD_FS, "couldn't find vdev tree"); + } + err = fill_vdev_info (data, nv, diskdesc, inserted); + if (err) + { + grub_free (nv); + grub_free (nvlist); + return err; + } + grub_free (nv); + } + grub_dprintf ("zfs", "check 10 passed\n"); + + grub_free (nvlist); + + return GRUB_ERR_NONE; +} + +static grub_err_t +scan_disk (grub_device_t dev, struct grub_zfs_data *data, + int original, int *inserted) +{ + int label = 0; + uberblock_phys_t *ub_array, *ubbest = NULL; + vdev_boot_header_t *bh; + grub_err_t err; + int vdevnum; + struct grub_zfs_device_desc desc; + + ub_array = grub_malloc (VDEV_UBERBLOCK_RING); + if (!ub_array) + return grub_errno; + + bh = grub_malloc (VDEV_BOOT_HEADER_SIZE); + if (!bh) + { + grub_free (ub_array); + return grub_errno; + } + + vdevnum = VDEV_LABELS; + + desc.dev = dev; + desc.original = original; + + /* Don't check back labels on CDROM. */ + if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) + vdevnum = VDEV_LABELS / 2; + + for (label = 0; ubbest == NULL && label < vdevnum; label++) + { + desc.vdev_phys_sector + = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) + + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) + + (label < VDEV_LABELS / 2 ? 0 : + ALIGN_DOWN (grub_disk_get_size (dev->disk), sizeof (vdev_label_t)) + - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); + + /* Read in the uberblock ring (128K). */ + err = grub_disk_read (dev->disk, desc.vdev_phys_sector + + (VDEV_PHYS_SIZE >> SPA_MINBLOCKSHIFT), + 0, VDEV_UBERBLOCK_RING, (char *) ub_array); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + grub_dprintf ("zfs", "label ok %d\n", label); + + err = check_pool_label (data, &desc, inserted); + if (err || !*inserted) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + ubbest = find_bestub (ub_array, &desc); + if (!ubbest) + { + grub_dprintf ("zfs", "No uberblock found\n"); + grub_errno = GRUB_ERR_NONE; + continue; + } + + grub_memmove (&(desc.current_uberblock), + &ubbest->ubp_uberblock, sizeof (uberblock_t)); + if (original) + grub_memmove (&(data->current_uberblock), + &ubbest->ubp_uberblock, sizeof (uberblock_t)); + +#if 0 + if (find_best_root && + vdev_uberblock_compare (&ubbest->ubp_uberblock, + &(current_uberblock)) <= 0) + continue; +#endif + grub_free (ub_array); + grub_free (bh); + return GRUB_ERR_NONE; + } + + grub_free (ub_array); + grub_free (bh); + + return grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label"); +} + +static grub_err_t +scan_devices (struct grub_zfs_data *data) +{ + auto int hook (const char *name); + int hook (const char *name) + { + grub_device_t dev; + grub_err_t err; + int inserted; + dev = grub_device_open (name); + if (!dev) + return 0; + if (!dev->disk) + { + grub_device_close (dev); + return 0; + } + err = scan_disk (dev, data, 0, &inserted); + if (err == GRUB_ERR_BAD_FS) + { + grub_device_close (dev); + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (err) + { + grub_device_close (dev); + grub_print_error (); + return 0; + } + + if (!inserted) + grub_device_close (dev); + + return 0; + } + grub_device_iterate (hook); + return GRUB_ERR_NONE; +} + +/* x**y. */ +static grub_uint8_t powx[255 * 2]; +/* Such an s that x**s = y */ +static int powx_inv[256]; +static const grub_uint8_t poly = 0x1d; + +/* perform the operation a ^= b * (x ** (known_idx * recovery_pow) ) */ +static inline void +xor_out (grub_uint8_t *a, const grub_uint8_t *b, grub_size_t s, + int known_idx, int recovery_pow) +{ + int add; + + /* Simple xor. */ + if (known_idx == 0 || recovery_pow == 0) + { + grub_crypto_xor (a, a, b, s); + return; + } + add = (known_idx * recovery_pow) % 255; + for (;s--; b++, a++) + if (*b) + *a ^= powx[powx_inv[*b] + add]; +} + +static inline grub_uint8_t +gf_mul (grub_uint8_t a, grub_uint8_t b) +{ + if (a == 0 || b == 0) + return 0; + return powx[powx_inv[a] + powx_inv[b]]; +} + +static inline grub_err_t +recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, + const unsigned *powers, + const int *idx) +{ + grub_dprintf ("zfs", "recovering %u buffers\n", nbufs); + /* Now we have */ + /* b_i = sum (r_j* (x ** (powers[i] * idx[j])))*/ + /* Let's invert the matrix in question. */ + switch (nbufs) + { + /* Easy: r_0 = bufs[0] / (x << (powers[i] * idx[j])). */ + case 1: + { + int add; + grub_uint8_t *a; + if (powers[0] == 0 || idx[0] == 0) + return GRUB_ERR_NONE; + add = 255 - ((powers[0] * idx[0]) % 255); + for (a = bufs[0]; s--; a++) + if (*a) + *a = powx[powx_inv[*a] + add]; + return GRUB_ERR_NONE; + } + /* Case 2x2: Let's use the determinant formula. */ + case 2: + { + grub_uint8_t det, det_inv; + grub_uint8_t matrixinv[2][2]; + unsigned i; + /* The determinant is: */ + det = (powx[(powers[0] * idx[0] + powers[1] * idx[1]) % 255] + ^ powx[(powers[0] * idx[1] + powers[1] * idx[0]) % 255]); + if (det == 0) + return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix"); + det_inv = powx[255 - powx_inv[det]]; + matrixinv[0][0] = gf_mul (powx[(powers[1] * idx[1]) % 255], det_inv); + matrixinv[1][1] = gf_mul (powx[(powers[0] * idx[0]) % 255], det_inv); + matrixinv[0][1] = gf_mul (powx[(powers[0] * idx[1]) % 255], det_inv); + matrixinv[1][0] = gf_mul (powx[(powers[1] * idx[0]) % 255], det_inv); + for (i = 0; i < s; i++) + { + grub_uint8_t b0, b1; + b0 = bufs[0][i]; + b1 = bufs[1][i]; + + bufs[0][i] = (gf_mul (b0, matrixinv[0][0]) + ^ gf_mul (b1, matrixinv[0][1])); + bufs[1][i] = (gf_mul (b0, matrixinv[1][0]) + ^ gf_mul (b1, matrixinv[1][1])); + } + return GRUB_ERR_NONE; + } + /* Otherwise use Gauss. */ + default: + { + grub_uint8_t matrix1[nbufs][nbufs], matrix2[nbufs][nbufs]; + int i, j, k; + + for (i = 0; i < nbufs; i++) + for (j = 0; j < nbufs; j++) + matrix1[i][j] = powx[(powers[i] * idx[j]) % 255]; + for (i = 0; i < nbufs; i++) + for (j = 0; j < nbufs; j++) + matrix2[i][j] = 0; + for (i = 0; i < nbufs; i++) + matrix2[i][i] = 1; + + for (i = 0; i < nbufs; i++) + { + grub_uint8_t mul; + for (j = i; j < nbufs; j++) + if (matrix1[i][j]) + break; + if (j == nbufs) + return grub_error (GRUB_ERR_BAD_FS, "singular recovery matrix"); + if (j != i) + { + int xchng; + xchng = j; + for (j = 0; j < nbufs; j++) + { + grub_uint8_t t; + t = matrix1[xchng][j]; + matrix1[xchng][j] = matrix1[i][j]; + matrix1[i][j] = t; + } + for (j = 0; j < nbufs; j++) + { + grub_uint8_t t; + t = matrix2[xchng][j]; + matrix2[xchng][j] = matrix2[i][j]; + matrix2[i][j] = t; + } + } + mul = powx[255 - powx_inv[matrix1[i][i]]]; + for (j = 0; j < nbufs; j++) + matrix1[i][j] = gf_mul (matrix1[i][j], mul); + for (j = 0; j < nbufs; j++) + matrix2[i][j] = gf_mul (matrix2[i][j], mul); + for (j = i + 1; j < nbufs; j++) + { + mul = matrix1[j][i]; + for (k = 0; k < nbufs; k++) + matrix1[j][k] ^= gf_mul (matrix1[i][k], mul); + for (k = 0; k < nbufs; k++) + matrix2[j][k] ^= gf_mul (matrix2[i][k], mul); + } + } + for (i = nbufs - 1; i >= 0; i--) + { + for (j = 0; j < i; j++) + { + grub_uint8_t mul; + mul = matrix1[j][i]; + for (k = 0; k < nbufs; k++) + matrix1[j][k] ^= gf_mul (matrix1[i][k], mul); + for (k = 0; k < nbufs; k++) + matrix2[j][k] ^= gf_mul (matrix2[i][k], mul); + } + } + + for (i = 0; i < (int) s; i++) + { + grub_uint8_t b[nbufs]; + for (j = 0; j < nbufs; j++) + b[j] = bufs[j][i]; + for (j = 0; j < nbufs; j++) + { + bufs[j][i] = 0; + for (k = 0; k < nbufs; k++) + bufs[j][i] ^= gf_mul (matrix2[j][k], b[k]); + } + } + return GRUB_ERR_NONE; + } + } +} + +static grub_err_t +read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + grub_size_t len, void *buf) +{ + switch (desc->type) + { + case DEVICE_LEAF: + { + grub_uint64_t sector; + sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); + if (!desc->dev) + { + return grub_error (GRUB_ERR_BAD_FS, "member drive unknown"); + } + /* read in a data block */ + return grub_disk_read (desc->dev->disk, sector, 0, len, buf); + } + case DEVICE_MIRROR: + { + grub_err_t err = GRUB_ERR_NONE; + unsigned i; + if (desc->n_children <= 0) + return grub_error (GRUB_ERR_BAD_FS, + "non-positive number of mirror children"); + for (i = 0; i < desc->n_children; i++) + { + err = read_device (offset, &desc->children[i], + len, buf); + if (!err) + break; + grub_errno = GRUB_ERR_NONE; + } + return (grub_errno = err); + } + case DEVICE_RAIDZ: + { + unsigned c = 0; + grub_uint64_t high; + grub_uint64_t devn; + grub_uint64_t m; + grub_uint32_t s, orig_s; + void *orig_buf = buf; + grub_size_t orig_len = len; + grub_uint8_t *recovery_buf[4]; + grub_size_t recovery_len[4]; + int recovery_idx[4]; + unsigned failed_devices = 0; + int idx, orig_idx; + + if (desc->nparity < 1 || desc->nparity > 3) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "raidz%d is not supported", desc->nparity); + + orig_s = (((len + (1 << desc->ashift) - 1) >> desc->ashift) + + (desc->n_children - desc->nparity) - 1); + s = orig_s; + + high = grub_divmod64 ((offset >> desc->ashift), + desc->n_children, &m); + if (desc->nparity == 2) + c = 2; + if (desc->nparity == 3) + c = 3; + if (((len + (1 << desc->ashift) - 1) >> desc->ashift) + >= (desc->n_children - desc->nparity)) + idx = (desc->n_children - desc->nparity - 1); + else + idx = ((len + (1 << desc->ashift) - 1) >> desc->ashift) - 1; + orig_idx = idx; + while (len > 0) + { + grub_size_t csize; + grub_uint32_t bsize; + grub_err_t err; + bsize = s / (desc->n_children - desc->nparity); + + if (desc->nparity == 1 + && ((offset >> (desc->ashift + 11)) & 1) == c) + c++; + + high = grub_divmod64 ((offset >> desc->ashift) + c, + desc->n_children, &devn); + csize = bsize << desc->ashift; + if (csize > len) + csize = len; + + grub_dprintf ("zfs", "RAIDZ mapping 0x%" PRIxGRUB_UINT64_T + "+%u (%" PRIxGRUB_SIZE ", %" PRIxGRUB_UINT32_T + ") -> (0x%" PRIxGRUB_UINT64_T ", 0x%" + PRIxGRUB_UINT64_T ")\n", + offset >> desc->ashift, c, len, bsize, high, + devn); + err = read_device ((high << desc->ashift) + | (offset & ((1 << desc->ashift) - 1)), + &desc->children[devn], + csize, buf); + if (err && failed_devices < desc->nparity) + { + recovery_buf[failed_devices] = buf; + recovery_len[failed_devices] = csize; + recovery_idx[failed_devices] = idx; + failed_devices++; + grub_errno = err = 0; + } + if (err) + return err; + + c++; + idx--; + s--; + buf = (char *) buf + csize; + len -= csize; + } + if (failed_devices) + { + unsigned redundancy_pow[4]; + unsigned cur_redundancy_pow = 0; + unsigned n_redundancy = 0; + unsigned i, j; + grub_err_t err; + + /* Compute mul. x**s has a period of 255. */ + if (powx[0] == 0) + { + grub_uint8_t cur = 1; + for (i = 0; i < 255; i++) + { + powx[i] = cur; + powx[i + 255] = cur; + powx_inv[cur] = i; + if (cur & 0x80) + cur = (cur << 1) ^ poly; + else + cur <<= 1; + } + } + + /* Read redundancy data. */ + for (n_redundancy = 0, cur_redundancy_pow = 0; + n_redundancy < failed_devices; + cur_redundancy_pow++) + { + high = grub_divmod64 ((offset >> desc->ashift) + + cur_redundancy_pow + + ((desc->nparity == 1) + && ((offset >> (desc->ashift + 11)) + & 1)), + desc->n_children, &devn); + err = read_device ((high << desc->ashift) + | (offset & ((1 << desc->ashift) - 1)), + &desc->children[devn], + recovery_len[n_redundancy], + recovery_buf[n_redundancy]); + /* Ignore error if we may still have enough devices. */ + if (err && n_redundancy + desc->nparity - cur_redundancy_pow - 1 + >= failed_devices) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + if (err) + return err; + redundancy_pow[n_redundancy] = cur_redundancy_pow; + n_redundancy++; + } + /* Now xor-our the parts we already know. */ + buf = orig_buf; + len = orig_len; + s = orig_s; + idx = orig_idx; + + while (len > 0) + { + grub_size_t csize; + csize = ((s / (desc->n_children - desc->nparity)) + << desc->ashift); + if (csize > len) + csize = len; + + for (j = 0; j < failed_devices; j++) + if (buf == recovery_buf[j]) + break; + + if (j == failed_devices) + for (j = 0; j < failed_devices; j++) + xor_out (recovery_buf[j], buf, + csize < recovery_len[j] ? csize : recovery_len[j], + idx, redundancy_pow[j]); + + s--; + buf = (char *) buf + csize; + len -= csize; + idx--; + } + for (i = 0; i < failed_devices + && recovery_len[i] == recovery_len[0]; + i++); + /* Since the chunks have variable length handle the last block + separately. */ + if (i != failed_devices) + { + grub_uint8_t *tmp_recovery_buf[4]; + for (j = 0; j < i; j++) + tmp_recovery_buf[j] = recovery_buf[j] + recovery_len[failed_devices - 1]; + err = recovery (tmp_recovery_buf, recovery_len[0] - recovery_len[failed_devices - 1], i, redundancy_pow, + recovery_idx); + if (err) + return err; + } + err = recovery (recovery_buf, recovery_len[failed_devices - 1], + failed_devices, redundancy_pow, recovery_idx); + if (err) + return err; + } + return GRUB_ERR_NONE; + } + } + return grub_error (GRUB_ERR_BAD_FS, "unsupported device type"); +} + +static grub_err_t +read_dva (const dva_t *dva, + grub_zfs_endian_t endian, struct grub_zfs_data *data, + void *buf, grub_size_t len) +{ + grub_uint64_t offset; + unsigned i; + grub_err_t err = 0; + int try = 0; + offset = dva_get_offset (dva, endian); + + for (try = 0; try < 2; try++) + { + for (i = 0; i < data->n_devices_attached; i++) + if (data->devices_attached[i].id == DVA_GET_VDEV (dva)) + { + err = read_device (offset, &data->devices_attached[i], len, buf); + if (!err) + return GRUB_ERR_NONE; + break; + } + if (try == 1) + break; + err = scan_devices (data); + if (err) + return err; + } + if (!err) + return grub_error (GRUB_ERR_BAD_FS, "unknown device %d", + (int) DVA_GET_VDEV (dva)); + return err; +} + +/* + * Read a block of data based on the gang block address dva, + * and put its data in buf. + * + */ +static grub_err_t +zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, + struct grub_zfs_data *data) +{ + zio_gbh_phys_t *zio_gb; + unsigned i; + grub_err_t err; + zio_cksum_t zc; + + grub_memset (&zc, 0, sizeof (zc)); + + zio_gb = grub_malloc (SPA_GANGBLOCKSIZE); + if (!zio_gb) + return grub_errno; + grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n" + :"big-endian gang\n"); + + err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE); + if (err) + { + grub_free (zio_gb); + return err; + } + + /* XXX */ + /* self checksuming the gang block header */ + ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva), + dva_get_offset (dva, endian), bp->blk_birth, 0); + err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER, endian, + (char *) zio_gb, SPA_GANGBLOCKSIZE); + if (err) + { + grub_free (zio_gb); + return err; + } + + endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; + + for (i = 0; i < SPA_GBH_NBLKPTRS; i++) + { + if (zio_gb->zg_blkptr[i].blk_birth == 0) + continue; + + err = zio_read_data (&zio_gb->zg_blkptr[i], endian, buf, data); + if (err) + { + grub_free (zio_gb); + return err; + } + buf = (char *) buf + get_psize (&zio_gb->zg_blkptr[i], endian); + } + grub_free (zio_gb); + return GRUB_ERR_NONE; +} + +/* + * Read in a block of raw data to buf. + */ +static grub_err_t +zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, + struct grub_zfs_data *data) +{ + int i, psize; + grub_err_t err = GRUB_ERR_NONE; + + psize = get_psize (bp, endian); + + /* pick a good dva from the block pointer */ + for (i = 0; i < SPA_DVAS_PER_BP; i++) + { + if (bp->blk_dva[i].dva_word[0] == 0 && bp->blk_dva[i].dva_word[1] == 0) + continue; + + if ((grub_zfs_to_cpu64 (bp->blk_dva[i].dva_word[1], endian)>>63) & 1) + err = zio_read_gang (bp, endian, &bp->blk_dva[i], buf, data); + else + err = read_dva (&bp->blk_dva[i], endian, data, buf, psize); + if (!err) + return GRUB_ERR_NONE; + grub_errno = GRUB_ERR_NONE; + } + + if (!err) + err = grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid DVA"); + grub_errno = err; + + return err; +} + +/* + * Read in a block of data, verify its checksum, decompress if needed, + * and put the uncompressed data in buf. + */ +static grub_err_t +zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + grub_size_t *size, struct grub_zfs_data *data) +{ + grub_size_t lsize, psize; + unsigned int comp, encrypted; + char *compbuf = NULL; + grub_err_t err; + zio_cksum_t zc = bp->blk_cksum; + grub_uint32_t checksum; + + *buf = NULL; + + checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; + comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0xff; + encrypted = ((grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 60) & 3); + lsize = (BP_IS_HOLE(bp) ? 0 : + (((grub_zfs_to_cpu64 ((bp)->blk_prop, endian) & 0xffff) + 1) + << SPA_MINBLOCKSHIFT)); + psize = get_psize (bp, endian); + + if (size) + *size = lsize; + + if (comp >= ZIO_COMPRESS_FUNCTIONS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "compression algorithm %u not supported\n", (unsigned int) comp); + + if (comp != ZIO_COMPRESS_OFF && decomp_table[comp].decomp_func == NULL) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "compression algorithm %s not supported\n", decomp_table[comp].name); + + if (comp != ZIO_COMPRESS_OFF) + { + /* It's not really necessary to align to 16, just for safety. */ + compbuf = grub_malloc (ALIGN_UP (psize, 16)); + if (! compbuf) + return grub_errno; + } + else + compbuf = *buf = grub_malloc (lsize); + + grub_dprintf ("zfs", "endian = %d\n", endian); + err = zio_read_data (bp, endian, compbuf, data); + if (err) + { + grub_free (compbuf); + *buf = NULL; + return err; + } + grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize); + + err = zio_checksum_verify (zc, checksum, endian, + compbuf, psize); + if (err) + { + grub_dprintf ("zfs", "incorrect checksum\n"); + grub_free (compbuf); + *buf = NULL; + return err; + } + + if (encrypted) + { + if (!grub_zfs_decrypt) + err = grub_error (GRUB_ERR_BAD_FS, "zfscrypt module not loaded"); + else + { + unsigned i, besti = 0; + grub_uint64_t bestval = 0; + for (i = 0; i < data->subvol.nkeys; i++) + if (data->subvol.keyring[i].txg <= grub_zfs_to_cpu64 (bp->blk_birth, + endian) + && data->subvol.keyring[i].txg > bestval) + { + besti = i; + bestval = data->subvol.keyring[i].txg; + } + if (bestval == 0) + { + grub_free (compbuf); + *buf = NULL; + grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n", + grub_zfs_to_cpu64 (bp->blk_birth, + endian)); + return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain"); + } + grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T + ", %p) for txg %" PRIxGRUB_UINT64_T "\n", + besti, data->subvol.keyring[besti].txg, + data->subvol.keyring[besti].cipher, + grub_zfs_to_cpu64 (bp->blk_birth, + endian)); + err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher, + data->subvol.keyring[besti].algo, + &(bp)->blk_dva[encrypted], + compbuf, psize, ((grub_uint32_t *) &zc + 5), + endian); + } + if (err) + { + grub_free (compbuf); + *buf = NULL; + return err; + } + } + + if (comp != ZIO_COMPRESS_OFF) + { + *buf = grub_malloc (lsize); + if (!*buf) + { + grub_free (compbuf); + return grub_errno; + } + + err = decomp_table[comp].decomp_func (compbuf, *buf, psize, lsize); + grub_free (compbuf); + if (err) + { + grub_free (*buf); + *buf = NULL; + return err; + } + } + + return GRUB_ERR_NONE; +} + +/* + * Get the block from a block id. + * push the block onto the stack. + * + */ +static grub_err_t +dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, + grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) +{ + int level; + grub_off_t idx; + blkptr_t *bp_array = dn->dn.dn_blkptr; + int epbs = dn->dn.dn_indblkshift - SPA_BLKPTRSHIFT; + blkptr_t *bp; + void *tmpbuf = 0; + grub_zfs_endian_t endian; + grub_err_t err = GRUB_ERR_NONE; + + bp = grub_malloc (sizeof (blkptr_t)); + if (!bp) + return grub_errno; + + endian = dn->endian; + for (level = dn->dn.dn_nlevels - 1; level >= 0; level--) + { + grub_dprintf ("zfs", "endian = %d\n", endian); + idx = (blkid >> (epbs * level)) & ((1 << epbs) - 1); + *bp = bp_array[idx]; + if (bp_array != dn->dn.dn_blkptr) + { + grub_free (bp_array); + bp_array = 0; + } + + if (BP_IS_HOLE (bp)) + { + grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, + dn->endian) + << SPA_MINBLOCKSHIFT; + *buf = grub_malloc (size); + if (*buf) + { + err = grub_errno; + break; + } + grub_memset (*buf, 0, size); + endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; + break; + } + if (level == 0) + { + grub_dprintf ("zfs", "endian = %d\n", endian); + err = zio_read (bp, endian, buf, 0, data); + endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; + break; + } + grub_dprintf ("zfs", "endian = %d\n", endian); + err = zio_read (bp, endian, &tmpbuf, 0, data); + endian = (grub_zfs_to_cpu64 (bp->blk_prop, endian) >> 63) & 1; + if (err) + break; + bp_array = tmpbuf; + } + if (bp_array != dn->dn.dn_blkptr) + grub_free (bp_array); + if (endian_out) + *endian_out = endian; + + grub_free (bp); + return err; +} + +/* + * mzap_lookup: Looks up property described by "name" and returns the value + * in "value". + */ +static grub_err_t +mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, + int objsize, const char *name, grub_uint64_t * value, + int case_insensitive) +{ + int i, chunks; + mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; + + chunks = objsize / MZAP_ENT_LEN - 1; + for (i = 0; i < chunks; i++) + { + if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0) + : (grub_strcmp (mzap_ent[i].mze_name, name) == 0)) + { + *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian); + return GRUB_ERR_NONE; + } + } + + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't find %s", name); +} + +static int +mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, + int NESTED_FUNC_ATTR (*hook) (const char *name, + grub_uint64_t val)) +{ + int i, chunks; + mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; + + chunks = objsize / MZAP_ENT_LEN - 1; + for (i = 0; i < chunks; i++) + { + grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n", + mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value, + (int)mzap_ent[i].mze_cd); + if (hook (mzap_ent[i].mze_name, + grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian))) + return 1; + } + + return 0; +} + +static grub_uint64_t +zap_hash (grub_uint64_t salt, const char *name, + int case_insensitive) +{ + static grub_uint64_t table[256]; + const grub_uint8_t *cp; + grub_uint8_t c; + grub_uint64_t crc = salt; + + if (table[128] == 0) + { + grub_uint64_t *ct; + int i, j; + for (i = 0; i < 256; i++) + { + for (ct = table + i, *ct = i, j = 8; j > 0; j--) + *ct = (*ct >> 1) ^ (-(*ct & 1) & ZFS_CRC64_POLY); + } + } + + if (case_insensitive) + for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++) + crc = (crc >> 8) ^ table[(crc ^ grub_toupper (c)) & 0xFF]; + else + for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++) + crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF]; + + /* + * Only use 28 bits, since we need 4 bits in the cookie for the + * collision differentiator. We MUST use the high bits, since + * those are the onces that we first pay attention to when + * chosing the bucket. + */ + crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1); + + return (crc); +} + +/* + * Only to be used on 8-bit arrays. + * array_len is actual len in bytes (not encoded le_value_length). + * buf is null-terminated. + */ + +static inline int +name_cmp (const char *s1, const char *s2, grub_size_t n, + int case_insensitive) +{ + const char *t1 = (const char *) s1; + const char *t2 = (const char *) s2; + + if (!case_insensitive) + return grub_memcmp (t1, t2, n); + + while (n--) + { + if (grub_toupper (*t1) != grub_toupper (*t2)) + return (int) grub_toupper (*t1) - (int) grub_toupper (*t2); + + t1++; + t2++; + } + + return 0; +} + +/* XXX */ +static int +zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + int blksft, int chunk, grub_size_t array_len, + const char *buf, int case_insensitive) +{ + grub_size_t bseen = 0; + + while (bseen < array_len) + { + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array; + grub_size_t toread = array_len - bseen; + + if (toread > ZAP_LEAF_ARRAY_BYTES) + toread = ZAP_LEAF_ARRAY_BYTES; + + if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) + return 0; + + if (name_cmp ((char *) la->la_array, buf + bseen, toread, + case_insensitive) != 0) + break; + chunk = grub_zfs_to_cpu16 (la->la_next, endian); + bseen += toread; + } + return (bseen == array_len); +} + +/* XXX */ +static grub_err_t +zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, + int chunk, grub_size_t array_len, char *buf) +{ + grub_size_t bseen = 0; + + while (bseen < array_len) + { + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array; + grub_size_t toread = array_len - bseen; + + if (toread > ZAP_LEAF_ARRAY_BYTES) + toread = ZAP_LEAF_ARRAY_BYTES; + + if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) + /* Don't use grub_error because this error is to be ignored. */ + return GRUB_ERR_BAD_FS; + + grub_memcpy (buf + bseen,la->la_array, toread); + chunk = grub_zfs_to_cpu16 (la->la_next, endian); + bseen += toread; + } + return GRUB_ERR_NONE; +} + + +/* + * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the + * value for the property "name". + * + */ +/* XXX */ +static grub_err_t +zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + int blksft, grub_uint64_t h, + const char *name, grub_uint64_t * value, + int case_insensitive) +{ + grub_uint16_t chunk; + struct zap_leaf_entry *le; + + /* Verify if this is a valid leaf block */ + if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF) + return grub_error (GRUB_ERR_BAD_FS, "invalid leaf type"); + if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC) + return grub_error (GRUB_ERR_BAD_FS, "invalid leaf magic"); + + for (chunk = grub_zfs_to_cpu16 (l->l_hash[LEAF_HASH (blksft, h, l)], endian); + chunk != CHAIN_END; chunk = grub_zfs_to_cpu16 (le->le_next, endian)) + { + + if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) + return grub_error (GRUB_ERR_BAD_FS, "invalid chunk number"); + + le = ZAP_LEAF_ENTRY (l, blksft, chunk); + + /* Verify the chunk entry */ + if (le->le_type != ZAP_CHUNK_ENTRY) + return grub_error (GRUB_ERR_BAD_FS, "invalid chunk entry"); + + if (grub_zfs_to_cpu64 (le->le_hash,endian) != h) + continue; + + grub_dprintf ("zfs", "fzap: length %d\n", (int) le->le_name_length); + + if (zap_leaf_array_equal (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk,endian), + grub_zfs_to_cpu16 (le->le_name_length, endian), + name, case_insensitive)) + { + struct zap_leaf_array *la; + + if (le->le_int_size != 8 || grub_zfs_to_cpu16 (le->le_value_length, + endian) != 1) + return grub_error (GRUB_ERR_BAD_FS, "invalid leaf chunk entry"); + + /* get the uint64_t property value */ + la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk)->l_array; + + *value = grub_be_to_cpu64 (la->la_array64); + + return GRUB_ERR_NONE; + } + } + + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't find %s", name); +} + + +/* Verify if this is a fat zap header block */ +static grub_err_t +zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian) +{ + if (grub_zfs_to_cpu64 (zap->zap_magic, endian) != (grub_uint64_t) ZAP_MAGIC) + return grub_error (GRUB_ERR_BAD_FS, "bad ZAP magic"); + + if (zap->zap_salt == 0) + return grub_error (GRUB_ERR_BAD_FS, "bad ZAP salt"); + + return GRUB_ERR_NONE; +} + +/* + * Fat ZAP lookup + * + */ +/* XXX */ +static grub_err_t +fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, + const char *name, grub_uint64_t * value, + struct grub_zfs_data *data, int case_insensitive) +{ + void *l; + grub_uint64_t hash, idx, blkid; + int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t leafendian; + + err = zap_verify (zap, zap_dnode->endian); + if (err) + return err; + + hash = zap_hash (zap->zap_salt, name, case_insensitive); + + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); + blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian); + + /* Get the leaf block */ + if ((1U << blksft) < sizeof (zap_leaf_phys_t)) + return grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); + err = dmu_read (zap_dnode, blkid, &l, &leafendian, data); + if (err) + return err; + + err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value, + case_insensitive); + grub_free (l); + return err; +} + +/* XXX */ +static int +fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + grub_size_t name_elem_length, + int NESTED_FUNC_ATTR (*hook) (const void *name, + grub_size_t name_length, + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize), + struct grub_zfs_data *data) +{ + zap_leaf_phys_t *l; + void *l_in; + grub_uint64_t idx, idx2, blkid; + grub_uint16_t chunk; + int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t endian; + + if (zap_verify (zap, zap_dnode->endian)) + return 0; + + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + return 0; + } + /* Get the leaf block */ + if ((1U << blksft) < sizeof (zap_leaf_phys_t)) + { + grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); + return 0; + } + for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++) + { + blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], + zap_dnode->endian); + + for (idx2 = 0; idx2 < idx; idx2++) + if (blkid == grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx2 + (1 << (blksft - 3 - 1))], + zap_dnode->endian)) + break; + if (idx2 != idx) + continue; + + err = dmu_read (zap_dnode, blkid, &l_in, &endian, data); + l = l_in; + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + /* Verify if this is a valid leaf block */ + if (grub_zfs_to_cpu64 (l->l_hdr.lh_block_type, endian) != ZBT_LEAF) + { + grub_free (l); + continue; + } + if (grub_zfs_to_cpu32 (l->l_hdr.lh_magic, endian) != ZAP_LEAF_MAGIC) + { + grub_free (l); + continue; + } + + for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++) + { + char *buf; + struct zap_leaf_entry *le; + char *val; + grub_size_t val_length; + le = ZAP_LEAF_ENTRY (l, blksft, chunk); + + /* Verify the chunk entry */ + if (le->le_type != ZAP_CHUNK_ENTRY) + continue; + + buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) + * name_elem_length + 1); + if (zap_leaf_array_get (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk, + endian), + grub_zfs_to_cpu16 (le->le_name_length, + endian) + * name_elem_length, buf)) + { + grub_free (buf); + continue; + } + buf[le->le_name_length * name_elem_length] = 0; + + val_length = ((int) le->le_value_length + * (int) le->le_int_size); + val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian)); + if (zap_leaf_array_get (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_value_chunk, + endian), + val_length, val)) + { + grub_free (buf); + grub_free (val); + continue; + } + + if (hook (buf, le->le_name_length, + val, le->le_value_length, le->le_int_size)) + { + grub_free (l); + return 1; + } + grub_free (buf); + grub_free (val); + } + grub_free (l); + } + return 0; +} + +/* + * Read in the data of a zap object and find the value for a matching + * property name. + * + */ +static grub_err_t +zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val, + struct grub_zfs_data *data, int case_insensitive) +{ + grub_uint64_t block_type; + int size; + void *zapbuf; + grub_err_t err; + grub_zfs_endian_t endian; + + grub_dprintf ("zfs", "looking for '%s'\n", name); + + /* Read in the first block of the zap object data. */ + size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << SPA_MINBLOCKSHIFT; + err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); + if (err) + return err; + block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); + + grub_dprintf ("zfs", "zap read\n"); + + if (block_type == ZBT_MICRO) + { + grub_dprintf ("zfs", "micro zap\n"); + err = mzap_lookup (zapbuf, endian, size, name, val, + case_insensitive); + grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; + } + else if (block_type == ZBT_HEADER) + { + grub_dprintf ("zfs", "fat zap\n"); + /* this is a fat zap */ + err = fzap_lookup (zap_dnode, zapbuf, name, val, data, + case_insensitive); + grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; + } + + return grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); +} + +static int +zap_iterate_u64 (dnode_end_t * zap_dnode, + int NESTED_FUNC_ATTR (*hook) (const char *name, + grub_uint64_t val), + struct grub_zfs_data *data) +{ + grub_uint64_t block_type; + int size; + void *zapbuf; + grub_err_t err; + int ret; + grub_zfs_endian_t endian; + + auto int NESTED_FUNC_ATTR transform (const void *name, + grub_size_t namelen, + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize); + + int NESTED_FUNC_ATTR transform (const void *name, + grub_size_t namelen __attribute__ ((unused)), + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize) + { + if (elemsize != sizeof (grub_uint64_t) || nelem != 1) + return 0; + return hook (name, grub_be_to_cpu64 (*(const grub_uint64_t *) val_in)); + } + + /* Read in the first block of the zap object data. */ + size = grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, zap_dnode->endian) << SPA_MINBLOCKSHIFT; + err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); + if (err) + return 0; + block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); + + grub_dprintf ("zfs", "zap iterate\n"); + + if (block_type == ZBT_MICRO) + { + grub_dprintf ("zfs", "micro zap\n"); + ret = mzap_iterate (zapbuf, endian, size, hook); + grub_free (zapbuf); + return ret; + } + else if (block_type == ZBT_HEADER) + { + grub_dprintf ("zfs", "fat zap\n"); + /* this is a fat zap */ + ret = fzap_iterate (zap_dnode, zapbuf, 1, transform, data); + grub_free (zapbuf); + return ret; + } + grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); + return 0; +} + +static int +zap_iterate (dnode_end_t * zap_dnode, + grub_size_t nameelemlen, + int NESTED_FUNC_ATTR (*hook) (const void *name, + grub_size_t namelen, + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize), + struct grub_zfs_data *data) +{ + grub_uint64_t block_type; + void *zapbuf; + grub_err_t err; + int ret; + grub_zfs_endian_t endian; + + /* Read in the first block of the zap object data. */ + err = dmu_read (zap_dnode, 0, &zapbuf, &endian, data); + if (err) + return 0; + block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); + + grub_dprintf ("zfs", "zap iterate\n"); + + if (block_type == ZBT_MICRO) + { + grub_error (GRUB_ERR_BAD_FS, "micro ZAP where FAT ZAP expected"); + return 0; + } + if (block_type == ZBT_HEADER) + { + grub_dprintf ("zfs", "fat zap\n"); + /* this is a fat zap */ + ret = fzap_iterate (zap_dnode, zapbuf, nameelemlen, hook, data); + grub_free (zapbuf); + return ret; + } + grub_error (GRUB_ERR_BAD_FS, "unknown ZAP type"); + return 0; +} + + +/* + * Get the dnode of an object number from the metadnode of an object set. + * + * Input + * mdn - metadnode to get the object dnode + * objnum - object number for the object dnode + * buf - data buffer that holds the returning dnode + */ +static grub_err_t +dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + dnode_end_t * buf, struct grub_zfs_data *data) +{ + grub_uint64_t blkid, blksz; /* the block id this object dnode is in */ + int epbs; /* shift of number of dnodes in a block */ + int idx; /* index within a block */ + void *dnbuf; + grub_err_t err; + grub_zfs_endian_t endian; + + blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, + mdn->endian) << SPA_MINBLOCKSHIFT; + epbs = zfs_log2 (blksz) - DNODE_SHIFT; + blkid = objnum >> epbs; + idx = objnum & ((1 << epbs) - 1); + + if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn, + sizeof (*mdn)) == 0 + && objnum >= data->dnode_start && objnum < data->dnode_end) + { + grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE); + buf->endian = data->dnode_endian; + if (type && buf->dn.dn_type != type) + return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); + return GRUB_ERR_NONE; + } + + grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian, + (unsigned long long) blkid); + err = dmu_read (mdn, blkid, &dnbuf, &endian, data); + if (err) + return err; + grub_dprintf ("zfs", "alive\n"); + + grub_free (data->dnode_buf); + grub_free (data->dnode_mdn); + data->dnode_mdn = grub_malloc (sizeof (*mdn)); + if (! data->dnode_mdn) + { + grub_errno = GRUB_ERR_NONE; + data->dnode_buf = 0; + } + else + { + grub_memcpy (data->dnode_mdn, mdn, sizeof (*mdn)); + data->dnode_buf = dnbuf; + data->dnode_start = blkid << epbs; + data->dnode_end = (blkid + 1) << epbs; + data->dnode_endian = endian; + } + + grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); + buf->endian = endian; + if (type && buf->dn.dn_type != type) + return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); + + return GRUB_ERR_NONE; +} + +/* + * Get the file dnode for a given file name where mdn is the meta dnode + * for this ZFS object set. When found, place the file dnode in dn. + * The 'path' argument will be mangled. + * + */ +static grub_err_t +dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + struct grub_zfs_data *data) +{ + grub_uint64_t objnum, version; + char *cname, ch; + grub_err_t err = GRUB_ERR_NONE; + char *path, *path_buf; + struct dnode_chain + { + struct dnode_chain *next; + dnode_end_t dn; + }; + struct dnode_chain *dnode_path = 0, *dn_new, *root; + + dn_new = grub_malloc (sizeof (*dn_new)); + if (! dn_new) + return grub_errno; + dn_new->next = 0; + dnode_path = root = dn_new; + + err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + &(dnode_path->dn), data); + if (err) + { + grub_free (dn_new); + return err; + } + + err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, + data, 0); + if (err) + { + grub_free (dn_new); + return err; + } + + if (version > ZPL_VERSION) + { + grub_free (dn_new); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too new ZPL version"); + } + + err = zap_lookup (&(dnode_path->dn), "casesensitivity", + &subvol->case_insensitive, + data, 0); + if (err == GRUB_ERR_FILE_NOT_FOUND) + { + grub_errno = GRUB_ERR_NONE; + subvol->case_insensitive = 0; + } + + err = zap_lookup (&(dnode_path->dn), ZFS_ROOT_OBJ, &objnum, data, 0); + if (err) + { + grub_free (dn_new); + return err; + } + + err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data); + if (err) + { + grub_free (dn_new); + return err; + } + + path = path_buf = grub_strdup (path_in); + if (!path_buf) + { + grub_free (dn_new); + return grub_errno; + } + + while (1) + { + /* skip leading slashes */ + while (*path == '/') + path++; + if (!*path) + break; + /* get the next component name */ + cname = path; + while (*path && *path != '/') + path++; + /* Skip dot. */ + if (cname + 1 == path && cname[0] == '.') + continue; + /* Handle double dot. */ + if (cname + 2 == path && cname[0] == '.' && cname[1] == '.') + { + if (dn_new->next) + { + dn_new = dnode_path; + dnode_path = dn_new->next; + grub_free (dn_new); + } + else + { + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, + "can't resolve .."); + break; + } + continue; + } + + ch = *path; + *path = 0; /* ensure null termination */ + + if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS) + { + grub_free (path_buf); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + } + err = zap_lookup (&(dnode_path->dn), cname, &objnum, + data, subvol->case_insensitive); + if (err) + break; + + dn_new = grub_malloc (sizeof (*dn_new)); + if (! dn_new) + { + err = grub_errno; + break; + } + dn_new->next = dnode_path; + dnode_path = dn_new; + + objnum = ZFS_DIRENT_OBJ (objnum); + err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data); + if (err) + break; + + *path = ch; + if (dnode_path->dn.dn.dn_bonustype == DMU_OT_ZNODE + && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa) + { + char *sym_value; + grub_size_t sym_sz; + int free_symval = 0; + char *oldpath = path, *oldpathbuf = path_buf; + sym_value = ((char *) DN_BONUS (&dnode_path->dn.dn) + sizeof (struct znode_phys)); + + sym_sz = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_size, dnode_path->dn.endian); + + if (dnode_path->dn.dn.dn_flags & 1) + { + grub_size_t block; + grub_size_t blksz; + blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, + dnode_path->dn.endian) + << SPA_MINBLOCKSHIFT); + + sym_value = grub_malloc (sym_sz); + if (!sym_value) + return grub_errno; + for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++) + { + void *t; + grub_size_t movesize; + + err = dmu_read (&(dnode_path->dn), block, &t, 0, data); + if (err) + return err; + + movesize = sym_sz - block * blksz; + if (movesize > blksz) + movesize = blksz; + + grub_memcpy (sym_value + block * blksz, t, movesize); + grub_free (t); + } + free_symval = 1; + } + path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); + if (!path_buf) + { + grub_free (oldpathbuf); + return grub_errno; + } + grub_memcpy (path, sym_value, sym_sz); + if (free_symval) + grub_free (sym_value); + path [sym_sz] = 0; + grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); + + grub_free (oldpathbuf); + if (path[0] != '/') + { + dn_new = dnode_path; + dnode_path = dn_new->next; + grub_free (dn_new); + } + else while (dnode_path != root) + { + dn_new = dnode_path; + dnode_path = dn_new->next; + grub_free (dn_new); + } + } + if (dnode_path->dn.dn.dn_bonustype == DMU_OT_SA) + { + void *sahdrp; + int hdrsize; + + if (dnode_path->dn.dn.dn_bonuslen != 0) + { + sahdrp = DN_BONUS (&dnode_path->dn.dn); + } + else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) + { + blkptr_t *bp = &dnode_path->dn.dn.dn_spill; + + err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data); + if (err) + return err; + } + else + { + return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); + } + + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); + + if (((grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + + hdrsize + + SA_TYPE_OFFSET), + dnode_path->dn.endian) >> 12) & 0xf) == 0xa) + { + char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET; + grub_size_t sym_sz = + grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + + hdrsize + + SA_SIZE_OFFSET), + dnode_path->dn.endian); + char *oldpath = path, *oldpathbuf = path_buf; + path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); + if (!path_buf) + { + grub_free (oldpathbuf); + return grub_errno; + } + grub_memcpy (path, sym_value, sym_sz); + path [sym_sz] = 0; + grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); + + grub_free (oldpathbuf); + if (path[0] != '/') + { + dn_new = dnode_path; + dnode_path = dn_new->next; + grub_free (dn_new); + } + else while (dnode_path != root) + { + dn_new = dnode_path; + dnode_path = dn_new->next; + grub_free (dn_new); + } + } + } + } + + if (!err) + grub_memcpy (dn, &(dnode_path->dn), sizeof (*dn)); + + while (dnode_path) + { + dn_new = dnode_path->next; + grub_free (dnode_path); + dnode_path = dn_new; + } + grub_free (path_buf); + return err; +} + +#if 0 +/* + * Get the default 'bootfs' property value from the rootpool. + * + */ +static grub_err_t +get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj, + struct grub_zfs_data *data) +{ + grub_uint64_t objnum = 0; + dnode_phys_t *dn; + if (!dn) + return grub_errno; + + if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, + DMU_OT_OBJECT_DIRECTORY, dn, data))) + { + grub_free (dn); + return (grub_errno); + } + + /* + * find the object number for 'pool_props', and get the dnode + * of the 'pool_props'. + */ + if (zap_lookup (dn, DMU_POOL_PROPS, &objnum, data)) + { + grub_free (dn); + return (GRUB_ERR_BAD_FS); + } + if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, dn, data))) + { + grub_free (dn); + return (grub_errno); + } + if (zap_lookup (dn, ZPOOL_PROP_BOOTFS, &objnum, data)) + { + grub_free (dn); + return (GRUB_ERR_BAD_FS); + } + + if (!objnum) + { + grub_free (dn); + return (GRUB_ERR_BAD_FS); + } + + *obj = objnum; + return (0); +} +#endif +/* + * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname), + * e.g. pool/rootfs, or a given object number (obj), e.g. the object number + * of pool/rootfs. + * + * If no fsname and no obj are given, return the DSL_DIR metadnode. + * If fsname is given, return its metadnode and its matching object number. + * If only obj is given, return the metadnode for this object number. + * + */ +static grub_err_t +get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, + dnode_end_t * mdn, struct grub_zfs_data *data) +{ + grub_uint64_t objnum; + grub_err_t err; + + grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian); + + err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, + DMU_OT_OBJECT_DIRECTORY, mdn, data); + if (err) + return err; + + grub_dprintf ("zfs", "alive\n"); + + err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0); + if (err) + return err; + + grub_dprintf ("zfs", "alive\n"); + + err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data); + if (err) + return err; + + grub_dprintf ("zfs", "alive\n"); + + while (*fsname) + { + grub_uint64_t childobj; + char *cname, ch; + + while (*fsname == '/') + fsname++; + + if (! *fsname || *fsname == '@') + break; + + cname = fsname; + while (*fsname && *fsname != '/') + fsname++; + ch = *fsname; + *fsname = 0; + + childobj = grub_zfs_to_cpu64 ((((dsl_dir_phys_t *) DN_BONUS (&mdn->dn)))->dd_child_dir_zapobj, mdn->endian); + err = dnode_get (mosmdn, childobj, + DMU_OT_DSL_DIR_CHILD_MAP, mdn, data); + if (err) + return err; + + err = zap_lookup (mdn, cname, &objnum, data, 0); + if (err) + return err; + + err = dnode_get (mosmdn, objnum, DMU_OT_DSL_DIR, mdn, data); + if (err) + return err; + + *fsname = ch; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data) +{ + void *osp; + blkptr_t *bp; + grub_size_t ospsize; + grub_err_t err; + + grub_dprintf ("zfs", "endian = %d\n", mdn->endian); + + bp = &(((dsl_dataset_phys_t *) DN_BONUS (&mdn->dn))->ds_bp); + err = zio_read (bp, mdn->endian, &osp, &ospsize, data); + if (err) + return err; + if (ospsize < OBJSET_PHYS_SIZE_V14) + { + grub_free (osp); + return grub_error (GRUB_ERR_BAD_FS, "too small osp"); + } + + mdn->endian = (grub_zfs_to_cpu64 (bp->blk_prop, mdn->endian)>>63) & 1; + grub_memmove ((char *) &(mdn->dn), + (char *) &((objset_phys_t *) osp)->os_meta_dnode, DNODE_SIZE); + grub_free (osp); + return GRUB_ERR_NONE; +} + +static grub_err_t +dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + dnode_end_t * dn, int *isfs, + struct grub_zfs_data *data) +{ + char *fsname, *snapname; + const char *ptr_at, *filename; + grub_uint64_t headobj; + grub_uint64_t keychainobj; + grub_uint64_t salt; + grub_err_t err; + int keyn = 0; + + auto int NESTED_FUNC_ATTR count_zap_keys (const void *name, + grub_size_t namelen, + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize); + int NESTED_FUNC_ATTR count_zap_keys (const void *name __attribute__ ((unused)), + grub_size_t namelen __attribute__ ((unused)), + const void *val_in __attribute__ ((unused)), + grub_size_t nelem __attribute__ ((unused)), + grub_size_t elemsize __attribute__ ((unused))) + { + subvol->nkeys++; + return 0; + } + + auto int NESTED_FUNC_ATTR load_zap_key (const void *name, + grub_size_t namelen, + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize); + int NESTED_FUNC_ATTR load_zap_key (const void *name, + grub_size_t namelen, + const void *val_in, + grub_size_t nelem, + grub_size_t elemsize) + { + if (namelen != 1) + { + grub_dprintf ("zfs", "Unexpected key index size %" PRIuGRUB_SIZE "\n", + namelen); + return 0; + } + + if (elemsize != 1) + { + grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n", + elemsize); + return 0; + } + + subvol->keyring[keyn].txg = grub_be_to_cpu64 (*(grub_uint64_t *) name); + subvol->keyring[keyn].algo = grub_le_to_cpu64 (*(grub_uint64_t *) val_in); + subvol->keyring[keyn].cipher = grub_zfs_load_key (val_in, nelem, salt, + subvol->keyring[keyn].algo); + keyn++; + return 0; + } + + ptr_at = grub_strchr (fullpath, '@'); + if (! ptr_at) + { + *isfs = 1; + filename = 0; + snapname = 0; + fsname = grub_strdup (fullpath); + } + else + { + const char *ptr_slash = grub_strchr (ptr_at, '/'); + + *isfs = 0; + fsname = grub_malloc (ptr_at - fullpath + 1); + if (!fsname) + return grub_errno; + grub_memcpy (fsname, fullpath, ptr_at - fullpath); + fsname[ptr_at - fullpath] = 0; + if (ptr_at[1] && ptr_at[1] != '/') + { + snapname = grub_malloc (ptr_slash - ptr_at); + if (!snapname) + { + grub_free (fsname); + return grub_errno; + } + grub_memcpy (snapname, ptr_at + 1, ptr_slash - ptr_at - 1); + snapname[ptr_slash - ptr_at - 1] = 0; + } + else + snapname = 0; + if (ptr_slash) + filename = ptr_slash; + else + filename = "/"; + grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n", + fsname, snapname, filename); + } + grub_dprintf ("zfs", "alive\n"); + err = get_filesystem_dnode (&(data->mos), fsname, dn, data); + if (err) + { + grub_free (fsname); + grub_free (snapname); + return err; + } + + grub_dprintf ("zfs", "alive\n"); + + headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_head_dataset_obj, dn->endian); + + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); + + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &subvol->mdn, + data); + if (err) + { + grub_free (fsname); + grub_free (snapname); + return err; + } + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); + + keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian); + if (grub_zfs_load_key && keychainobj) + { + dnode_end_t keychain_dn, props_dn; + grub_uint64_t propsobj; + propsobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->dd_props_zapobj, dn->endian); + + err = dnode_get (&(data->mos), propsobj, DMU_OT_DSL_PROPS, + &props_dn, data); + if (err) + { + grub_free (fsname); + grub_free (snapname); + return err; + } + + err = zap_lookup (&props_dn, "salt", &salt, data, 0); + if (err == GRUB_ERR_FILE_NOT_FOUND) + { + err = 0; + grub_errno = 0; + salt = 0; + } + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } + + err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN, + &keychain_dn, data); + if (err) + { + grub_free (fsname); + grub_free (snapname); + return err; + } + subvol->nkeys = 0; + zap_iterate (&keychain_dn, 8, count_zap_keys, data); + subvol->keyring = grub_zalloc (subvol->nkeys * sizeof (subvol->keyring[0])); + if (!subvol->keyring) + { + grub_free (fsname); + grub_free (snapname); + return err; + } + zap_iterate (&keychain_dn, 8, load_zap_key, data); + } + + if (snapname) + { + grub_uint64_t snapobj; + + snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian); + + err = dnode_get (&(data->mos), snapobj, + DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data); + if (!err) + err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0); + if (!err) + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, + &subvol->mdn, data); + if (err) + { + grub_free (fsname); + grub_free (snapname); + return err; + } + } + + subvol->obj = headobj; + + make_mdn (&subvol->mdn, data); + + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); + + if (*isfs) + { + grub_free (fsname); + grub_free (snapname); + return GRUB_ERR_NONE; + } + err = dnode_get_path (subvol, filename, dn, data); + grub_free (fsname); + grub_free (snapname); + return err; +} + +/* + * For a given XDR packed nvlist, verify the first 4 bytes and move on. + * + * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : + * + * encoding method/host endian (4 bytes) + * nvl_version (4 bytes) + * nvl_nvflag (4 bytes) + * encoded nvpairs: + * encoded size of the nvpair (4 bytes) + * decoded size of the nvpair (4 bytes) + * name string size (4 bytes) + * name string data (sizeof(NV_ALIGN4(string)) + * data type (4 bytes) + * # of elements in the nvpair (4 bytes) + * data + * 2 zero's for the last nvpair + * (end of the entire list) (8 bytes) + * + */ + +static int +nvlist_find_value (const char *nvlist_in, const char *name, + int valtype, char **val, + grub_size_t *size_out, grub_size_t *nelm_out) +{ + int name_len, type, encode_size; + const char *nvpair, *nvp_name, *nvlist = nvlist_in; + + /* Verify if the 1st and 2nd byte in the nvlist are valid. */ + /* NOTE: independently of what endianness header announces all + subsequent values are big-endian. */ + if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN + && nvlist[1] != NV_BIG_ENDIAN)) + { + grub_dprintf ("zfs", "incorrect nvlist header\n"); + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); + return 0; + } + + /* skip the header, nvl_version, and nvl_nvflag */ + nvlist = nvlist + 4 * 3; + /* + * Loop thru the nvpair list + * The XDR representation of an integer is in big-endian byte order. + */ + while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist)))) + { + int nelm; + + if (nvlist + 4 * 4 >= nvlist_in + VDEV_PHYS_SIZE) + { + grub_dprintf ("zfs", "nvlist overflow\n"); + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); + return 0; + } + + nvpair = nvlist + 4 * 2; /* skip the encode/decode size */ + + name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); + nvpair += 4; + + nvp_name = nvpair; + nvpair = nvpair + ((name_len + 3) & ~3); /* align */ + + if (nvpair + 8 >= nvlist_in + VDEV_PHYS_SIZE + || encode_size < 0 + || nvpair + 8 + encode_size > nvlist_in + VDEV_PHYS_SIZE) + { + grub_dprintf ("zfs", "nvlist overflow\n"); + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); + return 0; + } + + type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); + nvpair += 4; + + nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); + if (nelm < 1) + return grub_error (GRUB_ERR_BAD_FS, "empty nvpair"); + + nvpair += 4; + + if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) + { + *val = (char *) nvpair; + *size_out = encode_size; + if (nelm_out) + *nelm_out = nelm; + return 1; + } + + nvlist += encode_size; /* goto the next nvpair */ + } + return 0; +} + +int +grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name, + grub_uint64_t * out) +{ + char *nvpair; + grub_size_t size; + int found; + + found = nvlist_find_value (nvlist, name, DATA_TYPE_UINT64, &nvpair, &size, 0); + if (!found) + return 0; + if (size < sizeof (grub_uint64_t)) + { + grub_error (GRUB_ERR_BAD_FS, "invalid uint64"); + return 0; + } + + *out = grub_be_to_cpu64 (grub_get_unaligned64 (nvpair)); + return 1; +} + +char * +grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name) +{ + char *nvpair; + char *ret; + grub_size_t slen; + grub_size_t size; + int found; + + found = nvlist_find_value (nvlist, name, DATA_TYPE_STRING, &nvpair, &size, 0); + if (!found) + return 0; + if (size < 4) + { + grub_error (GRUB_ERR_BAD_FS, "invalid string"); + return 0; + } + slen = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); + if (slen > size - 4) + slen = size - 4; + ret = grub_malloc (slen + 1); + if (!ret) + return 0; + grub_memcpy (ret, nvpair + 4, slen); + ret[slen] = 0; + return ret; +} + +char * +grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name) +{ + char *nvpair; + char *ret; + grub_size_t size; + int found; + + found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair, + &size, 0); + if (!found) + return 0; + ret = grub_zalloc (size + 3 * sizeof (grub_uint32_t)); + if (!ret) + return 0; + grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); + + grub_memcpy (ret + sizeof (grub_uint32_t), nvpair, size); + return ret; +} + +int +grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist, + const char *name) +{ + char *nvpair; + grub_size_t nelm, size; + int found; + + found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, + &size, &nelm); + if (! found) + return -1; + return nelm; +} + +static int +get_nvlist_size (const char *beg, const char *limit) +{ + const char *ptr; + grub_uint32_t encode_size; + + ptr = beg + 8; + + while (ptr < limit + && (encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (ptr)))) + ptr += encode_size; /* goto the next nvpair */ + ptr += 8; + return (ptr > limit) ? -1 : (ptr - beg); +} + +char * +grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, + grub_size_t index) +{ + char *nvpair, *nvpairptr; + int found; + char *ret; + grub_size_t size; + unsigned i; + grub_size_t nelm; + int elemsize = 0; + + found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, + &size, &nelm); + if (!found) + return 0; + if (index >= nelm) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "trying to lookup past nvlist array"); + return 0; + } + + nvpairptr = nvpair; + + for (i = 0; i < index; i++) + { + int r; + r = get_nvlist_size (nvpairptr, nvpair + size); + + if (r < 0) + { + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); + return NULL; + } + nvpairptr += r; + } + + elemsize = get_nvlist_size (nvpairptr, nvpair + size); + + if (elemsize < 0) + { + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); + return 0; + } + + ret = grub_zalloc (elemsize + sizeof (grub_uint32_t)); + if (!ret) + return 0; + grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); + + grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize); + return ret; +} + +static void +unmount_device (struct grub_zfs_device_desc *desc) +{ + unsigned i; + switch (desc->type) + { + case DEVICE_LEAF: + if (!desc->original && desc->dev) + grub_device_close (desc->dev); + return; + case DEVICE_RAIDZ: + case DEVICE_MIRROR: + for (i = 0; i < desc->n_children; i++) + unmount_device (&desc->children[i]); + grub_free (desc->children); + return; + } +} + +static void +zfs_unmount (struct grub_zfs_data *data) +{ + unsigned i; + for (i = 0; i < data->n_devices_attached; i++) + unmount_device (&data->devices_attached[i]); + grub_free (data->devices_attached); + grub_free (data->dnode_buf); + grub_free (data->dnode_mdn); + grub_free (data->file_buf); + for (i = 0; i < data->subvol.nkeys; i++) + grub_crypto_cipher_close (data->subvol.keyring[i].cipher); + grub_free (data->subvol.keyring); + grub_free (data); +} + +/* + * zfs_mount() locates a valid uberblock of the root pool and read in its MOS + * to the memory address MOS. + * + */ +static struct grub_zfs_data * +zfs_mount (grub_device_t dev) +{ + struct grub_zfs_data *data = 0; + grub_err_t err; + void *osp = 0; + grub_size_t ospsize; + grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; + uberblock_t *ub; + int inserted; + + if (! dev->disk) + { + grub_error (GRUB_ERR_BAD_DEVICE, "not a disk"); + return 0; + } + + data = grub_zalloc (sizeof (*data)); + if (!data) + return 0; +#if 0 + /* if it's our first time here, zero the best uberblock out */ + if (data->best_drive == 0 && data->best_part == 0 && find_best_root) + grub_memset (¤t_uberblock, 0, sizeof (uberblock_t)); +#endif + + data->n_devices_allocated = 16; + data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) + * data->n_devices_allocated); + data->n_devices_attached = 0; + err = scan_disk (dev, data, 1, &inserted); + if (err) + { + zfs_unmount (data); + return NULL; + } + + ub = &(data->current_uberblock); + ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, + GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); + + err = zio_read (&ub->ub_rootbp, ub_endian, + &osp, &ospsize, data); + if (err) + { + zfs_unmount (data); + return NULL; + } + + if (ospsize < OBJSET_PHYS_SIZE_V14) + { + grub_error (GRUB_ERR_BAD_FS, "OSP too small"); + grub_free (osp); + zfs_unmount (data); + return NULL; + } + + /* Got the MOS. Save it at the memory addr MOS. */ + grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode, + DNODE_SIZE); + data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop, + ub_endian) >> 63) & 1; + grub_free (osp); + + data->mounted = 1; + + return data; +} + +grub_err_t +grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist) +{ + struct grub_zfs_data *zfs; + grub_err_t err; + + zfs = zfs_mount (dev); + if (!zfs) + return grub_errno; + err = zfs_fetch_nvlist (zfs->device_original, nvlist); + zfs_unmount (zfs); + return err; +} + +static grub_err_t +zfs_label (grub_device_t device, char **label) +{ + char *nvlist; + grub_err_t err; + struct grub_zfs_data *data; + + data = zfs_mount (device); + if (! data) + return grub_errno; + + err = zfs_fetch_nvlist (data->device_original, &nvlist); + if (err) + { + zfs_unmount (data); + return err; + } + + *label = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); + grub_free (nvlist); + zfs_unmount (data); + return grub_errno; +} + +static grub_err_t +zfs_uuid (grub_device_t device, char **uuid) +{ + struct grub_zfs_data *data; + + *uuid = 0; + + data = zfs_mount (device); + if (! data) + return grub_errno; + + *uuid = grub_xasprintf ("%016llx", (long long unsigned) data->guid); + zfs_unmount (data); + if (! *uuid) + return grub_errno; + return GRUB_ERR_NONE; +} + +static grub_err_t +zfs_mtime (grub_device_t device, grub_int32_t *mt) +{ + struct grub_zfs_data *data; + grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; + uberblock_t *ub; + + *mt = 0; + + data = zfs_mount (device); + if (! data) + return grub_errno; + + ub = &(data->current_uberblock); + ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, + GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); + + *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian); + zfs_unmount (data); + return GRUB_ERR_NONE; +} + +/* + * zfs_open() locates a file in the rootpool by following the + * MOS and places the dnode of the file in the memory address DNODE. + */ +static grub_err_t +grub_zfs_open (struct grub_file *file, const char *fsfilename) +{ + struct grub_zfs_data *data; + grub_err_t err; + int isfs; + + data = zfs_mount (file->device); + if (! data) + return grub_errno; + + err = dnode_get_fullpath (fsfilename, &(data->subvol), + &(data->dnode), &isfs, data); + if (err) + { + zfs_unmount (data); + return err; + } + + if (isfs) + { + zfs_unmount (data); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "Missing @ or / separator"); + } + + /* We found the dnode for this file. Verify if it is a plain file. */ + if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS) + { + zfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a file"); + } + + /* get the file size and set the file position to 0 */ + + /* + * For DMU_OT_SA we will need to locate the SIZE attribute + * attribute, which could be either in the bonus buffer + * or the "spill" block. + */ + if (data->dnode.dn.dn_bonustype == DMU_OT_SA) + { + void *sahdrp; + int hdrsize; + + if (data->dnode.dn.dn_bonuslen != 0) + { + sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn); + } + else if (data->dnode.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) + { + blkptr_t *bp = &data->dnode.dn.dn_spill; + + err = zio_read (bp, data->dnode.endian, &sahdrp, NULL, data); + if (err) + return err; + } + else + { + return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); + } + + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); + file->size = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian); + } + else if (data->dnode.dn.dn_bonustype == DMU_OT_ZNODE) + { + file->size = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&data->dnode.dn))->zp_size, data->dnode.endian); + } + else + return grub_error (GRUB_ERR_BAD_FS, "bad bonus type"); + + file->data = data; + file->offset = 0; + +#ifndef GRUB_UTIL + grub_dl_ref (my_mod); +#endif + + return GRUB_ERR_NONE; +} + +static grub_ssize_t +grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_zfs_data *data = (struct grub_zfs_data *) file->data; + grub_size_t blksz, movesize; + grub_size_t length; + grub_size_t read; + grub_err_t err; + + /* + * If offset is in memory, move it into the buffer provided and return. + */ + if (file->offset >= data->file_start + && file->offset + len <= data->file_end) + { + grub_memmove (buf, data->file_buf + file->offset - data->file_start, + len); + return len; + } + + blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec, + data->dnode.endian) << SPA_MINBLOCKSHIFT; + + /* + * Entire Dnode is too big to fit into the space available. We + * will need to read it in chunks. This could be optimized to + * read in as large a chunk as there is space available, but for + * now, this only reads in one data block at a time. + */ + length = len; + read = 0; + while (length) + { + void *t; + /* + * Find requested blkid and the offset within that block. + */ + grub_uint64_t blkid = grub_divmod64 (file->offset + read, blksz, 0); + grub_free (data->file_buf); + data->file_buf = 0; + + err = dmu_read (&(data->dnode), blkid, &t, + 0, data); + data->file_buf = t; + if (err) + { + data->file_buf = NULL; + data->file_start = data->file_end = 0; + return -1; + } + + data->file_start = blkid * blksz; + data->file_end = data->file_start + blksz; + + movesize = data->file_end - file->offset - read; + if (movesize > length) + movesize = length; + + grub_memmove (buf, data->file_buf + file->offset + read + - data->file_start, movesize); + buf += movesize; + length -= movesize; + read += movesize; + } + + return len; +} + +static grub_err_t +grub_zfs_close (grub_file_t file) +{ + zfs_unmount ((struct grub_zfs_data *) file->data); + +#ifndef GRUB_UTIL + grub_dl_unref (my_mod); +#endif + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename, + grub_uint64_t *mdnobj) +{ + struct grub_zfs_data *data; + grub_err_t err; + int isfs; + + data = zfs_mount (dev); + if (! data) + return grub_errno; + + err = dnode_get_fullpath (fsfilename, &(data->subvol), + &(data->dnode), &isfs, data); + *mdnobj = data->subvol.obj; + zfs_unmount (data); + return err; +} + +static void +fill_fs_info (struct grub_dirhook_info *info, + dnode_end_t mdn, struct grub_zfs_data *data) +{ + grub_err_t err; + dnode_end_t dn; + grub_uint64_t objnum; + grub_uint64_t headobj; + + grub_memset (info, 0, sizeof (*info)); + + info->dir = 1; + + if (mdn.dn.dn_type == DMU_OT_DSL_DIR) + { + headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian); + + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &mdn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return; + } + } + make_mdn (&mdn, data); + err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + &dn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return; + } + + err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return; + } + + err = dnode_get (&mdn, objnum, 0, &dn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return; + } + + if (dn.dn.dn_bonustype == DMU_OT_SA) + { + void *sahdrp; + int hdrsize; + + if (dn.dn.dn_bonuslen != 0) + { + sahdrp = (sa_hdr_phys_t *) DN_BONUS (&dn.dn); + } + else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) + { + blkptr_t *bp = &dn.dn.dn_spill; + + err = zio_read (bp, dn.endian, &sahdrp, NULL, data); + if (err) + return; + } + else + { + grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); + return; + } + + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); + info->mtimeset = 1; + info->mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); + } + + if (dn.dn.dn_bonustype == DMU_OT_ZNODE) + { + info->mtimeset = 1; + info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian); + } + return; +} + +static grub_err_t +grub_zfs_dir (grub_device_t device, const char *path, + int (*hook) (const char *, const struct grub_dirhook_info *)) +{ + struct grub_zfs_data *data; + grub_err_t err; + int isfs; + auto int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val); + auto int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, + grub_uint64_t val); + auto int NESTED_FUNC_ATTR iterate_zap_snap (const char *name, + grub_uint64_t val); + + int NESTED_FUNC_ATTR iterate_zap (const char *name, grub_uint64_t val) + { + struct grub_dirhook_info info; + dnode_end_t dn; + grub_memset (&info, 0, sizeof (info)); + + dnode_get (&(data->subvol.mdn), val, 0, &dn, data); + + if (dn.dn.dn_bonustype == DMU_OT_SA) + { + void *sahdrp; + int hdrsize; + + if (dn.dn.dn_bonuslen != 0) + { + sahdrp = (sa_hdr_phys_t *) DN_BONUS (&data->dnode.dn); + } + else if (dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) + { + blkptr_t *bp = &dn.dn.dn_spill; + + err = zio_read (bp, dn.endian, &sahdrp, NULL, data); + if (err) + { + grub_print_error (); + return 0; + } + } + else + { + grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt"); + grub_print_error (); + return 0; + } + + hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); + info.mtimeset = 1; + info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); + info.case_insensitive = data->subvol.case_insensitive; + } + + if (dn.dn.dn_bonustype == DMU_OT_ZNODE) + { + info.mtimeset = 1; + info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], + dn.endian); + } + info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); + grub_dprintf ("zfs", "type=%d, name=%s\n", + (int)dn.dn.dn_type, (char *)name); + return hook (name, &info); + } + + int NESTED_FUNC_ATTR iterate_zap_fs (const char *name, grub_uint64_t val) + { + struct grub_dirhook_info info; + dnode_end_t mdn; + err = dnode_get (&(data->mos), val, 0, &mdn, data); + if (err) + return 0; + if (mdn.dn.dn_type != DMU_OT_DSL_DIR) + return 0; + + fill_fs_info (&info, mdn, data); + return hook (name, &info); + } + int NESTED_FUNC_ATTR iterate_zap_snap (const char *name, grub_uint64_t val) + { + struct grub_dirhook_info info; + char *name2; + int ret; + dnode_end_t mdn; + + err = dnode_get (&(data->mos), val, 0, &mdn, data); + if (err) + return 0; + + if (mdn.dn.dn_type != DMU_OT_DSL_DATASET) + return 0; + + fill_fs_info (&info, mdn, data); + + name2 = grub_malloc (grub_strlen (name) + 2); + name2[0] = '@'; + grub_memcpy (name2 + 1, name, grub_strlen (name) + 1); + ret = hook (name2, &info); + grub_free (name2); + return ret; + } + + data = zfs_mount (device); + if (! data) + return grub_errno; + err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data); + if (err) + { + zfs_unmount (data); + return err; + } + if (isfs) + { + grub_uint64_t childobj, headobj; + grub_uint64_t snapobj; + dnode_end_t dn; + struct grub_dirhook_info info; + + fill_fs_info (&info, data->dnode, data); + hook ("@", &info); + + childobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_child_dir_zapobj, data->dnode.endian); + headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&data->dnode.dn))->dd_head_dataset_obj, data->dnode.endian); + err = dnode_get (&(data->mos), childobj, + DMU_OT_DSL_DIR_CHILD_MAP, &dn, data); + if (err) + { + zfs_unmount (data); + return err; + } + + zap_iterate_u64 (&dn, iterate_zap_fs, data); + + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data); + if (err) + { + zfs_unmount (data); + return err; + } + + snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&dn.dn))->ds_snapnames_zapobj, dn.endian); + + err = dnode_get (&(data->mos), snapobj, + DMU_OT_DSL_DS_SNAP_MAP, &dn, data); + if (err) + { + zfs_unmount (data); + return err; + } + + zap_iterate_u64 (&dn, iterate_zap_snap, data); + } + else + { + if (data->dnode.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS) + { + zfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); + } + zap_iterate_u64 (&(data->dnode), iterate_zap, data); + } + zfs_unmount (data); + return grub_errno; +} + +#ifdef GRUB_UTIL +static grub_err_t +grub_zfs_embed (grub_device_t device __attribute__ ((unused)), + unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) +{ + unsigned i; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "ZFS currently supports only PC-BIOS embedding"); + + if ((VDEV_BOOT_SIZE >> GRUB_DISK_SECTOR_BITS) < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your core.img is unusually large. " + "It won't fit in the embedding area."); + + *nsectors = (VDEV_BOOT_SIZE >> GRUB_DISK_SECTOR_BITS); + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = i + (VDEV_BOOT_OFFSET >> GRUB_DISK_SECTOR_BITS); + + return GRUB_ERR_NONE; +} +#endif + +static struct grub_fs grub_zfs_fs = { + .name = "zfs", + .dir = grub_zfs_dir, + .open = grub_zfs_open, + .read = grub_zfs_read, + .close = grub_zfs_close, + .label = zfs_label, + .uuid = zfs_uuid, + .mtime = zfs_mtime, +#ifdef GRUB_UTIL + .embed = grub_zfs_embed, + .reserved_first_sector = 1, +#endif + .next = 0 +}; + +GRUB_MOD_INIT (zfs) +{ + COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE); + grub_fs_register (&grub_zfs_fs); +#ifndef GRUB_UTIL + my_mod = mod; +#endif +} + +GRUB_MOD_FINI (zfs) +{ + grub_fs_unregister (&grub_zfs_fs); +} diff --git a/grub-core/fs/zfs/zfs_fletcher.c b/grub-core/fs/zfs/zfs_fletcher.c new file mode 100644 index 000000000..7d27b053d --- /dev/null +++ b/grub-core/fs/zfs/zfs_fletcher.c @@ -0,0 +1,84 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc. + * Copyright 2007 Sun Microsystems, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void +fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + zio_cksum_t *zcp) +{ + const grub_uint64_t *ip = buf; + const grub_uint64_t *ipend = ip + (size / sizeof (grub_uint64_t)); + grub_uint64_t a0, b0, a1, b1; + + for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) + { + a0 += grub_zfs_to_cpu64 (ip[0], endian); + a1 += grub_zfs_to_cpu64 (ip[1], endian); + b0 += a0; + b1 += a1; + } + + zcp->zc_word[0] = grub_cpu_to_zfs64 (a0, endian); + zcp->zc_word[1] = grub_cpu_to_zfs64 (a1, endian); + zcp->zc_word[2] = grub_cpu_to_zfs64 (b0, endian); + zcp->zc_word[3] = grub_cpu_to_zfs64 (b1, endian); +} + +void +fletcher_4 (const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + zio_cksum_t *zcp) +{ + const grub_uint32_t *ip = buf; + const grub_uint32_t *ipend = ip + (size / sizeof (grub_uint32_t)); + grub_uint64_t a, b, c, d; + + for (a = b = c = d = 0; ip < ipend; ip++) + { + a += grub_zfs_to_cpu32 (ip[0], endian);; + b += a; + c += b; + d += c; + } + + zcp->zc_word[0] = grub_cpu_to_zfs64 (a, endian); + zcp->zc_word[1] = grub_cpu_to_zfs64 (b, endian); + zcp->zc_word[2] = grub_cpu_to_zfs64 (c, endian); + zcp->zc_word[3] = grub_cpu_to_zfs64 (d, endian); +} + diff --git a/grub-core/fs/zfs/zfs_lzjb.c b/grub-core/fs/zfs/zfs_lzjb.c new file mode 100644 index 000000000..62b5ea6a0 --- /dev/null +++ b/grub-core/fs/zfs/zfs_lzjb.c @@ -0,0 +1,93 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc. + * Copyright 2007 Sun Microsystems, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MATCH_BITS 6 +#define MATCH_MIN 3 +#define OFFSET_MASK ((1 << (16 - MATCH_BITS)) - 1) + +/* + * Decompression Entry - lzjb + */ +#ifndef NBBY +#define NBBY 8 +#endif + +grub_err_t +lzjb_decompress (void *s_start, void *d_start, grub_size_t s_len, + grub_size_t d_len); + +grub_err_t +lzjb_decompress (void *s_start, void *d_start, grub_size_t s_len, + grub_size_t d_len) +{ + grub_uint8_t *src = s_start; + grub_uint8_t *dst = d_start; + grub_uint8_t *d_end = (grub_uint8_t *) d_start + d_len; + grub_uint8_t *s_end = (grub_uint8_t *) s_start + s_len; + grub_uint8_t *cpy, copymap = 0; + int copymask = 1 << (NBBY - 1); + + while (dst < d_end && src < s_end) + { + if ((copymask <<= 1) == (1 << NBBY)) + { + copymask = 1; + copymap = *src++; + } + if (src >= s_end) + return grub_error (GRUB_ERR_BAD_FS, "lzjb decompression failed"); + if (copymap & copymask) + { + int mlen = (src[0] >> (NBBY - MATCH_BITS)) + MATCH_MIN; + int offset = ((src[0] << NBBY) | src[1]) & OFFSET_MASK; + src += 2; + cpy = dst - offset; + if (src > s_end || cpy < (grub_uint8_t *) d_start) + return grub_error (GRUB_ERR_BAD_FS, "lzjb decompression failed"); + while (--mlen >= 0 && dst < d_end) + *dst++ = *cpy++; + } + else + *dst++ = *src++; + } + if (dst < d_end) + return grub_error (GRUB_ERR_BAD_FS, "lzjb decompression failed"); + return GRUB_ERR_NONE; +} diff --git a/grub-core/fs/zfs/zfs_sha256.c b/grub-core/fs/zfs/zfs_sha256.c new file mode 100644 index 000000000..ba510cf69 --- /dev/null +++ b/grub-core/fs/zfs/zfs_sha256.c @@ -0,0 +1,143 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc. + * Copyright 2007 Sun Microsystems, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * SHA-256 checksum, as specified in FIPS 180-2, available at: + * http://csrc.nist.gov/cryptval + * + * This is a very compact implementation of SHA-256. + * It is designed to be simple and portable, not to be fast. + */ + +/* + * The literal definitions according to FIPS180-2 would be: + * + * Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) + * Maj(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) + * + * We use logical equivalents which require one less op. + */ +#define Ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x, y, z) (((x) & (y)) ^ ((z) & ((x) ^ (y)))) +#define Rot32(x, s) (((x) >> s) | ((x) << (32 - s))) +#define SIGMA0(x) (Rot32(x, 2) ^ Rot32(x, 13) ^ Rot32(x, 22)) +#define SIGMA1(x) (Rot32(x, 6) ^ Rot32(x, 11) ^ Rot32(x, 25)) +#define sigma0(x) (Rot32(x, 7) ^ Rot32(x, 18) ^ ((x) >> 3)) +#define sigma1(x) (Rot32(x, 17) ^ Rot32(x, 19) ^ ((x) >> 10)) + +static const grub_uint32_t SHA256_K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static void +SHA256Transform(grub_uint32_t *H, const grub_uint8_t *cp) +{ + grub_uint32_t a, b, c, d, e, f, g, h, t, T1, T2, W[64]; + + for (t = 0; t < 16; t++, cp += 4) + W[t] = (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | cp[3]; + + for (t = 16; t < 64; t++) + W[t] = sigma1(W[t - 2]) + W[t - 7] + + sigma0(W[t - 15]) + W[t - 16]; + + a = H[0]; b = H[1]; c = H[2]; d = H[3]; + e = H[4]; f = H[5]; g = H[6]; h = H[7]; + + for (t = 0; t < 64; t++) { + T1 = h + SIGMA1(e) + Ch(e, f, g) + SHA256_K[t] + W[t]; + T2 = SIGMA0(a) + Maj(a, b, c); + h = g; g = f; f = e; e = d + T1; + d = c; c = b; b = a; a = T1 + T2; + } + + H[0] += a; H[1] += b; H[2] += c; H[3] += d; + H[4] += e; H[5] += f; H[6] += g; H[7] += h; +} + +void +zio_checksum_SHA256(const void *buf, grub_uint64_t size, + grub_zfs_endian_t endian, zio_cksum_t *zcp) +{ + grub_uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; + grub_uint8_t pad[128]; + unsigned padsize = size & 63; + unsigned i; + + for (i = 0; i < size - padsize; i += 64) + SHA256Transform(H, (grub_uint8_t *)buf + i); + + for (i = 0; i < padsize; i++) + pad[i] = ((grub_uint8_t *)buf)[i]; + + for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++) + pad[padsize] = 0; + + for (i = 0; i < 8; i++) + pad[padsize++] = (size << 3) >> (56 - 8 * i); + + for (i = 0; i < padsize; i += 64) + SHA256Transform(H, pad + i); + + zcp->zc_word[0] = grub_cpu_to_zfs64 ((grub_uint64_t)H[0] << 32 | H[1], + endian); + zcp->zc_word[1] = grub_cpu_to_zfs64 ((grub_uint64_t)H[2] << 32 | H[3], + endian); + zcp->zc_word[2] = grub_cpu_to_zfs64 ((grub_uint64_t)H[4] << 32 | H[5], + endian); + zcp->zc_word[3] = grub_cpu_to_zfs64 ((grub_uint64_t)H[6] << 32 | H[7], + endian); +} diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c new file mode 100644 index 000000000..63380f66a --- /dev/null +++ b/grub-core/fs/zfs/zfscrypt.c @@ -0,0 +1,473 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +enum grub_zfs_algo + { + GRUB_ZFS_ALGO_CCM, + GRUB_ZFS_ALGO_GCM, + }; + +struct grub_zfs_key +{ + grub_uint64_t algo; + grub_uint8_t enc_nonce[13]; + grub_uint8_t unused[3]; + grub_uint8_t enc_key[48]; + grub_uint8_t unknown_purpose_nonce[13]; + grub_uint8_t unused2[3]; + grub_uint8_t unknown_purpose_key[48]; +}; + +struct grub_zfs_wrap_key +{ + struct grub_zfs_wrap_key *next; + grub_size_t keylen; + int is_passphrase; + grub_uint64_t key[0]; +}; + +static struct grub_zfs_wrap_key *zfs_wrap_keys; + +grub_err_t +grub_zfs_add_key (grub_uint8_t *key_in, + grub_size_t keylen, + int passphrase) +{ + struct grub_zfs_wrap_key *key; + if (!passphrase && keylen > 32) + keylen = 32; + key = grub_malloc (sizeof (*key) + keylen); + if (!key) + return grub_errno; + key->is_passphrase = passphrase; + key->keylen = keylen; + grub_memcpy (key->key, key_in, keylen); + key->next = zfs_wrap_keys; + zfs_wrap_keys = key; + return GRUB_ERR_NONE; +} + +static gcry_err_code_t +grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher, + grub_uint8_t *out, const grub_uint8_t *in, + grub_size_t psize, + void *mac_out, const void *nonce, + unsigned l, unsigned m) +{ + grub_uint8_t iv[16]; + grub_uint8_t mul[16]; + grub_uint32_t mac[4]; + unsigned i, j; + gcry_err_code_t err; + + grub_memcpy (iv + 1, nonce, 15 - l); + + iv[0] = (l - 1) | (((m-2) / 2) << 3); + for (j = 0; j < l; j++) + iv[15 - j] = psize >> (8 * j); + err = grub_crypto_ecb_encrypt (cipher, mac, iv, 16); + if (err) + return err; + + iv[0] = l - 1; + + for (i = 0; i < (psize + 15) / 16; i++) + { + grub_size_t csize; + csize = 16; + if (csize > psize - 16 * i) + csize = psize - 16 * i; + for (j = 0; j < l; j++) + iv[15 - j] = (i + 1) >> (8 * j); + err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); + if (err) + return err; + grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize); + grub_crypto_xor (mac, mac, out + 16 * i, csize); + err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16); + if (err) + return err; + } + for (j = 0; j < l; j++) + iv[15 - j] = 0; + err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); + if (err) + return err; + if (mac_out) + grub_crypto_xor (mac_out, mac, mul, m); + return GRUB_ERR_NONE; +} + +static void +grub_gcm_mul_x (grub_uint8_t *a) +{ + int i; + int c = 0, d = 0; + for (i = 0; i < 16; i++) + { + c = a[i] & 0x1; + a[i] = (a[i] >> 1) | (d << 7); + d = c; + } + if (d) + a[0] ^= 0xe1; +} + +static void +grub_gcm_mul (grub_uint8_t *a, const grub_uint8_t *b) +{ + grub_uint8_t res[16], bs[16]; + int i; + grub_memcpy (bs, b, 16); + grub_memset (res, 0, 16); + for (i = 0; i < 128; i++) + { + if ((a[i / 8] << (i % 8)) & 0x80) + grub_crypto_xor (res, res, bs, 16); + grub_gcm_mul_x (bs); + } + + grub_memcpy (a, res, 16); +} + +static gcry_err_code_t +grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher, + grub_uint8_t *out, const grub_uint8_t *in, + grub_size_t psize, + void *mac_out, const void *nonce, + unsigned nonce_len, unsigned m) +{ + grub_uint8_t iv[16]; + grub_uint8_t mul[16]; + grub_uint8_t mac[16], h[16], mac_xor[16]; + unsigned i, j; + gcry_err_code_t err; + + grub_memset (mac, 0, sizeof (mac)); + + err = grub_crypto_ecb_encrypt (cipher, h, mac, 16); + if (err) + return err; + + if (nonce_len == 12) + { + grub_memcpy (iv, nonce, 12); + iv[12] = 0; + iv[13] = 0; + iv[14] = 0; + iv[15] = 1; + } + else + { + grub_memset (iv, 0, sizeof (iv)); + grub_memcpy (iv, nonce, nonce_len); + grub_gcm_mul (iv, h); + iv[15] ^= nonce_len * 8; + grub_gcm_mul (iv, h); + } + + err = grub_crypto_ecb_encrypt (cipher, mac_xor, iv, 16); + if (err) + return err; + + for (i = 0; i < (psize + 15) / 16; i++) + { + grub_size_t csize; + csize = 16; + if (csize > psize - 16 * i) + csize = psize - 16 * i; + for (j = 0; j < 4; j++) + { + iv[15 - j]++; + if (iv[15 - j] != 0) + break; + } + grub_crypto_xor (mac, mac, in + 16 * i, csize); + grub_gcm_mul (mac, h); + err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); + if (err) + return err; + grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize); + } + for (j = 0; j < 8; j++) + mac[15 - j] ^= ((psize * 8) >> (8 * j)); + grub_gcm_mul (mac, h); + + if (mac_out) + grub_crypto_xor (mac_out, mac, mac_xor, m); + + return GRUB_ERR_NONE; +} + + +static gcry_err_code_t +algo_decrypt (grub_crypto_cipher_handle_t cipher, grub_uint64_t algo, + grub_uint8_t *out, const grub_uint8_t *in, + grub_size_t psize, + void *mac_out, const void *nonce, + unsigned l, unsigned m) +{ + switch (algo) + { + case 0: + return grub_ccm_decrypt (cipher, out, in, psize, mac_out, nonce, l, m); + case 1: + return grub_gcm_decrypt (cipher, out, in, psize, mac_out, nonce, + 15 - l, m); + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "algorithm %" + PRIuGRUB_UINT64_T " is not supported yet", algo); + } +} + +static grub_err_t +grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + grub_uint64_t algo, + void *nonce, + char *buf, grub_size_t size, + const grub_uint32_t *expected_mac, + grub_zfs_endian_t endian) +{ + grub_uint32_t mac[4]; + unsigned i; + grub_uint32_t sw[4]; + grub_err_t err; + + grub_memcpy (sw, nonce, 16); + if (endian != GRUB_ZFS_BIG_ENDIAN) + for (i = 0; i < 4; i++) + sw[i] = grub_swap_bytes32 (sw[i]); + + if (!cipher) + return grub_error (GRUB_ERR_ACCESS_DENIED, + "no decryption key available");; + err = algo_decrypt (cipher, algo, + (grub_uint8_t *) buf, + (grub_uint8_t *) buf, + size, mac, + sw + 1, 3, 12); + if (err) + return err; + + for (i = 0; i < 3; i++) + if (grub_zfs_to_cpu32 (expected_mac[i], endian) + != grub_be_to_cpu32 (mac[i])) + return grub_error (GRUB_ERR_BAD_FS, "MAC verification failed"); + return GRUB_ERR_NONE; +} + +static grub_crypto_cipher_handle_t +grub_zfs_load_key_real (const struct grub_zfs_key *key, + grub_size_t keysize, + grub_uint64_t salt, + grub_uint64_t algo) +{ + unsigned keylen; + struct grub_zfs_wrap_key *wrap_key; + grub_crypto_cipher_handle_t ret = NULL; + + if (keysize != sizeof (*key)) + { + grub_dprintf ("zfs", "Unexpected key size %" PRIuGRUB_SIZE "\n", keysize); + return 0; + } + + if (grub_memcmp (key->enc_key + 32, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) + == 0) + keylen = 16; + else if (grub_memcmp (key->enc_key + 40, "\0\0\0\0\0\0\0\0", 8) == 0) + keylen = 24; + else + keylen = 32; + + for (wrap_key = zfs_wrap_keys; wrap_key; wrap_key = wrap_key->next) + { + grub_crypto_cipher_handle_t cipher; + grub_uint8_t decrypted[32], mac[32], wrap_key_real[32]; + gcry_err_code_t err; + cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES); + if (!cipher) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + grub_memset (wrap_key_real, 0, sizeof (wrap_key_real)); + err = 0; + if (!wrap_key->is_passphrase) + grub_memcpy(wrap_key_real, wrap_key->key, + wrap_key->keylen < keylen ? wrap_key->keylen : keylen); + else + err = grub_crypto_pbkdf2 (GRUB_MD_SHA1, + (const grub_uint8_t *) wrap_key->key, + wrap_key->keylen, + (const grub_uint8_t *) &salt, sizeof (salt), + 1000, wrap_key_real, keylen); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + err = grub_crypto_cipher_set_key (cipher, wrap_key_real, + keylen); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + err = algo_decrypt (cipher, algo, decrypted, key->unknown_purpose_key, 32, + mac, key->unknown_purpose_nonce, 2, 16); + if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) + != 0)) + { + grub_dprintf ("zfs", "key loading failed\n"); + grub_errno = GRUB_ERR_NONE; + continue; + } + + err = algo_decrypt (cipher, algo, decrypted, key->enc_key, keylen, mac, + key->enc_nonce, 2, 16); + if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0) + { + grub_dprintf ("zfs", "key loading failed\n"); + grub_errno = GRUB_ERR_NONE; + continue; + } + ret = grub_crypto_cipher_open (GRUB_CIPHER_AES); + if (!ret) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + err = grub_crypto_cipher_set_key (ret, decrypted, keylen); + if (err) + { + grub_errno = GRUB_ERR_NONE; + grub_crypto_cipher_close (ret); + continue; + } + return ret; + } + return NULL; +} + +static const struct grub_arg_option options[] = + { + {"raw", 'r', 0, N_("Assume input is raw."), 0, 0}, + {"hex", 'h', 0, N_("Assume input is hex."), 0, 0}, + {"passphrase", 'p', 0, N_("Assume input is passphrase."), 0, 0}, + {0, 0, 0, 0, 0, 0} + }; + +static grub_err_t +grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint8_t buf[1024]; + grub_ssize_t real_size; + + if (argc > 0) + { + grub_file_t file; + file = grub_file_open (args[0]); + if (!file) + return grub_errno; + real_size = grub_file_read (file, buf, 1024); + if (real_size < 0) + return grub_errno; + } + else + { + grub_xputs (_("Enter ZFS password: ")); + if (!grub_password_get ((char *) buf, 1023)) + return grub_errno; + real_size = grub_strlen ((char *) buf); + } + + if (ctxt->state[1].set) + { + int i; + grub_err_t err; + for (i = 0; i < real_size / 2; i++) + { + char c1 = grub_tolower (buf[2 * i]) - '0'; + char c2 = grub_tolower (buf[2 * i + 1]) - '0'; + if (c1 > 9) + c1 += '0' - 'a' + 10; + if (c2 > 9) + c2 += '0' - 'a' + 10; + buf[i] = (c1 << 4) | c2; + } + err = grub_zfs_add_key (buf, real_size / 2, 0); + if (err) + return err; + return GRUB_ERR_NONE; + } + + return grub_zfs_add_key (buf, real_size, + ctxt->state[2].set + || (argc == 0 && !ctxt->state[0].set + && !ctxt->state[1].set)); +} + +static grub_extcmd_t cmd_key; + +GRUB_MOD_INIT(zfscrypt) +{ + grub_zfs_decrypt = grub_zfs_decrypt_real; + grub_zfs_load_key = grub_zfs_load_key_real; + cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0, + N_("[-h|-p|-r] [FILE]"), + N_("Import ZFS wrapping key stored in FILE."), + options); +} + +GRUB_MOD_FINI(zfscrypt) +{ + grub_zfs_decrypt = 0; + grub_zfs_load_key = 0; + grub_unregister_extcmd (cmd_key); +} diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c new file mode 100644 index 000000000..94f2a1ac8 --- /dev/null +++ b/grub-core/fs/zfs/zfsinfo.c @@ -0,0 +1,410 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc. + * Copyright 2008 Sun Microsystems, 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +static inline void +print_tabs (int n) +{ + int i; + + for (i = 0; i < n; i++) + grub_printf (" "); +} + +static grub_err_t +print_state (char *nvlist, int tab) +{ + grub_uint64_t ival; + int isok = 1; + + print_tabs (tab); + grub_xputs (_("State: ")); + + if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_REMOVED, &ival)) + { + grub_xputs (_("removed ")); + isok = 0; + } + + if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival)) + { + grub_xputs (_("faulted ")); + isok = 0; + } + + if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_OFFLINE, &ival)) + { + grub_xputs (_("offline ")); + isok = 0; + } + + if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival)) + grub_xputs (_("degraded ")); + + if (isok) + grub_xputs (_("online")); + grub_xputs ("\n"); + + return GRUB_ERR_NONE; +} + +static grub_err_t +print_vdev_info (char *nvlist, int tab) +{ + char *type = 0; + + type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE); + + if (!type) + { + print_tabs (tab); + grub_puts_ (N_("Incorrect VDEV: no type available")); + return grub_errno; + } + + if (grub_strcmp (type, VDEV_TYPE_DISK) == 0) + { + char *bootpath = 0; + char *path = 0; + char *devid = 0; + + print_tabs (tab); + grub_puts_ (N_("Leaf VDEV")); + + print_state (nvlist, tab); + + bootpath = + grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_PHYS_PATH); + print_tabs (tab); + if (!bootpath) + grub_puts_ (N_("Bootpath: unavailable\n")); + else + grub_printf_ (N_("Bootpath: %s\n"), bootpath); + + path = grub_zfs_nvlist_lookup_string (nvlist, "path"); + print_tabs (tab); + if (!path) + grub_puts_ (N_("Path: unavailable")); + else + grub_printf_ (N_("Path: %s\n"), path); + + devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID); + print_tabs (tab); + if (!devid) + grub_puts_ (N_("Devid: unavailable")); + else + grub_printf_ (N_("Devid: %s\n"), devid); + grub_free (bootpath); + grub_free (devid); + grub_free (path); + return GRUB_ERR_NONE; + } + + if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) + { + int nelm, i; + + nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm + (nvlist, ZPOOL_CONFIG_CHILDREN); + + print_tabs (tab); + if (nelm <= 0) + { + grub_puts_ (N_("Incorrect mirror VDEV")); + return GRUB_ERR_NONE; + } + grub_printf_ (N_("Mirror VDEV with %d children\n"), nelm); + print_state (nvlist, tab); + for (i = 0; i < nelm; i++) + { + char *child; + + child = grub_zfs_nvlist_lookup_nvlist_array + (nvlist, ZPOOL_CONFIG_CHILDREN, i); + + print_tabs (tab); + if (!child) + { + grub_printf_ (N_("Mirror VDEV element %d isn't correct\n"), i); + continue; + } + + grub_printf_ (N_("Mirror VDEV element %d:\n"), i); + print_vdev_info (child, tab + 1); + + grub_free (child); + } + return GRUB_ERR_NONE; + } + + print_tabs (tab); + grub_printf_ (N_("Unknown VDEV type: %s\n"), type); + + return GRUB_ERR_NONE; +} + +static grub_err_t +get_bootpath (char *nvlist, char **bootpath, char **devid) +{ + char *type = 0; + + type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE); + + if (!type) + return grub_errno; + + if (grub_strcmp (type, VDEV_TYPE_DISK) == 0) + { + *bootpath = grub_zfs_nvlist_lookup_string (nvlist, + ZPOOL_CONFIG_PHYS_PATH); + *devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID); + if (!*bootpath || !*devid) + { + grub_free (*bootpath); + grub_free (*devid); + *bootpath = 0; + *devid = 0; + } + return GRUB_ERR_NONE; + } + + if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0) + { + int nelm, i; + + nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm + (nvlist, ZPOOL_CONFIG_CHILDREN); + + for (i = 0; i < nelm; i++) + { + char *child; + + child = grub_zfs_nvlist_lookup_nvlist_array (nvlist, + ZPOOL_CONFIG_CHILDREN, + i); + + get_bootpath (child, bootpath, devid); + + grub_free (child); + + if (*bootpath && *devid) + return GRUB_ERR_NONE; + } + } + + return GRUB_ERR_NONE; +} + +static const char *poolstates[] = { + [POOL_STATE_ACTIVE] = N_("Pool state: active"), + [POOL_STATE_EXPORTED] = N_("Pool state: exported"), + [POOL_STATE_DESTROYED] = N_("Pool state: destroyed"), + [POOL_STATE_SPARE] = N_("Pool state: reserved for hot spare"), + [POOL_STATE_L2CACHE] = N_("Pool state: level 2 ARC device"), + [POOL_STATE_UNINITIALIZED] = N_("Pool state: uninitialized"), + [POOL_STATE_UNAVAIL] = N_("Pool state: unavailable"), + [POOL_STATE_POTENTIALLY_ACTIVE] = N_("Pool state: potentially active") +}; + +static grub_err_t +grub_cmd_zfsinfo (grub_command_t cmd __attribute__ ((unused)), int argc, + char **args) +{ + grub_device_t dev; + char *devname; + grub_err_t err; + char *nvlist = 0; + char *nv = 0; + char *poolname; + grub_uint64_t guid; + grub_uint64_t pool_state; + int found; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + + if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')') + { + devname = grub_strdup (args[0] + 1); + if (devname) + devname[grub_strlen (devname) - 1] = 0; + } + else + devname = grub_strdup (args[0]); + if (!devname) + return grub_errno; + + dev = grub_device_open (devname); + grub_free (devname); + if (!dev) + return grub_errno; + + err = grub_zfs_fetch_nvlist (dev, &nvlist); + + grub_device_close (dev); + + if (err) + return err; + + poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); + if (!poolname) + grub_puts_ (N_("Pool name: unavailable")); + else + grub_printf_ (N_("Pool name: %s\n"), poolname); + + found = + grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid); + if (!found) + grub_puts_ (N_("Pool GUID: unavailable")); + else + grub_printf_ (N_("Pool GUID: %016llx\n"), (long long unsigned) guid); + + found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_STATE, + &pool_state); + if (!found) + grub_puts_ (N_("Unable to retrieve pool state")); + else if (pool_state >= ARRAY_SIZE (poolstates)) + grub_puts_ (N_("Unrecognized pool state")); + else + grub_puts_ (poolstates[pool_state]); + + nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE); + + if (!nv) + grub_puts_ (N_("No vdev tree available")); + else + print_vdev_info (nv, 1); + + grub_free (nv); + grub_free (nvlist); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc, + char **args) +{ + grub_device_t dev; + char *devname; + grub_err_t err; + char *nvlist = 0; + char *nv = 0; + char *bootpath = 0, *devid = 0; + char *fsname; + char *bootfs; + char *poolname; + grub_uint64_t mdnobj; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "filesystem name required"); + + devname = grub_file_get_device_name (args[0]); + if (grub_errno) + return grub_errno; + + dev = grub_device_open (devname); + grub_free (devname); + if (!dev) + return grub_errno; + + err = grub_zfs_fetch_nvlist (dev, &nvlist); + + fsname = grub_strchr (args[0], ')'); + if (fsname) + fsname++; + else + fsname = args[0]; + + if (!err) + err = grub_zfs_getmdnobj (dev, fsname, &mdnobj); + + grub_device_close (dev); + + if (err) + return err; + + poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); + if (!poolname) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_FS, "No poolname found"); + return grub_errno; + } + + nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE); + + if (nv) + get_bootpath (nv, &bootpath, &devid); + + grub_free (nv); + grub_free (nvlist); + + bootfs = grub_xasprintf ("zfs-bootfs=%s/%llu%s%s%s%s%s%s", + poolname, (unsigned long long) mdnobj, + bootpath ? ",bootpath=\"" : "", + bootpath ? : "", + bootpath ? "\"" : "", + devid ? ",diskdevid=\"" : "", + devid ? : "", + devid ? "\"" : ""); + if (!bootfs) + return grub_errno; + if (argc >= 2) + grub_env_set (args[1], bootfs); + else + grub_printf ("%s\n", bootfs); + + grub_free (bootfs); + grub_free (poolname); + grub_free (bootpath); + grub_free (devid); + + return GRUB_ERR_NONE; +} + + +static grub_command_t cmd_info, cmd_bootfs; + +GRUB_MOD_INIT (zfsinfo) +{ + cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo, + N_("DEVICE"), + N_("Print ZFS info about DEVICE.")); + cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs, + N_("FILESYSTEM [VARIABLE]"), + N_("Print ZFS-BOOTFSOBJ or set it to VARIABLE")); +} + +GRUB_MOD_FINI (zfsinfo) +{ + grub_unregister_command (cmd_info); + grub_unregister_command (cmd_bootfs); +} diff --git a/grub-core/gdb_grub.in b/grub-core/gdb_grub.in new file mode 100644 index 000000000..4a55233da --- /dev/null +++ b/grub-core/gdb_grub.in @@ -0,0 +1,82 @@ +### +### Load debuging information about GNU GRUB 2 modules into GDB +### automatically. Needs readelf, Perl and gmodule.pl script +### +### $Id: .gdbinit,v 1.1 2006/05/14 11:38:08 lkundrak Exp $ +### Lubomir Kundrak +### + +# Add section numbers and addresses to .segments.tmp +define dump_module_sections + set $mod = $arg0 + + # FIXME: save logging status + set logging file .segments.tmp + set logging redirect on + set logging overwrite off + set logging on + + printf "%s", $mod->name + set $segment = $mod->segment + while ($segment) + printf " %i 0x%x", $segment->section, $segment->addr + set $segment = $segment->next + end + printf "\n" + + set logging off + # FIXME: restore logging status +end +document dump_module_sections + Gather information about module whose mod structure was + given for use with match_and_load_symbols +end + +# Generate and execute GDB commands and delete temporary files +# afterwards +define match_and_load_symbols + shell perl gmodule.pl <.segments.tmp >.loadsym.gdb + source .loadsym.gdb + shell rm -f .segments.tmp .loadsym.gdb +end +document match_and_load_symbols + Launch script, that matches section names with information + generated by dump_module_sections and load debugging info + apropriately +end + +### + +define load_module + dump_module_sections $arg0 + match_and_load_symbols +end +document load_module + Load debugging information for module given as argument. +end + +define load_all_modules + set $this = grub_dl_head + while ($this != 0) + dump_module_sections $this->mod + set $this = $this->next + end + match_and_load_symbols +end +document load_all_modules + Load debugging information for all loaded modules. +end + +### + +set confirm off +file kernel.exec +target remote :1234 + +# inform when module is loaded +break grub_dl_add +commands + silent + load_module mod + cont +end diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in index faac2b605..4cab8e50e 100644 --- a/grub-core/genmod.sh.in +++ b/grub-core/genmod.sh.in @@ -1,5 +1,6 @@ -#! /bin/sh -e -# +#! /bin/sh +set -e + # Copyright (C) 2010 Free Software Foundation, Inc. # # This gensymlist.sh is free software; the author @@ -35,25 +36,25 @@ deps=`grep ^$modname: $moddep | sed s@^.*:@@` rm -f $tmpfile $outfile # stripout .modname and .moddeps sections from input module -objcopy -R .modname -R .moddeps $infile $tmpfile +@OBJCOPY@ -R .modname -R .moddeps $infile $tmpfile # Attach .modname and .moddeps sections -t1=`mktemp` +t1=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 printf "$modname\0" >$t1 -t2=`mktemp` +t2=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 for dep in $deps; do printf "$dep\0" >> $t2; done if test -n "$deps"; then - objcopy --add-section .modname=$t1 --add-section .moddeps=$t2 $tmpfile + @OBJCOPY@ --add-section .modname=$t1 --add-section .moddeps=$t2 $tmpfile else - objcopy --add-section .modname=$t1 $tmpfile + @OBJCOPY@ --add-section .modname=$t1 $tmpfile fi rm -f $t1 $t2 if test x@TARGET_APPLE_CC@ != x1; then - if ! test -z "@TARGET_OBJ2ELF@"; then - ./@TARGET_OBJ2ELF@ $tmpfile || exit 1 + if ! test -z "${TARGET_OBJ2ELF}"; then + ./${TARGET_OBJ2ELF} $tmpfile || exit 1 fi if test x@platform@ != xemu; then @STRIP@ --strip-unneeded \ diff --git a/grub-core/gensyminfo.sh.in b/grub-core/gensyminfo.sh.in index 4f5184913..d383f2640 100644 --- a/grub-core/gensyminfo.sh.in +++ b/grub-core/gensyminfo.sh.in @@ -1,5 +1,6 @@ -#! /bin/sh -e -# +#! /bin/sh +set -e + # Copyright (C) 2010 Free Software Foundation, Inc. # # This gensymlist.sh is free software; the author diff --git a/grub-core/gensymlist.sh b/grub-core/gensymlist.sh index 0ab56e9cb..5f402ea87 100644 --- a/grub-core/gensymlist.sh +++ b/grub-core/gensymlist.sh @@ -47,7 +47,7 @@ grub_register_exported_symbols (void) EOF cat < sizeof (tab[0])); for (p = tab; p->name; p++) - grub_dl_register_symbol (p->name, p->addr, 0); + grub_dl_register_symbol (p->name, p->addr, p->isfunc, 0); } EOF diff --git a/grub-core/gentrigtables.c b/grub-core/gentrigtables.c index bef2b083c..8c039570d 100644 --- a/grub-core/gentrigtables.c +++ b/grub-core/gentrigtables.c @@ -30,6 +30,14 @@ main (int argc __attribute__ ((unused)), int i; printf ("#include \n"); + printf ("#include \n"); + printf ("\n"); + + printf ("/* Under copyright legislature such automated output isn't\n"); + printf ("covered by any copyright. Hence it's public domain. Public\n"); + printf ("domain works can be dual-licenced with any license. */\n"); + printf ("GRUB_MOD_LICENSE (\"GPLv3+\");"); + printf ("GRUB_MOD_DUAL_LICENSE (\"Public Domain\");"); #define TAB(op) \ printf ("grub_int16_t grub_trig_" #op "tab[] =\n{"); \ diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c index 9ab4c3b8d..2ff9d079b 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c @@ -28,6 +28,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* .mo file information from: http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html . @@ -44,12 +46,13 @@ static const char *(*grub_gettext_original) (const char *s); struct grub_gettext_msg { struct grub_gettext_msg *next; + struct grub_gettext_msg *prev; const char *name; const char *translated; }; -struct grub_gettext_msg *grub_gettext_msg_list = NULL; +static struct grub_gettext_msg *grub_gettext_msg_list = NULL; #define GETTEXT_MAGIC_NUMBER 0 #define GETTEXT_FILE_FORMAT 4 @@ -261,24 +264,16 @@ grub_mofile_open (const char *filename) return fd_mo; } +/* Returning grub_file_t would be more natural, but grub_mofile_open assigns + to fd_mo anyway ... */ static void -grub_gettext_init_ext (const char *lang) +grub_mofile_open_lang (const char *locale_dir, const char *locale) { char *mo_file; - char *locale_dir; - - locale_dir = grub_env_get ("locale_dir"); - if (locale_dir == NULL) - { - grub_dprintf ("gettext", "locale_dir variable is not set up.\n"); - return; - } - - fd_mo = NULL; /* mo_file e.g.: /boot/grub/locale/ca.mo */ - mo_file = grub_xasprintf ("%s/%s.mo", locale_dir, lang); + mo_file = grub_xasprintf ("%s/%s.mo", locale_dir, locale); if (!mo_file) return; @@ -295,6 +290,41 @@ grub_gettext_init_ext (const char *lang) return; fd_mo = grub_mofile_open (mo_file); } +} + +static void +grub_gettext_init_ext (const char *locale) +{ + const char *locale_dir; + + if (!locale) + return; + + locale_dir = grub_env_get ("locale_dir"); + if (locale_dir == NULL) + { + grub_dprintf ("gettext", "locale_dir variable is not set up.\n"); + return; + } + + fd_mo = NULL; + + grub_mofile_open_lang (locale_dir, locale); + + /* ll_CC didn't work, so try ll. */ + if (fd_mo == NULL) + { + char *lang = grub_strdup (locale); + char *underscore = grub_strchr (lang, '_'); + + if (underscore) + { + *underscore = '\0'; + grub_mofile_open_lang (locale_dir, lang); + } + + grub_free (lang); + } if (fd_mo) { @@ -344,8 +374,6 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)), GRUB_MOD_INIT (gettext) { - (void) mod; /* To stop warning. */ - const char *lang; lang = grub_env_get ("lang"); diff --git a/grub-core/gfxmenu/gfxmenu.c b/grub-core/gfxmenu/gfxmenu.c index 1acab9ca7..2f210e02b 100644 --- a/grub-core/gfxmenu/gfxmenu.c +++ b/grub-core/gfxmenu/gfxmenu.c @@ -37,7 +37,9 @@ #include #include -grub_gfxmenu_view_t cached_view; +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_gfxmenu_view_t cached_view; static void grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) @@ -56,30 +58,15 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) theme_path = grub_env_get ("theme"); if (! theme_path) - { - grub_error_push (); - grub_gfxterm_fullscreen (); - grub_error_pop (); - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); - } + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no theme specified"); instance = grub_zalloc (sizeof (*instance)); if (!instance) - { - grub_error_push (); - grub_gfxterm_fullscreen (); - grub_error_pop (); - return grub_errno; - } + return grub_errno; err = grub_video_get_info (&mode_info); if (err) - { - grub_error_push (); - grub_gfxterm_fullscreen (); - grub_error_pop (); - return err; - } + return err; if (!cached_view || grub_strcmp (cached_view->theme_path, theme_path) != 0 || cached_view->screen.width != mode_info.width @@ -94,9 +81,6 @@ grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) if (! cached_view) { grub_free (instance); - grub_error_push (); - grub_gfxterm_fullscreen (); - grub_error_pop (); return grub_errno; } diff --git a/grub-core/gfxmenu/gui_image.c b/grub-core/gfxmenu/gui_image.c index 3988f4ba8..60e4a46de 100644 --- a/grub-core/gfxmenu/gui_image.c +++ b/grub-core/gfxmenu/gui_image.c @@ -101,6 +101,9 @@ image_get_parent (void *vself) static grub_err_t rescale_image (grub_gui_image_t self) { + signed width; + signed height; + if (! self->raw_bitmap) { if (self->bitmap) @@ -111,12 +114,12 @@ rescale_image (grub_gui_image_t self) return grub_errno; } - unsigned width = self->bounds.width; - unsigned height = self->bounds.height; + width = self->bounds.width; + height = self->bounds.height; if (self->bitmap - && (grub_video_bitmap_get_width (self->bitmap) == width) - && (grub_video_bitmap_get_height (self->bitmap) == height)) + && ((signed) grub_video_bitmap_get_width (self->bitmap) == width) + && ((signed) grub_video_bitmap_get_height (self->bitmap) == height)) { /* Nothing to do; already the right size. */ return grub_errno; @@ -131,15 +134,15 @@ rescale_image (grub_gui_image_t self) /* Create a scaled bitmap, unless the requested size is the same as the raw size -- in that case a reference is made. */ - if (grub_video_bitmap_get_width (self->raw_bitmap) == width - && grub_video_bitmap_get_height (self->raw_bitmap) == height) + if ((signed) grub_video_bitmap_get_width (self->raw_bitmap) == width + && (signed) grub_video_bitmap_get_height (self->raw_bitmap) == height) { self->bitmap = self->raw_bitmap; return grub_errno; } /* Don't scale to an invalid size. */ - if (width == 0 || height == 0) + if (width <= 0 || height <= 0) return grub_errno; /* Create the scaled bitmap. */ diff --git a/grub-core/gfxmenu/gui_label.c b/grub-core/gfxmenu/gui_label.c index 15a352f84..688bea077 100644 --- a/grub-core/gfxmenu/gui_label.c +++ b/grub-core/gfxmenu/gui_label.c @@ -48,7 +48,7 @@ struct grub_gui_label char *text; char *template; grub_font_t font; - grub_gui_color_t color; + grub_video_rgba_color_t color; int value; enum align_mode align; }; @@ -94,20 +94,22 @@ label_paint (void *vself, const grub_video_rect_t *region) if (self->align == align_left) left_x = 0; else if (self->align == align_center) - left_x = ((self->bounds.width - - grub_font_get_string_width (self->font, self->text)) - ) / 2; + left_x = (self->bounds.width + - grub_font_get_string_width (self->font, self->text)) / 2; else if (self->align == align_right) left_x = (self->bounds.width - grub_font_get_string_width (self->font, self->text)); else return; /* Invalid alignment. */ + if (left_x < 0 || left_x > (int) self->bounds.width) + left_x = 0; + grub_video_rect_t vpsave; grub_gui_set_viewport (&self->bounds, &vpsave); grub_font_draw_string (self->text, self->font, - grub_gui_map_color (self->color), + grub_video_map_rgba_color (self->color), left_x, grub_font_get_ascent (self->font)); grub_gui_restore_viewport (&vpsave); @@ -186,7 +188,7 @@ label_set_property (void *vself, const char *name, const char *value) } else if (grub_strcmp (name, "color") == 0) { - grub_gui_parse_color (value, &self->color); + grub_video_parse_color (value, &self->color); } else if (grub_strcmp (name, "align") == 0) { diff --git a/grub-core/gfxmenu/gui_list.c b/grub-core/gfxmenu/gui_list.c index 8058fcc4f..1982d9a40 100644 --- a/grub-core/gfxmenu/gui_list.c +++ b/grub-core/gfxmenu/gui_list.c @@ -41,9 +41,9 @@ struct grub_gui_list_impl int item_spacing; grub_font_t item_font; grub_font_t selected_item_font; - grub_gui_color_t item_color; + grub_video_rgba_color_t item_color; int selected_item_color_set; - grub_gui_color_t selected_item_color; + grub_video_rgba_color_t selected_item_color; int draw_scrollbar; int need_to_recreate_scrollbar; @@ -245,17 +245,20 @@ draw_menu (list_impl_t self, int num_shown_items) visible_index++, menu_index++) { int is_selected = (menu_index == self->view->selected); + struct grub_video_bitmap *icon; if (is_selected) { - selbox->set_content_size (selbox, oviewport.width - 2 * boxpad - 2, - item_height - 1); + int cwidth = oviewport.width - 2 * boxpad - 2; + if (selbox->get_border_width) + cwidth -= selbox->get_border_width (selbox); + selbox->set_content_size (selbox, cwidth, item_height - 1); selbox->draw (selbox, 0, item_top - sel_toppad); } - struct grub_video_bitmap *icon; - if ((icon = get_item_icon (self, menu_index)) != 0) + icon = get_item_icon (self, menu_index); + if (icon != 0) grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND, sel_leftpad, item_top + (item_height - self->icon_height) / 2, @@ -267,13 +270,13 @@ draw_menu (list_impl_t self, int num_shown_items) (is_selected && self->selected_item_font ? self->selected_item_font : self->item_font); - grub_gui_color_t text_color = + grub_video_rgba_color_t text_color = ((is_selected && self->selected_item_color_set) ? self->selected_item_color : self->item_color); grub_font_draw_string (item_title, font, - grub_gui_map_color (text_color), + grub_video_map_rgba_color (text_color), sel_leftpad + self->icon_width + icon_text_space, (item_top + (item_height - (ascent + descent)) / 2 + ascent)); @@ -429,7 +432,7 @@ list_set_property (void *vself, const char *name, const char *value) } else if (grub_strcmp (name, "item_color") == 0) { - grub_gui_parse_color (value, &self->item_color); + grub_video_parse_color (value, &self->item_color); } else if (grub_strcmp (name, "selected_item_color") == 0) { @@ -439,7 +442,7 @@ list_set_property (void *vself, const char *name, const char *value) } else { - if (grub_gui_parse_color (value, &self->selected_item_color) + if (grub_video_parse_color (value, &self->selected_item_color) == GRUB_ERR_NONE) self->selected_item_color_set = 1; } @@ -562,8 +565,7 @@ grub_gui_list_new (void) { list_impl_t self; grub_font_t default_font; - grub_gui_color_t default_fg_color; - grub_gui_color_t default_bg_color; + grub_video_rgba_color_t default_fg_color; self = grub_zalloc (sizeof (*self)); if (! self) @@ -575,8 +577,7 @@ grub_gui_list_new (void) self->visible = 1; default_font = grub_font_get ("Unknown Regular 16"); - default_fg_color = grub_gui_color_rgb (0, 0, 0); - default_bg_color = grub_gui_color_rgb (255, 255, 255); + default_fg_color = grub_video_rgba_color_rgb (0, 0, 0); self->icon_width = 32; self->icon_height = 32; diff --git a/grub-core/gfxmenu/gui_progress_bar.c b/grub-core/gfxmenu/gui_progress_bar.c index e1b31794f..db89ccbf7 100644 --- a/grub-core/gfxmenu/gui_progress_bar.c +++ b/grub-core/gfxmenu/gui_progress_bar.c @@ -40,10 +40,10 @@ struct grub_gui_progress_bar int show_text; char *template; grub_font_t font; - grub_gui_color_t text_color; - grub_gui_color_t border_color; - grub_gui_color_t bg_color; - grub_gui_color_t fg_color; + grub_video_rgba_color_t text_color; + grub_video_rgba_color_t border_color; + grub_video_rgba_color_t bg_color; + grub_video_rgba_color_t fg_color; char *theme_dir; int need_to_recreate_pixmaps; @@ -109,7 +109,7 @@ draw_filled_rect_bar (grub_gui_progress_bar_t self) f.height = self->bounds.height - 2; /* Border. */ - grub_video_fill_rect (grub_gui_map_color (self->border_color), + grub_video_fill_rect (grub_video_map_rgba_color (self->border_color), f.x - 1, f.y - 1, f.width + 2, f.height + 2); @@ -117,12 +117,12 @@ draw_filled_rect_bar (grub_gui_progress_bar_t self) int barwidth = (f.width * (self->value - self->start) / (self->end - self->start)); - grub_video_fill_rect (grub_gui_map_color (self->bg_color), + grub_video_fill_rect (grub_video_map_rgba_color (self->bg_color), f.x + barwidth, f.y, f.width - barwidth, f.height); /* Bar foreground. */ - grub_video_fill_rect (grub_gui_map_color (self->fg_color), + grub_video_fill_rect (grub_video_map_rgba_color (self->fg_color), f.x, f.y, barwidth, f.height); } @@ -161,7 +161,8 @@ draw_text (grub_gui_progress_bar_t self) if (self->template) { grub_font_t font = self->font; - grub_video_color_t text_color = grub_gui_map_color (self->text_color); + grub_video_color_t text_color = + grub_video_map_rgba_color (self->text_color); int width = self->bounds.width; int height = self->bounds.height; char *text; @@ -298,19 +299,19 @@ progress_bar_set_property (void *vself, const char *name, const char *value) } else if (grub_strcmp (name, "text_color") == 0) { - grub_gui_parse_color (value, &self->text_color); + grub_video_parse_color (value, &self->text_color); } else if (grub_strcmp (name, "border_color") == 0) { - grub_gui_parse_color (value, &self->border_color); + grub_video_parse_color (value, &self->border_color); } else if (grub_strcmp (name, "bg_color") == 0) { - grub_gui_parse_color (value, &self->bg_color); + grub_video_parse_color (value, &self->bg_color); } else if (grub_strcmp (name, "fg_color") == 0) { - grub_gui_parse_color (value, &self->fg_color); + grub_video_parse_color (value, &self->fg_color); } else if (grub_strcmp (name, "bar_style") == 0) { @@ -379,9 +380,9 @@ grub_gui_progress_bar_new (void) self->progress.component.ops = &progress_bar_ops; self->visible = 1; self->font = grub_font_get ("Unknown Regular 16"); - grub_gui_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 }; - grub_gui_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 }; - grub_gui_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 }; + grub_video_rgba_color_t black = { .red = 0, .green = 0, .blue = 0, .alpha = 255 }; + grub_video_rgba_color_t gray = { .red = 128, .green = 128, .blue = 128, .alpha = 255 }; + grub_video_rgba_color_t lightgray = { .red = 200, .green = 200, .blue = 200, .alpha = 255 }; self->text_color = black; self->border_color = black; self->bg_color = gray; diff --git a/grub-core/gfxmenu/gui_string_util.c b/grub-core/gfxmenu/gui_string_util.c index 8c51e396a..a9a415e31 100644 --- a/grub-core/gfxmenu/gui_string_util.c +++ b/grub-core/gfxmenu/gui_string_util.c @@ -204,124 +204,3 @@ grub_get_dirname (const char *file_path) return grub_new_substring (file_path, 0, last_slash + 1); } - -static __inline int -my_isxdigit (char c) -{ - return ((c >= '0' && c <= '9') - || (c >= 'a' && c <= 'f') - || (c >= 'A' && c <= 'F')); -} - -static int -parse_hex_color_component (const char *s, unsigned start, unsigned end) -{ - unsigned len; - char buf[3]; - - len = end - start; - /* Check the limits so we don't overrun the buffer. */ - if (len < 1 || len > 2) - return 0; - - if (len == 1) - { - buf[0] = s[start]; /* Get the first and only hex digit. */ - buf[1] = buf[0]; /* Duplicate the hex digit. */ - } - else if (len == 2) - { - buf[0] = s[start]; - buf[1] = s[start + 1]; - } - - buf[2] = '\0'; - - return grub_strtoul (buf, 0, 16); -} - -/* Parse a color string of the form "r, g, b", "#RGB", "#RGBA", - "#RRGGBB", or "#RRGGBBAA". */ -grub_err_t -grub_gui_parse_color (const char *s, grub_gui_color_t *color) -{ - grub_gui_color_t c; - - /* Skip whitespace. */ - while (*s && grub_isspace (*s)) - s++; - - if (*s == '#') - { - /* HTML-style. Number if hex digits: - [6] #RRGGBB [3] #RGB - [8] #RRGGBBAA [4] #RGBA */ - - s++; /* Skip the '#'. */ - /* Count the hexits to determine the format. */ - int hexits = 0; - const char *end = s; - while (my_isxdigit (*end)) - { - end++; - hexits++; - } - - /* Parse the color components based on the format. */ - if (hexits == 3 || hexits == 4) - { - c.red = parse_hex_color_component (s, 0, 1); - c.green = parse_hex_color_component (s, 1, 2); - c.blue = parse_hex_color_component (s, 2, 3); - if (hexits == 4) - c.alpha = parse_hex_color_component (s, 3, 4); - else - c.alpha = 255; - } - else if (hexits == 6 || hexits == 8) - { - c.red = parse_hex_color_component (s, 0, 2); - c.green = parse_hex_color_component (s, 2, 4); - c.blue = parse_hex_color_component (s, 4, 6); - if (hexits == 8) - c.alpha = parse_hex_color_component (s, 6, 8); - else - c.alpha = 255; - } - else - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid HTML-type color string `%s'", s); - } - else if (grub_isdigit (*s)) - { - /* Comma separated decimal values. */ - c.red = grub_strtoul (s, 0, 0); - if ((s = grub_strchr (s, ',')) == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "missing 1st comma separator in color `%s'", s); - s++; - c.green = grub_strtoul (s, 0, 0); - if ((s = grub_strchr (s, ',')) == 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "missing 2nd comma separator in color `%s'", s); - s++; - c.blue = grub_strtoul (s, 0, 0); - if ((s = grub_strchr (s, ',')) == 0) - c.alpha = 255; - else - { - s++; - c.alpha = grub_strtoul (s, 0, 0); - } - } - else - { - if (! grub_gui_get_named_color (s, &c)) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid named color `%s'", s); - } - - if (grub_errno == GRUB_ERR_NONE) - *color = c; - return grub_errno; -} diff --git a/grub-core/gfxmenu/icon_manager.c b/grub-core/gfxmenu/icon_manager.c index 0c304ede0..6990d05d4 100644 --- a/grub-core/gfxmenu/icon_manager.c +++ b/grub-core/gfxmenu/icon_manager.c @@ -257,7 +257,7 @@ grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr, /* Try each class in succession. */ icon = 0; - for (c = entry->classes->next; c && ! icon; c = c->next) + for (c = entry->classes; c && ! icon; c = c->next) icon = get_icon_by_class (mgr, c->name); return icon; } diff --git a/grub-core/gfxmenu/theme_loader.c b/grub-core/gfxmenu/theme_loader.c index 3854c6c53..f9c711d3e 100644 --- a/grub-core/gfxmenu/theme_loader.c +++ b/grub-core/gfxmenu/theme_loader.c @@ -135,11 +135,11 @@ theme_set_string (grub_gfxmenu_view_t view, return grub_errno; } else if (! grub_strcmp ("title-color", name)) - grub_gui_parse_color (value, &view->title_color); + grub_video_parse_color (value, &view->title_color); else if (! grub_strcmp ("message-color", name)) - grub_gui_parse_color (value, &view->message_color); + grub_video_parse_color (value, &view->message_color); else if (! grub_strcmp ("message-bg-color", name)) - grub_gui_parse_color (value, &view->message_bg_color); + grub_video_parse_color (value, &view->message_bg_color); else if (! grub_strcmp ("desktop-image", name)) { struct grub_video_bitmap *raw_bitmap; @@ -170,7 +170,7 @@ theme_set_string (grub_gfxmenu_view_t view, view->desktop_image = scaled_bitmap; } else if (! grub_strcmp ("desktop-color", name)) - grub_gui_parse_color (value, &view->desktop_color); + grub_video_parse_color (value, &view->desktop_color); else if (! grub_strcmp ("terminal-box", name)) { grub_err_t err; diff --git a/grub-core/gfxmenu/view.c b/grub-core/gfxmenu/view.c index 518c3ba53..9023fd3c4 100644 --- a/grub-core/gfxmenu/view.c +++ b/grub-core/gfxmenu/view.c @@ -36,6 +36,7 @@ #include #include #include +#include static void init_terminal (grub_gfxmenu_view_t view); @@ -50,8 +51,8 @@ grub_gfxmenu_view_new (const char *theme_path, { grub_gfxmenu_view_t view; grub_font_t default_font; - grub_gui_color_t default_fg_color; - grub_gui_color_t default_bg_color; + grub_video_rgba_color_t default_fg_color; + grub_video_rgba_color_t default_bg_color; view = grub_malloc (sizeof (*view)); if (! view) @@ -63,8 +64,8 @@ grub_gfxmenu_view_new (const char *theme_path, view->screen.height = height; default_font = grub_font_get ("Unknown Regular 16"); - default_fg_color = grub_gui_color_rgb (0, 0, 0); - default_bg_color = grub_gui_color_rgb (255, 255, 255); + default_fg_color = grub_video_rgba_color_rgb (0, 0, 0); + default_bg_color = grub_video_rgba_color_rgb (255, 255, 255); view->canvas = 0; @@ -77,7 +78,7 @@ grub_gfxmenu_view_new (const char *theme_path, view->desktop_image = 0; view->desktop_color = default_bg_color; view->terminal_box = grub_gfxmenu_create_box (0, 0); - view->title_text = grub_strdup ("GRUB Boot Menu"); + view->title_text = grub_strdup (_("GRUB Boot Menu")); view->progress_message_text = 0; view->theme_path = 0; @@ -131,7 +132,7 @@ redraw_background (grub_gfxmenu_view_t view, } else { - grub_video_fill_rect (grub_gui_map_color (view->desktop_color), + grub_video_fill_rect (grub_video_map_rgba_color (view->desktop_color), bounds->x, bounds->y, bounds->width, bounds->height); } @@ -150,7 +151,7 @@ draw_title (grub_gfxmenu_view_t view) int y = 40 + grub_font_get_ascent (view->title_font); grub_font_draw_string (view->title_text, view->title_font, - grub_gui_map_color (view->title_color), + grub_video_map_rgba_color (view->title_color), x, y); } @@ -244,13 +245,13 @@ draw_message (grub_gfxmenu_view_t view) return; grub_font_t font = view->message_font; - grub_video_color_t color = grub_gui_map_color (view->message_color); + grub_video_color_t color = grub_video_map_rgba_color (view->message_color); /* Border. */ grub_video_fill_rect (color, f.x-1, f.y-1, f.width+2, f.height+2); /* Fill. */ - grub_video_fill_rect (grub_gui_map_color (view->message_bg_color), + grub_video_fill_rect (grub_video_map_rgba_color (view->message_bg_color), f.x, f.y, f.width, f.height); /* Center the text. */ @@ -309,10 +310,8 @@ redraw_menu_visit (grub_gui_component_t component, view = userdata; if (component->ops->is_instance (component, "list")) { - grub_gui_list_t list; grub_video_rect_t bounds; - list = (grub_gui_list_t) component; component->ops->get_bounds (component, &bounds); grub_gfxmenu_view_redraw (view, &bounds); } diff --git a/grub-core/gfxmenu/widget-box.c b/grub-core/gfxmenu/widget-box.c index 079fd66d4..8c9131a24 100644 --- a/grub-core/gfxmenu/widget-box.c +++ b/grub-core/gfxmenu/widget-box.c @@ -79,21 +79,9 @@ static void draw (grub_gfxmenu_box_t self, int x, int y) { int height_n; - int height_s; - int height_e; - int height_w; - int width_n; - int width_s; - int width_e; int width_w; height_n = get_height (self->scaled_pixmaps[BOX_PIXMAP_N]); - height_s = get_height (self->scaled_pixmaps[BOX_PIXMAP_S]); - height_e = get_height (self->scaled_pixmaps[BOX_PIXMAP_E]); - height_w = get_height (self->scaled_pixmaps[BOX_PIXMAP_W]); - width_n = get_width (self->scaled_pixmaps[BOX_PIXMAP_N]); - width_s = get_width (self->scaled_pixmaps[BOX_PIXMAP_S]); - width_e = get_width (self->scaled_pixmaps[BOX_PIXMAP_E]); width_w = get_width (self->scaled_pixmaps[BOX_PIXMAP_W]); /* Draw sides. */ @@ -190,28 +178,75 @@ set_content_size (grub_gfxmenu_box_t self, return; } +static int +get_border_width (grub_gfxmenu_box_t self) +{ + return (get_width (self->raw_pixmaps[BOX_PIXMAP_E]) + + get_width (self->raw_pixmaps[BOX_PIXMAP_W])); +} + static int get_left_pad (grub_gfxmenu_box_t self) { - return get_width (self->raw_pixmaps[BOX_PIXMAP_W]); + int v, c; + + v = get_width (self->raw_pixmaps[BOX_PIXMAP_W]); + c = get_width (self->raw_pixmaps[BOX_PIXMAP_NW]); + if (c > v) + v = c; + c = get_width (self->raw_pixmaps[BOX_PIXMAP_SW]); + if (c > v) + v = c; + + return v; } static int get_top_pad (grub_gfxmenu_box_t self) { - return get_height (self->raw_pixmaps[BOX_PIXMAP_N]); + int v, c; + + v = get_height (self->raw_pixmaps[BOX_PIXMAP_N]); + c = get_height (self->raw_pixmaps[BOX_PIXMAP_NW]); + if (c > v) + v = c; + c = get_height (self->raw_pixmaps[BOX_PIXMAP_NE]); + if (c > v) + v = c; + + return v; } static int get_right_pad (grub_gfxmenu_box_t self) { - return get_width (self->raw_pixmaps[BOX_PIXMAP_E]); + int v, c; + + v = get_width (self->raw_pixmaps[BOX_PIXMAP_E]); + c = get_width (self->raw_pixmaps[BOX_PIXMAP_NE]); + if (c > v) + v = c; + c = get_width (self->raw_pixmaps[BOX_PIXMAP_SE]); + if (c > v) + v = c; + + return v; } static int get_bottom_pad (grub_gfxmenu_box_t self) { - return get_height (self->raw_pixmaps[BOX_PIXMAP_S]); + int v, c; + + v = get_height (self->raw_pixmaps[BOX_PIXMAP_S]); + c = get_height (self->raw_pixmaps[BOX_PIXMAP_SW]); + if (c > v) + v = c; + c = get_height (self->raw_pixmaps[BOX_PIXMAP_SE]); + if (c > v) + v = c; + + return v; } static void @@ -300,6 +335,8 @@ grub_gfxmenu_create_box (const char *pixmaps_prefix, box->draw = draw; box->set_content_size = set_content_size; + box->get_border_width = get_border_width; + box->get_left_pad = get_left_pad; box->get_top_pad = get_top_pad; box->get_right_pad = get_right_pad; diff --git a/grub-core/gmodule.pl.in b/grub-core/gmodule.pl.in new file mode 100644 index 000000000..6739a6f1c --- /dev/null +++ b/grub-core/gmodule.pl.in @@ -0,0 +1,30 @@ +### +### Generate GDB commands, that load symbols for specified module, +### with proper section relocations. See .gdbinit +### +### $Id: gmodule.pl,v 1.2 2006/05/14 11:38:42 lkundrak Exp lkundrak $ +### Lubomir Kundrak +### + +use strict; + +while (<>) { + my ($name, %sections) = split; + + print "add-symbol-file $name.module"; + + open (READELF, "readelf -S $name.mod |") or die; + while () { + /\[\s*(\d+)\]\s+(\.\S+)/ or next; + + if ($2 eq '.text') { + print " $sections{$1}"; + next; + } + + print " -s $2 $sections{$1}" + if ($sections{$1} ne '0x0'); + }; + close (READELF); + print "\n"; +} diff --git a/grub-core/gnulib/argp-parse.c b/grub-core/gnulib/argp-parse.c index a1cbf884e..9c054653c 100644 --- a/grub-core/gnulib/argp-parse.c +++ b/grub-core/gnulib/argp-parse.c @@ -935,7 +935,7 @@ weak_alias (__argp_parse, argp_parse) void * __argp_input (const struct argp *argp, const struct argp_state *state) { - if (state) + if (state && state->pstate) { struct group *group; struct parser *parser = state->pstate; diff --git a/grub-core/gnulib/regcomp.c b/grub-core/gnulib/regcomp.c index 86ca02b0c..d153e3c2e 100644 --- a/grub-core/gnulib/regcomp.c +++ b/grub-core/gnulib/regcomp.c @@ -555,7 +555,7 @@ regerror (int errcode, const regex_t *_Restrict_ preg, to this routine. If we are given anything else, or if other regex code generates an invalid error code, then the program has a bug. Dump core so we can fix it. */ - abort (); + msg = "unknown regexp error"; msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); @@ -851,7 +851,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) { __re_size_t table_size; #ifndef _LIBC - char *codeset_name; + const char *codeset_name; #endif #ifdef RE_ENABLE_I18N size_t max_i18n_object_size = MAX (sizeof (wchar_t), sizeof (wctype_t)); @@ -1119,7 +1119,7 @@ optimize_utf8 (re_dfa_t *dfa) } break; default: - abort (); + break; } if (mb_chars || has_period) diff --git a/grub-core/hello/hello.c b/grub-core/hello/hello.c index 77c4c96b1..2c9e90f72 100644 --- a/grub-core/hello/hello.c +++ b/grub-core/hello/hello.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t grub_cmd_hello (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), diff --git a/grub-core/hook/datehook.c b/grub-core/hook/datehook.c index 9b5b54bf3..ac75908ef 100644 --- a/grub-core/hook/datehook.c +++ b/grub-core/hook/datehook.c @@ -24,7 +24,9 @@ #include #include -static char *grub_datetime_names[] = +GRUB_MOD_LICENSE ("GPLv3+"); + +static const char *grub_datetime_names[] = { "YEAR", "MONTH", @@ -35,7 +37,7 @@ static char *grub_datetime_names[] = "WEEKDAY", }; -static char * +static const char * grub_read_hook_datetime (struct grub_env_var *var, const char *val __attribute__ ((unused))) { @@ -48,7 +50,7 @@ grub_read_hook_datetime (struct grub_env_var *var, int i; for (i = 0; i < 7; i++) - if (! grub_strcmp (var->name, grub_datetime_names[i])) + if (grub_strcmp (var->name, grub_datetime_names[i]) == 0) { int n; @@ -86,18 +88,21 @@ grub_read_hook_datetime (struct grub_env_var *var, GRUB_MOD_INIT(datehook) { - int i; + unsigned i; - for (i = 0; i < 7; i++) - grub_register_variable_hook (grub_datetime_names[i], - grub_read_hook_datetime, 0); + for (i = 0; i < ARRAY_SIZE (grub_datetime_names); i++) + { + grub_register_variable_hook (grub_datetime_names[i], + grub_read_hook_datetime, 0); + grub_env_export (grub_datetime_names[i]); + } } GRUB_MOD_FINI(datehook) { - int i; + unsigned i; - for (i = 0; i < 7; i++) + for (i = 0; i < ARRAY_SIZE (grub_datetime_names); i++) { grub_register_variable_hook (grub_datetime_names[i], 0, 0); grub_env_unset (grub_datetime_names[i]); diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index 8a72ecd79..2a315e2d8 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -23,6 +23,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_BUFIO_DEF_SIZE 8192 #define GRUB_BUFIO_MAX_SIZE 1048576 @@ -32,6 +35,7 @@ struct grub_bufio grub_file_t file; grub_size_t block_size; grub_size_t buffer_len; + grub_off_t buffer_at; char buffer[0]; }; typedef struct grub_bufio *grub_bufio_t; @@ -67,6 +71,7 @@ grub_bufio_open (grub_file_t io, int size) bufio->file = io; bufio->block_size = size; bufio->buffer_len = 0; + bufio->buffer_at = 0; file->device = io->device; file->offset = 0; @@ -74,7 +79,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; + file->not_easily_seekable = io->not_easily_seekable; return file; } @@ -101,82 +106,82 @@ grub_buffile_open (const char *name, int size) static grub_ssize_t grub_bufio_read (grub_file_t file, char *buf, grub_size_t len) { - grub_size_t res = len; + grub_size_t res = 0; + grub_off_t next_buf; grub_bufio_t bufio = file->data; - grub_uint32_t pos; + grub_ssize_t really_read; - if ((file->offset >= bufio->file->offset) && - (file->offset < bufio->file->offset + bufio->buffer_len)) + if (file->size == GRUB_FILE_SIZE_UNKNOWN) + file->size = bufio->file->size; + + /* First part: use whatever we already have in the buffer. */ + if ((file->offset >= bufio->buffer_at) && + (file->offset < bufio->buffer_at + bufio->buffer_len)) { grub_size_t n; + grub_uint64_t pos; - pos = file->offset - bufio->file->offset; + pos = file->offset - bufio->buffer_at; n = bufio->buffer_len - pos; if (n > len) n = len; grub_memcpy (buf, &bufio->buffer[pos], n); len -= n; - if (! len) - return res; + res += n; buf += n; - bufio->file->offset += bufio->buffer_len; - pos = 0; } - else + if (len == 0) + return res; + + /* Need to read some more. */ + next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); + /* Now read between file->offset + res and bufio->buffer_at. */ + if (file->offset + res < next_buf) { - bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size, - &pos); - bufio->file->offset *= bufio->block_size; + grub_size_t read_now; + read_now = next_buf - (file->offset + res); + grub_file_seek (bufio->file, file->offset + res); + really_read = grub_file_read (bufio->file, buf, read_now); + if (really_read < 0) + return -1; + if (file->size == GRUB_FILE_SIZE_UNKNOWN) + file->size = bufio->file->size; + len -= really_read; + buf += really_read; + res += really_read; + + /* Partial read. File ended unexpectedly. Save the last chunk in buffer. + */ + if (really_read != (grub_ssize_t) read_now) + { + bufio->buffer_len = really_read; + if (bufio->buffer_len > bufio->block_size) + bufio->buffer_len = bufio->block_size; + bufio->buffer_at = file->offset + res - bufio->buffer_len; + grub_memcpy (&bufio->buffer[0], buf - bufio->buffer_len, + bufio->buffer_len); + return res; + } } - if (pos + len >= bufio->block_size) - { - if (pos) - { - grub_size_t n; - - bufio->file->fs->read (bufio->file, bufio->buffer, - bufio->block_size); - if (grub_errno) - return -1; - - n = bufio->block_size - pos; - grub_memcpy (buf, &bufio->buffer[pos], n); - len -= n; - buf += n; - bufio->file->offset += bufio->block_size; - pos = 0; - } - - while (len >= bufio->block_size) - { - bufio->file->fs->read (bufio->file, buf, bufio->block_size); - if (grub_errno) - return -1; - - len -= bufio->block_size; - buf += bufio->block_size; - bufio->file->offset += bufio->block_size; - } - - if (! len) - { - bufio->buffer_len = 0; - return res; - } - } - - bufio->buffer_len = bufio->file->size - bufio->file->offset; - if (bufio->buffer_len > bufio->block_size) - bufio->buffer_len = bufio->block_size; - - bufio->file->fs->read (bufio->file, bufio->buffer, bufio->buffer_len); - if (grub_errno) + /* Read into buffer. */ + grub_file_seek (bufio->file, next_buf); + really_read = grub_file_read (bufio->file, bufio->buffer, + bufio->block_size); + if (really_read < 0) return -1; + bufio->buffer_at = next_buf; + bufio->buffer_len = really_read; - grub_memcpy (buf, &bufio->buffer[pos], len); + if (file->size == GRUB_FILE_SIZE_UNKNOWN) + file->size = bufio->file->size; + + if (len > bufio->buffer_len) + len = bufio->buffer_len; + grub_memcpy (buf, &bufio->buffer[file->offset + res - next_buf], len); + res += len; return res; } diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 43b67c373..0d4003cd2 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -41,6 +41,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* * Window Size @@ -58,6 +61,9 @@ struct grub_gzio { /* The underlying file object. */ grub_file_t file; + /* If input is in memory following fields are used instead of file. */ + grub_size_t mem_input_size, mem_input_off; + grub_uint8_t *mem_input; /* The offset at which the data starts in the underlying file. */ grub_off_t data_offset; /* The type of current block. */ @@ -100,7 +106,7 @@ typedef struct grub_gzio *grub_gzio_t; static struct grub_fs grub_gzio_fs; /* Function prototypes */ -static void initialize_tables (grub_file_t file); +static void initialize_tables (grub_gzio_t); /* Eat variable-length header fields. */ static int @@ -162,7 +168,7 @@ typedef unsigned short ush; typedef unsigned long ulg; static int -test_header (grub_file_t file) +test_gzip_header (grub_file_t file) { struct { grub_uint16_t magic; @@ -212,21 +218,20 @@ test_header (grub_file_t file) gzio->data_offset = grub_file_tell (gzio->file); - grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4); + /* FIXME: don't do this on not easily seekable files. */ + { + grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4); + 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); + } - if (grub_file_seekable (gzio->file)) - { - 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); - - initialize_tables (file); + initialize_tables (gzio); return 1; } @@ -366,16 +371,22 @@ static ush mask_bits[] = 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; -#define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte(file))<>=(n);k-=(n);} while (0) static int -get_byte (grub_file_t file) +get_byte (grub_gzio_t gzio) { - grub_gzio_t gzio = file->data; + if (gzio->mem_input) + { + if (gzio->mem_input_off < gzio->mem_input_size) + return gzio->mem_input[gzio->mem_input_off++]; + return 0; + } - if (grub_file_tell (gzio->file) == (grub_off_t) gzio->data_offset - || gzio->inbuf_d == INBUFSIZ) + if (gzio->file && (grub_file_tell (gzio->file) + == (grub_off_t) gzio->data_offset + || gzio->inbuf_d == INBUFSIZ)) { gzio->inbuf_d = 0; grub_file_read (gzio->file, gzio->inbuf, INBUFSIZ); @@ -384,11 +395,26 @@ get_byte (grub_file_t file) return gzio->inbuf[gzio->inbuf_d++]; } +static void +gzio_seek (grub_gzio_t gzio, grub_off_t off) +{ + if (gzio->mem_input) + { + if (off > gzio->mem_input_size) + grub_error (GRUB_ERR_OUT_OF_RANGE, + "attempt to seek outside of the file"); + else + gzio->mem_input_off = off; + } + else + grub_file_seek (gzio->file, off); +} + /* more function prototypes */ static int huft_build (unsigned *, unsigned, unsigned, ush *, ush *, struct huft **, int *); static int huft_free (struct huft *); -static int inflate_codes_in_window (grub_file_t); +static int inflate_codes_in_window (grub_gzio_t); /* Given a list of code lengths and a maximum table size, make a set of @@ -615,7 +641,7 @@ huft_free (struct huft *t) */ static int -inflate_codes_in_window (grub_file_t file) +inflate_codes_in_window (grub_gzio_t gzio) { register unsigned e; /* table entry flag/number of extra bits */ unsigned n, d; /* length and index for copy */ @@ -624,7 +650,6 @@ inflate_codes_in_window (grub_file_t file) unsigned ml, md; /* masks for bl and bd bits */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ - grub_gzio_t gzio = file->data; /* make local copies of globals */ d = gzio->inflate_d; @@ -752,11 +777,10 @@ inflate_codes_in_window (grub_file_t file) /* get header for an inflated type 0 (stored) block. */ static void -init_stored_block (grub_file_t file) +init_stored_block (grub_gzio_t gzio) { register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ - grub_gzio_t gzio = file->data; /* make local copies of globals */ b = gzio->bb; /* initialize bit buffer */ @@ -786,11 +810,10 @@ init_stored_block (grub_file_t file) Huffman tables. */ static void -init_fixed_block (grub_file_t file) +init_fixed_block (grub_gzio_t gzio) { int i; /* temporary variable */ unsigned l[288]; /* length list for huft_build */ - grub_gzio_t gzio = file->data; /* set up literal table */ for (i = 0; i < 144; i++) @@ -833,7 +856,7 @@ init_fixed_block (grub_file_t file) /* get header for an inflated type 2 (dynamic Huffman codes) block. */ static void -init_dynamic_block (grub_file_t file) +init_dynamic_block (grub_gzio_t gzio) { int i; /* temporary variables */ unsigned j; @@ -846,7 +869,6 @@ init_dynamic_block (grub_file_t file) unsigned ll[286 + 30]; /* literal/length and distance code lengths */ register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ - grub_gzio_t gzio = file->data; /* make local bit buffer */ b = gzio->bb; @@ -977,11 +999,10 @@ init_dynamic_block (grub_file_t file) static void -get_new_block (grub_file_t file) +get_new_block (grub_gzio_t gzio) { register ulg b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ - grub_gzio_t gzio = file->data; /* make local bit buffer */ b = gzio->bb; @@ -1004,13 +1025,13 @@ get_new_block (grub_file_t file) switch (gzio->block_type) { case INFLATE_STORED: - init_stored_block (file); + init_stored_block (gzio); break; case INFLATE_FIXED: - init_fixed_block (file); + init_fixed_block (gzio); break; case INFLATE_DYNAMIC: - init_dynamic_block (file); + init_dynamic_block (gzio); break; default: break; @@ -1019,10 +1040,8 @@ get_new_block (grub_file_t file) static void -inflate_window (grub_file_t file) +inflate_window (grub_gzio_t gzio) { - grub_gzio_t gzio = file->data; - /* initialize window */ gzio->wp = 0; @@ -1037,7 +1056,7 @@ inflate_window (grub_file_t file) if (gzio->last_block) break; - get_new_block (file); + get_new_block (gzio); } if (gzio->block_type > INFLATE_DYNAMIC) @@ -1060,7 +1079,7 @@ inflate_window (grub_file_t file) while (gzio->block_len && w < WSIZE && grub_errno == GRUB_ERR_NONE) { - gzio->slide[w++] = get_byte (file); + gzio->slide[w++] = get_byte (gzio); gzio->block_len--; } @@ -1073,7 +1092,7 @@ inflate_window (grub_file_t file) * Expand other kind of block. */ - if (inflate_codes_in_window (file)) + if (inflate_codes_in_window (gzio)) { huft_free (gzio->tl); huft_free (gzio->td); @@ -1089,12 +1108,10 @@ inflate_window (grub_file_t file) static void -initialize_tables (grub_file_t file) +initialize_tables (grub_gzio_t gzio) { - grub_gzio_t gzio = file->data; - gzio->saved_offset = 0; - grub_file_seek (gzio->file, gzio->data_offset); + gzio_seek (gzio, gzio->data_offset); /* Initialize the bit buffer. */ gzio->bk = 0; @@ -1137,34 +1154,64 @@ grub_gzio_open (grub_file_t io) file->data = gzio; file->read_hook = 0; file->fs = &grub_gzio_fs; - file->not_easly_seekable = 1; + file->not_easily_seekable = 1; - if (! test_header (file)) + if (! test_gzip_header (file)) { grub_free (gzio); grub_free (file); grub_file_seek (io, 0); + grub_errno = GRUB_ERR_NONE; - if (grub_errno == GRUB_ERR_BAD_FILE_TYPE) - { - grub_errno = GRUB_ERR_NONE; - return io; - } + return io; } return file; } +static int +test_zlib_header (grub_gzio_t gzio) +{ + grub_uint8_t cmf, flg; + + cmf = get_byte (gzio); + flg = get_byte (gzio); + + /* Check that compression method is DEFLATE. */ + if ((cmf & 0xf) != DEFLATED) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unsupported gzip format"); + return 0; + } + + if ((cmf * 256 + flg) % 31) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unsupported gzip format"); + return 0; + } + + /* Dictionary isn't supported. */ + if (flg & 0x20) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unsupported gzip format"); + return 0; + } + + gzio->data_offset = 2; + initialize_tables (gzio); + + return 1; +} + static grub_ssize_t -grub_gzio_read (grub_file_t file, char *buf, grub_size_t len) +grub_gzio_read_real (grub_gzio_t gzio, grub_off_t offset, + char *buf, grub_size_t len) { grub_ssize_t ret = 0; - grub_gzio_t gzio = file->data; - grub_off_t offset; /* Do we reset decompression to the beginning of the file? */ - if (gzio->saved_offset > file->offset + WSIZE) - initialize_tables (file); + if (gzio->saved_offset > offset + WSIZE) + initialize_tables (gzio); /* * This loop operates upon uncompressed data only. The only @@ -1172,15 +1219,13 @@ grub_gzio_read (grub_file_t file, char *buf, grub_size_t len) * window is within the range of data it needs. */ - offset = file->offset; - while (len > 0 && grub_errno == GRUB_ERR_NONE) { register grub_size_t size; register char *srcaddr; while (offset >= gzio->saved_offset) - inflate_window (file); + inflate_window (gzio); srcaddr = (char *) ((offset & (WSIZE - 1)) + gzio->slide); size = gzio->saved_offset - offset; @@ -1201,6 +1246,12 @@ grub_gzio_read (grub_file_t file, char *buf, grub_size_t len) return ret; } +static grub_ssize_t +grub_gzio_read (grub_file_t file, char *buf, grub_size_t len) +{ + return grub_gzio_read_real (file->data, file->offset, buf, len); +} + /* Release everything, including the underlying file object. */ static grub_err_t grub_gzio_close (grub_file_t file) @@ -1218,6 +1269,33 @@ grub_gzio_close (grub_file_t file) return grub_errno; } +grub_ssize_t +grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize) +{ + grub_gzio_t gzio = 0; + grub_ssize_t ret; + + gzio = grub_zalloc (sizeof (*gzio)); + if (! gzio) + return -1; + gzio->mem_input = (grub_uint8_t *) inbuf; + gzio->mem_input_size = insize; + gzio->mem_input_off = 0; + + if (!test_zlib_header (gzio)) + { + grub_free (gzio); + return -1; + } + + ret = grub_gzio_read_real (gzio, off, outbuf, outsize); + grub_free (gzio); + + /* FIXME: Check Adler. */ + return ret; +} + static struct grub_fs grub_gzio_fs = diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c new file mode 100644 index 000000000..4996fa546 --- /dev/null +++ b/grub-core/io/lzopio.c @@ -0,0 +1,566 @@ +/* lzopio.c - decompression support for lzop */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define LZOP_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a" +#define LZOP_MAGIC_SIZE 9 +#define LZOP_CHECK_SIZE 4 +#define LZOP_NEW_LIB 0x0940 + +/* Header flags - copied from conf.h of LZOP source code. */ +#define F_ADLER32_D 0x00000001L +#define F_ADLER32_C 0x00000002L +#define F_STDIN 0x00000004L +#define F_STDOUT 0x00000008L +#define F_NAME_DEFAULT 0x00000010L +#define F_DOSISH 0x00000020L +#define F_H_EXTRA_FIELD 0x00000040L +#define F_H_GMTDIFF 0x00000080L +#define F_CRC32_D 0x00000100L +#define F_CRC32_C 0x00000200L +#define F_MULTIPART 0x00000400L +#define F_H_FILTER 0x00000800L +#define F_H_CRC32 0x00001000L +#define F_H_PATH 0x00002000L +#define F_MASK 0x00003FFFL + +struct block_header +{ + grub_uint32_t usize; + grub_uint32_t csize; + grub_uint32_t ucheck; + grub_uint32_t ccheck; + unsigned char *cdata; + unsigned char *udata; +}; + +struct grub_lzopio +{ + grub_file_t file; + int has_ccheck; + int has_ucheck; + const gcry_md_spec_t *ucheck_fun; + const gcry_md_spec_t *ccheck_fun; + grub_off_t saved_off; /* Rounded down to block boundary. */ + grub_off_t start_block_off; + struct block_header block; +}; + +typedef struct grub_lzopio *grub_lzopio_t; +static struct grub_fs grub_lzopio_fs; + +/* Some helper functions. On errors memory allocated by those function is free + * either on close() so no risk of leaks. This makes functions simpler. */ + +/* Read block header from file, after successful exit file points to + * beginning of block data. */ +static int +read_block_header (struct grub_lzopio *lzopio) +{ + lzopio->saved_off += lzopio->block.usize; + + /* Free cached block data if any. */ + grub_free (lzopio->block.udata); + grub_free (lzopio->block.cdata); + lzopio->block.udata = NULL; + lzopio->block.cdata = NULL; + + if (grub_file_read (lzopio->file, &lzopio->block.usize, + sizeof (lzopio->block.usize)) != + sizeof (lzopio->block.usize)) + return -1; + + lzopio->block.usize = grub_be_to_cpu32 (lzopio->block.usize); + + /* Last block has uncompressed data size == 0 and no other fields. */ + if (lzopio->block.usize == 0) + { + if (grub_file_tell (lzopio->file) == grub_file_size (lzopio->file)) + return 0; + else + return -1; + } + + /* Read compressed data block size. */ + if (grub_file_read (lzopio->file, &lzopio->block.csize, + sizeof (lzopio->block.csize)) != + sizeof (lzopio->block.csize)) + return -1; + + lzopio->block.csize = grub_be_to_cpu32 (lzopio->block.csize); + + /* Corrupted. */ + if (lzopio->block.csize > lzopio->block.usize) + return -1; + + /* Read checksum of uncompressed data. */ + if (lzopio->has_ucheck) + { + if (grub_file_read (lzopio->file, &lzopio->block.ucheck, + sizeof (lzopio->block.ucheck)) != + sizeof (lzopio->block.ucheck)) + return -1; + + lzopio->block.ucheck = grub_be_to_cpu32 (lzopio->block.ucheck); + } + + /* Read checksum of compressed data. */ + if (lzopio->has_ccheck) + { + /* Incompressible data block. */ + if (lzopio->block.csize == lzopio->block.usize) + { + lzopio->block.ccheck = lzopio->block.ucheck; + } + else + { + if (grub_file_read (lzopio->file, &lzopio->block.ccheck, + sizeof (lzopio->block.ccheck)) != + sizeof (lzopio->block.ccheck)) + return -1; + + lzopio->block.ccheck = grub_be_to_cpu32 (lzopio->block.ccheck); + } + } + + return 0; +} + +/* Read block data into memory. File must be set to beginning of block data. + * Can't be called on last block. */ +static int +read_block_data (struct grub_lzopio *lzopio) +{ + lzopio->block.cdata = grub_malloc (lzopio->block.csize); + if (!lzopio->block.cdata) + return -1; + + if (grub_file_read (lzopio->file, lzopio->block.cdata, lzopio->block.csize) + != (grub_ssize_t) lzopio->block.csize) + return -1; + + if (lzopio->ccheck_fun) + { + grub_uint64_t context[(lzopio->ccheck_fun->contextsize + 7) / 8]; + + lzopio->ccheck_fun->init (context); + lzopio->ccheck_fun->write (context, lzopio->block.cdata, + lzopio->block.csize); + lzopio->ccheck_fun->final (context); + + if (grub_memcmp + (lzopio->ccheck_fun->read (context), &lzopio->block.ccheck, + sizeof (lzopio->block.ccheck)) != 0) + return -1; + } + + return 0; +} + +/* Read block data, uncompressed and also store it in memory. */ +/* XXX Investigate possibility of in-place decompression to reduce memory + * footprint. Or try to uncompress directly to buf if possible. */ +static int +uncompress_block (struct grub_lzopio *lzopio) +{ + lzo_uint usize = lzopio->block.usize; + + if (read_block_data (lzopio) < 0) + return -1; + + /* Incompressible data. */ + if (lzopio->block.csize == lzopio->block.usize) + { + lzopio->block.udata = lzopio->block.cdata; + lzopio->block.cdata = NULL; + } + else + { + lzopio->block.udata = grub_malloc (lzopio->block.usize); + if (!lzopio->block.udata) + return -1; + + if (lzo1x_decompress_safe (lzopio->block.cdata, lzopio->block.csize, + lzopio->block.udata, &usize, NULL) + != LZO_E_OK) + return -1; + + if (lzopio->ucheck_fun) + { + grub_uint64_t context[(lzopio->ucheck_fun->contextsize + 7) / 8]; + + lzopio->ucheck_fun->init (context); + lzopio->ucheck_fun->write (context, lzopio->block.udata, + lzopio->block.usize); + lzopio->ucheck_fun->final (context); + + if (grub_memcmp + (lzopio->ucheck_fun->read (context), &lzopio->block.ucheck, + sizeof (lzopio->block.ucheck)) != 0) + return -1; + } + + /* Compressed data can be free now. */ + grub_free (lzopio->block.cdata); + lzopio->block.cdata = NULL; + } + + return 0; +} + +/* Jump to next block and read its header. */ +static int +jump_block (struct grub_lzopio *lzopio) +{ + /* only jump if block was not decompressed (and read from disk) */ + if (!lzopio->block.udata) + { + grub_off_t off = grub_file_tell (lzopio->file) + lzopio->block.csize; + + if (grub_file_seek (lzopio->file, off) == ((grub_off_t) - 1)) + return -1; + } + + return read_block_header (lzopio); +} + +static int +calculate_uncompressed_size (grub_file_t file) +{ + grub_lzopio_t lzopio = file->data; + grub_off_t usize_total = 0; + + if (read_block_header (lzopio) < 0) + return -1; + + /* FIXME: Don't do this for not easily seekable files. */ + while (lzopio->block.usize != 0) + { + usize_total += lzopio->block.usize; + + if (jump_block (lzopio) < 0) + return -1; + } + + file->size = usize_total; + + return 0; +} + +struct lzop_header +{ + grub_uint8_t magic[LZOP_MAGIC_SIZE]; + grub_uint16_t lzop_version; + grub_uint16_t lib_version; + grub_uint16_t lib_version_ext; + grub_uint8_t method; + grub_uint8_t level; + grub_uint32_t flags; + /* grub_uint32_t filter; */ /* No filters support. Rarely used anyway. */ + grub_uint32_t mode; + grub_uint32_t mtime_lo; + grub_uint32_t mtime_hi; + grub_uint8_t name_len; +} __attribute__ ((packed)); + +static int +test_header (grub_file_t file) +{ + grub_lzopio_t lzopio = file->data; + struct lzop_header header; + grub_uint32_t flags, checksum; + const gcry_md_spec_t *hcheck; + grub_uint8_t *context = NULL; + grub_uint8_t *name = NULL; + + if (grub_file_read (lzopio->file, &header, sizeof (header)) != sizeof (header)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "no lzop magic found"); + return 0; + } + + if (grub_memcmp (header.magic, LZOP_MAGIC, LZOP_MAGIC_SIZE) != 0) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "no lzop magic found"); + return 0; + } + + if (grub_be_to_cpu16(header.lib_version) < LZOP_NEW_LIB) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "unsupported (too old) LZOP version"); + return 0; + } + + /* Too new version, should upgrade minilzo? */ + if (grub_be_to_cpu16 (header.lib_version_ext) > MINILZO_VERSION) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "unsupported (too new) LZO version"); + return 0; + } + + flags = grub_be_to_cpu32 (header.flags); + + if (flags & F_CRC32_D) + { + lzopio->has_ucheck = 1; + lzopio->ucheck_fun = grub_crypto_lookup_md_by_name ("crc32"); + } + else if (flags & F_ADLER32_D) + { + lzopio->has_ucheck = 1; + lzopio->ucheck_fun = grub_crypto_lookup_md_by_name ("adler32"); + } + + if (flags & F_CRC32_C) + { + lzopio->has_ccheck = 1; + lzopio->ccheck_fun = grub_crypto_lookup_md_by_name ("crc32"); + } + else if (flags & F_ADLER32_C) + { + lzopio->has_ccheck = 1; + lzopio->ccheck_fun = grub_crypto_lookup_md_by_name ("adler32"); + } + + if (flags & F_H_CRC32) + hcheck = grub_crypto_lookup_md_by_name ("crc32"); + else + hcheck = grub_crypto_lookup_md_by_name ("adler32"); + + if (hcheck) { + context = grub_malloc(hcheck->contextsize); + if (! context) + return 0; + + hcheck->init(context); + + /* MAGIC is not included in check calculation. */ + hcheck->write(context, &header.lzop_version, sizeof(header)- LZOP_MAGIC_SIZE); + } + + if (header.name_len != 0) + { + name = grub_malloc (header.name_len); + if (! name) + { + grub_free (context); + return 0; + } + + if (grub_file_read (lzopio->file, name, header.name_len) != + header.name_len) + { + grub_free(name); + goto CORRUPTED; + } + + if (hcheck) + hcheck->write(context, name, header.name_len); + + grub_free(name); + } + + if (hcheck) + hcheck->final(context); + + if (grub_file_read (lzopio->file, &checksum, sizeof (checksum)) != + sizeof (checksum)) + goto CORRUPTED; + + if (hcheck) + { + checksum = grub_cpu_to_be32(checksum); + if (grub_memcmp (&checksum, hcheck->read(context), sizeof(checksum)) != 0) + goto CORRUPTED; + } + + lzopio->start_block_off = grub_file_tell (lzopio->file); + + if (calculate_uncompressed_size (file) < 0) + goto CORRUPTED; + + /* Get back to start block. */ + grub_file_seek (lzopio->file, lzopio->start_block_off); + + /* Read first block - grub_lzopio_read() expects valid block. */ + if (read_block_header (lzopio) < 0) + goto CORRUPTED; + + lzopio->saved_off = 0; + return 1; + +CORRUPTED: + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "lzop file corrupted"); + + grub_free(name); + + return 0; +} + +static grub_file_t +grub_lzopio_open (grub_file_t io) +{ + grub_file_t file; + grub_lzopio_t lzopio; + + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (!file) + return 0; + + lzopio = grub_zalloc (sizeof (*lzopio)); + if (!lzopio) + { + grub_free (file); + return 0; + } + + lzopio->file = io; + + file->device = io->device; + file->offset = 0; + file->data = lzopio; + file->read_hook = 0; + file->fs = &grub_lzopio_fs; + file->size = GRUB_FILE_SIZE_UNKNOWN; + file->not_easily_seekable = 1; + + if (grub_file_tell (lzopio->file) != 0) + grub_file_seek (lzopio->file, 0); + + if (!test_header (file)) + { + grub_errno = GRUB_ERR_NONE; + grub_file_seek (io, 0); + grub_free (lzopio); + grub_free (file); + + return io; + } + + return file; +} + +static grub_ssize_t +grub_lzopio_read (grub_file_t file, char *buf, grub_size_t len) +{ + grub_lzopio_t lzopio = file->data; + grub_ssize_t ret = 0; + grub_off_t off; + + /* Backward seek before last read block. */ + if (lzopio->saved_off > grub_file_tell (file)) + { + grub_file_seek (lzopio->file, lzopio->start_block_off); + + if (read_block_header (lzopio) < 0) + goto CORRUPTED; + + lzopio->saved_off = 0; + } + + /* Forward to first block with requested data. */ + while (lzopio->saved_off + lzopio->block.usize <= grub_file_tell (file)) + { + /* EOF, could be possible files with unknown size. */ + if (lzopio->block.usize == 0) + return 0; + + if (jump_block (lzopio) < 0) + goto CORRUPTED; + } + + off = grub_file_tell (file) - lzopio->saved_off; + + while (len != 0 && lzopio->block.usize != 0) + { + grub_size_t to_copy; + + /* Block not decompressed yet. */ + if (!lzopio->block.udata && uncompress_block (lzopio) < 0) + goto CORRUPTED; + + /* Copy requested data into buffer. */ + to_copy = lzopio->block.usize - off; + if (to_copy > len) + to_copy = len; + grub_memcpy (buf, lzopio->block.udata + off, to_copy); + + len -= to_copy; + buf += to_copy; + ret += to_copy; + off = 0; + + /* Read next block if needed. */ + if (len > 0 && read_block_header (lzopio) < 0) + goto CORRUPTED; + } + + return ret; + +CORRUPTED: + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "lzop file corrupted"); + return -1; +} + +/* Release everything, including the underlying file object. */ +static grub_err_t +grub_lzopio_close (grub_file_t file) +{ + grub_lzopio_t lzopio = file->data; + + grub_file_close (lzopio->file); + grub_free (lzopio->block.cdata); + grub_free (lzopio->block.udata); + grub_free (lzopio); + + /* Device must not be closed twice. */ + file->device = 0; + return grub_errno; +} + +static struct grub_fs grub_lzopio_fs = { + .name = "lzopio", + .dir = 0, + .open = 0, + .read = grub_lzopio_read, + .close = grub_lzopio_close, + .label = 0, + .next = 0 +}; + +GRUB_MOD_INIT (lzopio) +{ + grub_file_filter_register (GRUB_FILE_FILTER_LZOPIO, grub_lzopio_open); +} + +GRUB_MOD_FINI (lzopio) +{ + grub_file_filter_unregister (GRUB_FILE_FILTER_LZOPIO); +} diff --git a/grub-core/io/xzio.c b/grub-core/io/xzio.c index 1a22bdc70..c9f648188 100644 --- a/grub-core/io/xzio.c +++ b/grub-core/io/xzio.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #include "xz.h" #include "xz_stream.h" @@ -46,7 +48,7 @@ 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) + grub_uint64_t *num) { if (size_max == 0) return 0; @@ -69,7 +71,7 @@ decode_vli (const grub_uint8_t buf[], grub_size_t size_max, } static grub_ssize_t -read_vli (grub_file_t file, grub_uint64_t * num) +read_vli (grub_file_t file, grub_uint64_t *num) { grub_uint8_t buf[VLI_MAX_DIGITS]; grub_ssize_t read; @@ -90,6 +92,8 @@ static int test_header (grub_file_t file) { grub_xzio_t xzio = file->data; + enum xz_ret ret; + xzio->buf.in_size = grub_file_read (xzio->file, xzio->inbuf, STREAM_HEADER_SIZE); @@ -99,7 +103,7 @@ test_header (grub_file_t file) return 0; } - enum xz_ret ret = xz_dec_run (xzio->dec, &xzio->buf); + ret = xz_dec_run (xzio->dec, &xzio->buf); if (ret == XZ_FORMAT_ERROR) { @@ -130,8 +134,8 @@ test_footer (grub_file_t file) 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 + if (grub_file_read (xzio->file, footer, FOOTER_MAGIC_SIZE) + != FOOTER_MAGIC_SIZE || grub_memcmp (footer, FOOTER_MAGIC, FOOTER_MAGIC_SIZE) != 0) goto ERROR; @@ -148,8 +152,8 @@ test_footer (grub_file_t 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) + if (grub_file_read (xzio->file, &imarker, sizeof (imarker)) + != sizeof (imarker) && imarker != 0x00) goto ERROR; if (read_vli (xzio->file, &records) <= 0) @@ -200,7 +204,7 @@ grub_xzio_open (grub_file_t io) file->read_hook = 0; file->fs = &grub_xzio_fs; file->size = GRUB_FILE_SIZE_UNKNOWN; - file->not_easly_seekable = 1; + file->not_easily_seekable = 1; if (grub_file_tell (xzio->file) != 0) grub_file_seek (xzio->file, 0); @@ -222,7 +226,8 @@ grub_xzio_open (grub_file_t io) xzio->buf.out_pos = 0; xzio->buf.out_size = XZBUFSIZ; - if (!test_header (file) || !(grub_file_seekable (io) && test_footer (file))) + /* FIXME: don't test footer on not easily seekable files. */ + if (!test_header (file) || !test_footer (file)) { grub_errno = GRUB_ERR_NONE; grub_file_seek (io, 0); @@ -261,9 +266,9 @@ grub_xzio_read (grub_file_t file, char *buf, grub_size_t len) while (len > 0) { - xzio->buf.out_size = grub_min (file->offset + ret + len - current_offset, - XZBUFSIZ); - + xzio->buf.out_size = file->offset + ret + len - current_offset; + if (xzio->buf.out_size > XZBUFSIZ) + xzio->buf.out_size = XZBUFSIZ; /* Feed input. */ if (xzio->buf.in_pos == xzio->buf.in_size) { diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c index 7f353b653..91e469181 100644 --- a/grub-core/kern/command.c +++ b/grub-core/kern/command.c @@ -52,7 +52,6 @@ grub_register_command_prio (const char *name, void grub_unregister_command (grub_command_t cmd) { - grub_prio_list_remove (GRUB_AS_PRIO_LIST_P (&grub_command_list), - GRUB_AS_PRIO_LIST (cmd)); + grub_prio_list_remove (GRUB_AS_PRIO_LIST (cmd)); grub_free (cmd); } diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c index 3db14f50e..c998d4d4b 100644 --- a/grub-core/kern/device.c +++ b/grub-core/kern/device.c @@ -26,6 +26,8 @@ #include #include +grub_net_t (*grub_net_open) (const char *name) = NULL; + grub_device_t grub_device_open (const char *name) { @@ -35,7 +37,7 @@ grub_device_open (const char *name) if (! name) { name = grub_env_get ("root"); - if (*name == '\0') + if (name == NULL || *name == '\0') { grub_error (GRUB_ERR_BAD_DEVICE, "no device is set"); goto fail; @@ -46,15 +48,19 @@ grub_device_open (const char *name) if (! dev) goto fail; + dev->net = NULL; /* Try to open a disk. */ - disk = grub_disk_open (name); - if (! disk) - goto fail; + dev->disk = grub_disk_open (name); + if (dev->disk) + return dev; + if (grub_net_open && grub_errno == GRUB_ERR_UNKNOWN_DEVICE) + { + grub_errno = GRUB_ERR_NONE; + dev->net = grub_net_open (name); + } - dev->disk = disk; - dev->net = 0; /* FIXME */ - - return dev; + if (dev->net) + return dev; fail: if (disk) @@ -71,6 +77,12 @@ grub_device_close (grub_device_t device) if (device->disk) grub_disk_close (device->disk); + if (device->net) + { + grub_free (device->net->server); + grub_free (device->net); + } + grub_free (device); return grub_errno; diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c index 807ee4277..df772d531 100644 --- a/grub-core/kern/disk.c +++ b/grub-core/kern/disk.c @@ -46,11 +46,7 @@ static struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM]; void (*grub_disk_firmware_fini) (void); int grub_disk_firmware_is_tainted; -grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t, - struct grub_disk_ata_pass_through_parms *); - - -#if 0 +#if DISK_CACHE_STATS static unsigned long grub_disk_cache_hits; static unsigned long grub_disk_cache_misses; @@ -123,13 +119,13 @@ grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id, && cache->sector == sector) { cache->lock = 1; -#if 0 +#if DISK_CACHE_STATS grub_disk_cache_hits++; #endif return cache->data; } -#if 0 +#if DISK_CACHE_STATS grub_disk_cache_misses++; #endif @@ -181,7 +177,7 @@ grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id, -static grub_disk_dev_t grub_disk_dev_list; +grub_disk_dev_t grub_disk_dev_list; void grub_disk_dev_register (grub_disk_dev_t dev) @@ -203,18 +199,6 @@ grub_disk_dev_unregister (grub_disk_dev_t dev) } } -int -grub_disk_dev_iterate (int (*hook) (const char *name)) -{ - grub_disk_dev_t p; - - for (p = grub_disk_dev_list; p; p = p->next) - if (p->iterate && (p->iterate) (hook)) - return 1; - - return 0; -} - /* Return the location of the first ',', if any, which is not escaped by a '\'. */ static const char * @@ -247,6 +231,7 @@ grub_disk_open (const char *name) disk = (grub_disk_t) grub_zalloc (sizeof (*disk)); if (! disk) return 0; + disk->log_sector_size = GRUB_DISK_SECTOR_BITS; p = find_part_sep (name); if (p) @@ -266,7 +251,6 @@ grub_disk_open (const char *name) if (! disk->name) goto fail; - for (dev = grub_disk_dev_list; dev; dev = dev->next) { if ((dev->open) (raw, disk) == GRUB_ERR_NONE) @@ -282,6 +266,14 @@ grub_disk_open (const char *name) grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk"); goto fail; } + if (disk->log_sector_size > GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS + || disk->log_sector_size < GRUB_DISK_SECTOR_BITS) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "sector sizes of %d bytes aren't supported yet", + (1 << disk->log_sector_size)); + goto fail; + } disk->dev = dev; @@ -373,21 +365,113 @@ grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector, *sector += start; } - if (disk->total_sectors <= *sector - || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1) - >> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector) + if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN + && ((disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) <= *sector + || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1) + >> GRUB_DISK_SECTOR_BITS) > (disk->total_sectors + << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) - *sector)) return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk"); return GRUB_ERR_NONE; } +static inline grub_disk_addr_t +transform_sector (grub_disk_t disk, grub_disk_addr_t sector) +{ + return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); +} + +/* Small read (less than cache size and not pass across cache unit boundaries). + sector is already adjusted and is divisible by cache unit size. + */ +static grub_err_t +grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector, + grub_off_t offset, grub_size_t size, void *buf) +{ + char *data; + char *tmp_buf; + + /* Fetch the cache. */ + data = grub_disk_cache_fetch (disk->dev->id, disk->id, sector); + if (data) + { + /* Just copy it! */ + grub_memcpy (buf, data + offset, size); + grub_disk_cache_unlock (disk->dev->id, disk->id, sector); + return GRUB_ERR_NONE; + } + + /* Allocate a temporary buffer. */ + tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS); + if (! tmp_buf) + return grub_errno; + + /* Otherwise read data from the disk actually. */ + if (disk->total_sectors == GRUB_DISK_SIZE_UNKNOWN + || sector + GRUB_DISK_CACHE_SIZE + < (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS))) + { + grub_err_t err; + err = (disk->dev->read) (disk, transform_sector (disk, sector), + 1 << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS + - disk->log_sector_size), tmp_buf); + if (!err) + { + /* Copy it and store it in the disk cache. */ + grub_memcpy (buf, tmp_buf + offset, size); + grub_disk_cache_store (disk->dev->id, disk->id, + sector, tmp_buf); + grub_free (tmp_buf); + return GRUB_ERR_NONE; + } + } + + grub_free (tmp_buf); + grub_errno = GRUB_ERR_NONE; + + { + /* Uggh... Failed. Instead, just read necessary data. */ + unsigned num; + grub_disk_addr_t aligned_sector; + + sector += (offset >> GRUB_DISK_SECTOR_BITS); + offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1); + aligned_sector = (sector & ~((1 << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) + - 1)); + offset += ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS); + num = ((size + offset + (1 << (disk->log_sector_size)) + - 1) >> (disk->log_sector_size)); + + tmp_buf = grub_malloc (num << disk->log_sector_size); + if (!tmp_buf) + return grub_errno; + + if ((disk->dev->read) (disk, transform_sector (disk, aligned_sector), + num, tmp_buf)) + { + grub_error_push (); + grub_dprintf ("disk", "%s read failed\n", disk->name); + grub_error_pop (); + grub_free (tmp_buf); + return grub_errno; + } + grub_memcpy (buf, tmp_buf + offset, size); + grub_free (tmp_buf); + return GRUB_ERR_NONE; + } +} + /* Read data from the disk. */ grub_err_t grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_off_t offset, grub_size_t size, void *buf) { - char *tmp_buf; - unsigned real_offset; + grub_off_t real_offset; + grub_disk_addr_t real_sector; + grub_size_t real_size; /* First of all, check if the region is within the disk. */ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) @@ -399,126 +483,126 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, return grub_errno; } + real_sector = sector; real_offset = offset; + real_size = size; - /* Allocate a temporary buffer. */ - tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS); - if (! tmp_buf) - return grub_errno; - - /* Until SIZE is zero... */ - while (size) + /* First read until first cache boundary. */ + if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1))) { - char *data; grub_disk_addr_t start_sector; - grub_size_t len; grub_size_t pos; + grub_err_t err; + grub_size_t len; - /* For reading bulk data. */ start_sector = sector & ~(GRUB_DISK_CACHE_SIZE - 1); pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS; len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS) - - pos - real_offset); + - pos - offset); if (len > size) len = size; - - /* Fetch the cache. */ - data = grub_disk_cache_fetch (disk->dev->id, disk->id, start_sector); - if (data) - { - /* Just copy it! */ - grub_memcpy (buf, data + pos + real_offset, len); - grub_disk_cache_unlock (disk->dev->id, disk->id, start_sector); - } - else - { - /* Otherwise read data from the disk actually. */ - if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors - || (disk->dev->read) (disk, start_sector, - GRUB_DISK_CACHE_SIZE, tmp_buf) - != GRUB_ERR_NONE) - { - /* Uggh... Failed. Instead, just read necessary data. */ - unsigned num; - char *p; - - grub_errno = GRUB_ERR_NONE; - - num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1) - >> GRUB_DISK_SECTOR_BITS); - - p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS); - if (!p) - goto finish; - - tmp_buf = p; - - if ((disk->dev->read) (disk, sector, num, tmp_buf)) - { - grub_error_push (); - grub_dprintf ("disk", "%s read failed\n", disk->name); - grub_error_pop (); - goto finish; - } - - grub_memcpy (buf, tmp_buf + real_offset, size); - - /* Call the read hook, if any. */ - if (disk->read_hook) - while (size) - { - grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size; - (disk->read_hook) (sector, real_offset, - to_read); - if (grub_errno != GRUB_ERR_NONE) - goto finish; - - sector++; - size -= to_read - real_offset; - real_offset = 0; - } - - /* This must be the end. */ - goto finish; - } - - /* Copy it and store it in the disk cache. */ - grub_memcpy (buf, tmp_buf + pos + real_offset, len); - grub_disk_cache_store (disk->dev->id, disk->id, - start_sector, tmp_buf); - } - - /* Call the read hook, if any. */ - if (disk->read_hook) - { - grub_disk_addr_t s = sector; - grub_size_t l = len; - - while (l) - { - (disk->read_hook) (s, real_offset, - ((l > GRUB_DISK_SECTOR_SIZE) - ? GRUB_DISK_SECTOR_SIZE - : l)); - - if (l < GRUB_DISK_SECTOR_SIZE - real_offset) - break; - - s++; - l -= GRUB_DISK_SECTOR_SIZE - real_offset; - real_offset = 0; - } - } - - sector = start_sector + GRUB_DISK_CACHE_SIZE; + err = grub_disk_read_small (disk, start_sector, + offset + pos, len, buf); + if (err) + return err; buf = (char *) buf + len; size -= len; - real_offset = 0; + offset += len; + sector += (offset >> GRUB_DISK_SECTOR_BITS); + offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1); } - finish: + /* Until SIZE is zero... */ + while (size >= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS)) + { + char *data = NULL; + grub_disk_addr_t agglomerate; + grub_err_t err; - grub_free (tmp_buf); + /* agglomerate read until we find a first cached entry. */ + for (agglomerate = 0; agglomerate + < (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS)); + agglomerate++) + { + data = grub_disk_cache_fetch (disk->dev->id, disk->id, + sector + (agglomerate + << GRUB_DISK_CACHE_BITS)); + if (data) + break; + } + + if (data) + { + grub_memcpy ((char *) buf + + (agglomerate << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS)), + data, GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS); + grub_disk_cache_unlock (disk->dev->id, disk->id, + sector + (agglomerate + << GRUB_DISK_CACHE_BITS)); + } + + if (agglomerate) + { + grub_disk_addr_t i; + + err = (disk->dev->read) (disk, transform_sector (disk, sector), + agglomerate << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS + - disk->log_sector_size), + buf); + if (err) + return err; + + for (i = 0; i < agglomerate; i ++) + grub_disk_cache_store (disk->dev->id, disk->id, + sector + (i << GRUB_DISK_CACHE_BITS), + (char *) buf + + (i << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS))); + + sector += agglomerate << GRUB_DISK_CACHE_BITS; + size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS); + buf = (char *) buf + + (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS)); + } + + if (data) + { + sector += GRUB_DISK_CACHE_SIZE; + buf = (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS); + size -= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS); + } + } + + /* And now read the last part. */ + if (size) + { + grub_err_t err; + err = grub_disk_read_small (disk, sector, 0, size, buf); + if (err) + return err; + } + + /* Call the read hook, if any. */ + if (disk->read_hook) + { + grub_disk_addr_t s = real_sector; + grub_size_t l = real_size; + grub_off_t o = real_offset; + + while (l) + { + grub_size_t cl; + cl = GRUB_DISK_SECTOR_SIZE - o; + if (cl > l) + cl = l; + (disk->read_hook) (s, o, cl); + s++; + l -= cl; + o = 0; + } + } return grub_errno; } @@ -528,25 +612,31 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector, grub_off_t offset, grub_size_t size, const void *buf) { unsigned real_offset; + grub_disk_addr_t aligned_sector; grub_dprintf ("disk", "Writing `%s'...\n", disk->name); if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) return -1; - real_offset = offset; + aligned_sector = (sector & ~((1 << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) - 1)); + real_offset = offset + ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS); + sector = aligned_sector; while (size) { - if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0)) + if (real_offset != 0 || (size < (1U << disk->log_sector_size) + && size != 0)) { - char tmp_buf[GRUB_DISK_SECTOR_SIZE]; + char tmp_buf[1 << disk->log_sector_size]; grub_size_t len; grub_partition_t part; part = disk->partition; disk->partition = 0; - if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf) + if (grub_disk_read (disk, sector, + 0, (1 << disk->log_sector_size), tmp_buf) != GRUB_ERR_NONE) { disk->partition = part; @@ -554,7 +644,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector, } disk->partition = part; - len = GRUB_DISK_SECTOR_SIZE - real_offset; + len = (1 << disk->log_sector_size) - real_offset; if (len > size) len = size; @@ -565,7 +655,7 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector, if ((disk->dev->write) (disk, sector, 1, tmp_buf) != GRUB_ERR_NONE) goto finish; - sector++; + sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); buf = (char *) buf + len; size -= len; real_offset = 0; @@ -575,8 +665,8 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t len; grub_size_t n; - len = size & ~(GRUB_DISK_SECTOR_SIZE - 1); - n = size >> GRUB_DISK_SECTOR_BITS; + len = size & ~((1 << disk->log_sector_size) - 1); + n = size >> disk->log_sector_size; if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE) goto finish; @@ -599,6 +689,8 @@ grub_disk_get_size (grub_disk_t disk) { if (disk->partition) return grub_partition_get_len (disk->partition); + else if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN) + return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); else - return disk->total_sectors; + return GRUB_DISK_SIZE_UNKNOWN; } diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 02d785b9b..aaeb01f00 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -37,6 +37,10 @@ #define GRUB_MODULES_MACHINE_READONLY #endif +#ifdef GRUB_MACHINE_EMU +#include +#endif + grub_dl_t grub_dl_head = 0; @@ -86,6 +90,7 @@ struct grub_symbol struct grub_symbol *next; const char *name; void *addr; + int isfunc; grub_dl_t mod; /* The module to which this symbol belongs. */ }; typedef struct grub_symbol *grub_symbol_t; @@ -110,21 +115,22 @@ grub_symbol_hash (const char *s) /* Resolve the symbol name NAME and return the address. Return NULL, if not found. */ -static void * +static grub_symbol_t grub_dl_resolve_symbol (const char *name) { grub_symbol_t sym; for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next) if (grub_strcmp (sym->name, name) == 0) - return sym->addr; + return sym; return 0; } /* Register a symbol with the name NAME and the address ADDR. */ grub_err_t -grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod) +grub_dl_register_symbol (const char *name, void *addr, int isfunc, + grub_dl_t mod) { grub_symbol_t sym; unsigned k; @@ -147,6 +153,7 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod) sym->addr = addr; sym->mod = mod; + sym->isfunc = isfunc; k = grub_symbol_hash (name); sym->next = grub_symtab[k]; @@ -225,6 +232,49 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) { unsigned i; Elf_Shdr *s; + grub_size_t tsize = 0, talign = 1; +#if defined (__ia64__) || defined (__powerpc__) + grub_size_t tramp; + grub_size_t got; +#endif + char *ptr; + + for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + { + tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; + if (talign < s->sh_addralign) + talign = s->sh_addralign; + } + +#if defined (__ia64__) || defined (__powerpc__) + grub_arch_dl_get_tramp_got_size (e, &tramp, &got); + tramp *= GRUB_ARCH_DL_TRAMP_SIZE; + got *= sizeof (grub_uint64_t); + tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN); + if (talign < GRUB_ARCH_DL_TRAMP_ALIGN) + talign = GRUB_ARCH_DL_TRAMP_ALIGN; + tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN); + if (talign < GRUB_ARCH_DL_GOT_ALIGN) + talign = GRUB_ARCH_DL_GOT_ALIGN; +#endif + +#ifdef GRUB_MACHINE_EMU + if (talign < 8192 * 16) + talign = 8192 * 16; + tsize = ALIGN_UP (tsize, 8192 * 16); +#endif + + mod->base = grub_memalign (talign, tsize); + if (!mod->base) + return grub_errno; + mod->sz = tsize; + ptr = mod->base; + +#ifdef GRUB_MACHINE_EMU + mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC); +#endif for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); i < e->e_shnum; @@ -242,12 +292,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) { void *addr; - addr = grub_memalign (s->sh_addralign, s->sh_size); - if (! addr) - { - grub_free (seg); - return grub_errno; - } + ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign); + addr = ptr; + ptr += s->sh_size; switch (s->sh_type) { @@ -270,6 +317,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) mod->segment = seg; } } +#if defined (__ia64__) || defined (__powerpc__) + ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN); + mod->tramp = ptr; + ptr += tramp; + ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN); + mod->got = ptr; + ptr += got; +#endif return GRUB_ERR_NONE; } @@ -320,17 +375,20 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) /* Resolve a global symbol. */ if (sym->st_name != 0 && sym->st_shndx == 0) { - sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name); - if (! sym->st_value) + grub_symbol_t nsym = grub_dl_resolve_symbol (name); + if (! nsym) return grub_error (GRUB_ERR_BAD_MODULE, "symbol not found: `%s'", name); + sym->st_value = (Elf_Addr) nsym->addr; + if (nsym->isfunc) + sym->st_info = ELF_ST_INFO (bind, STT_FUNC); } else { sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, sym->st_shndx); if (bind != STB_LOCAL) - if (grub_dl_register_symbol (name, (void *) sym->st_value, mod)) + if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod)) return grub_errno; } break; @@ -338,10 +396,21 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) case STT_FUNC: sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod, sym->st_shndx); +#ifdef __ia64__ + { + /* FIXME: free descriptor once it's not used anymore. */ + char **desc; + desc = grub_malloc (2 * sizeof (char *)); + if (!desc) + return grub_errno; + desc[0] = (void *) sym->st_value; + desc[1] = mod->base; + sym->st_value = (grub_addr_t) desc; + } +#endif if (bind != STB_LOCAL) - if (grub_dl_register_symbol (name, (void *) sym->st_value, mod)) + if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod)) return grub_errno; - if (grub_strcmp (name, "grub_mod_init") == 0) mod->init = (void (*) (grub_dl_t)) sym->st_value; else if (grub_strcmp (name, "grub_mod_fini") == 0) @@ -373,6 +442,38 @@ grub_dl_call_init (grub_dl_t mod) (mod->init) (mod); } +/* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally + multi-licensed under other licences as well) independently of the + presence of this check and solely by linking (module loading in GRUB + constitutes linking) and GRUB core being licensed under GPLv3+. + Be sure to understand your license obligations. +*/ +static grub_err_t +grub_dl_check_license (Elf_Ehdr *e) +{ + Elf_Shdr *s; + const char *str; + unsigned i; + + s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); + str = (char *) e + s->sh_offset; + + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (grub_strcmp (str + s->sh_name, ".module_license") == 0) + { + if (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0 + || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0 + || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0) + return GRUB_ERR_NONE; + } + + return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license"); +} + static grub_err_t grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e) { @@ -475,15 +576,9 @@ grub_dl_unref (grub_dl_t mod) static void grub_dl_flush_cache (grub_dl_t mod) { - grub_dl_segment_t seg; - - for (seg = mod->segment; seg; seg = seg->next) { - if (seg->size) { - grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n", - (unsigned long) seg->size, seg->addr); - grub_arch_sync_caches (seg->addr, seg->size); - } - } + grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n", + (unsigned long) mod->sz, mod->base); + grub_arch_sync_caches (mod->base, mod->sz); } /* Load a module from core memory. */ @@ -519,7 +614,16 @@ grub_dl_load_core (void *addr, grub_size_t size) mod->ref_count = 1; grub_dprintf ("modules", "relocating to %p\n", mod); - if (grub_dl_resolve_name (mod, e) + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally + multi-licensed under other licences as well) independently of the + presence of this check and solely by linking (module loading in GRUB + constitutes linking) and GRUB core being licensed under GPLv3+. + Be sure to understand your license obligations. + */ + if (grub_dl_check_license (e) + || grub_dl_resolve_name (mod, e) || grub_dl_resolve_dependencies (mod, e) || grub_dl_load_segments (mod, e) || grub_dl_resolve_symbols (mod, e) @@ -579,13 +683,11 @@ grub_dl_load_file (const char *filename) grub_file_close (file); mod = grub_dl_load_core (core, size); + grub_free (core); if (! mod) - { - grub_free (core); - return 0; - } + return 0; - mod->ref_count = 0; + mod->ref_count--; return mod; } @@ -595,7 +697,7 @@ grub_dl_load (const char *name) { char *filename; grub_dl_t mod; - char *grub_dl_dir = grub_env_get ("prefix"); + const char *grub_dl_dir = grub_env_get ("prefix"); mod = grub_dl_get (name); if (mod) @@ -627,7 +729,6 @@ int grub_dl_unload (grub_dl_t mod) { grub_dl_dep_t dep, depn; - grub_dl_segment_t seg, segn; if (mod->ref_count > 0) return 0; @@ -642,19 +743,12 @@ grub_dl_unload (grub_dl_t mod) { depn = dep->next; - if (! grub_dl_unref (dep->mod)) - grub_dl_unload (dep->mod); + grub_dl_unload (dep->mod); grub_free (dep); } - for (seg = mod->segment; seg; seg = segn) - { - segn = seg->next; - grub_free (seg->addr); - grub_free (seg); - } - + grub_free (mod->base); grub_free (mod->name); #ifdef GRUB_MODULES_MACHINE_READONLY grub_free (mod->symtab); diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index fa1d0c730..9a2c5e64d 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -162,18 +163,6 @@ grub_exit (void) for (;;) ; } -/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */ -#ifndef __i386__ -void -grub_reboot (void) -{ - grub_efi_fini (); - efi_call_4 (grub_efi_system_table->runtime_services->reset_system, - GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); - for (;;) ; -} -#endif - grub_err_t grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, grub_efi_uintn_t descriptor_size, @@ -193,8 +182,8 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed"); } -grub_uint32_t -grub_get_rtc (void) +grub_uint64_t +grub_rtc_get_time_ms (void) { grub_efi_time_t time; grub_efi_runtime_services_t *r; @@ -204,15 +193,20 @@ grub_get_rtc (void) /* What is possible in this case? */ return 0; - return (((time.minute * 60 + time.second) * 1000 - + time.nanosecond / 1000000) - * GRUB_TICKS_PER_SECOND / 1000); + return ((time.minute * 60 + time.second) * 1000 + + time.nanosecond / 1000000); +} + +grub_uint32_t +grub_get_rtc (void) +{ + return grub_rtc_get_time_ms (); } /* Search the mods section from the PE32/PE32+ image. This code uses a PE32 header, but should work with PE32+ as well. */ grub_addr_t -grub_arch_modules_addr (void) +grub_efi_modules_addr (void) { grub_efi_loaded_image_t *image; struct grub_pe32_header *header; @@ -740,3 +734,51 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) dp = (grub_efi_device_path_t *) ((char *) dp + len); } } + +/* Compare device paths. */ +int +grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2) +{ + if (! dp1 || ! dp2) + /* Return non-zero. */ + return 1; + + while (1) + { + grub_efi_uint8_t type1, type2; + grub_efi_uint8_t subtype1, subtype2; + grub_efi_uint16_t len1, len2; + int ret; + + type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1); + type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2); + + if (type1 != type2) + return (int) type2 - (int) type1; + + subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1); + subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2); + + if (subtype1 != subtype2) + return (int) subtype1 - (int) subtype2; + + len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1); + len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2); + + if (len1 != len2) + return (int) len1 - (int) len2; + + ret = grub_memcmp (dp1, dp2, len1); + if (ret != 0) + return ret; + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1)) + break; + + dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1); + dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2); + } + + return 0; +} diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c index 1b0a872b4..942ab0256 100644 --- a/grub-core/kern/efi/init.c +++ b/grub-core/kern/efi/init.c @@ -26,9 +26,12 @@ #include #include +grub_addr_t grub_modbase; + void grub_efi_init (void) { + grub_modbase = grub_efi_modules_addr (); /* First of all, initialize the console so that GRUB can display messages. */ grub_console_init (); @@ -42,84 +45,28 @@ grub_efi_init (void) grub_efidisk_init (); } +void (*grub_efi_net_config) (grub_efi_handle_t hnd, + char **device, + char **path); + void -grub_efi_set_prefix (void) +grub_machine_get_bootlocation (char **device, char **path) { grub_efi_loaded_image_t *image = NULL; - char *device = NULL; - char *path = NULL; + char *p; - { - char *pptr = NULL; - if (grub_prefix[0] == '(') - { - pptr = grub_strrchr (grub_prefix, ')'); - if (pptr) - { - device = grub_strndup (grub_prefix + 1, pptr - grub_prefix - 1); - pptr++; - } - } - if (!pptr) - pptr = grub_prefix; - if (pptr[0]) - path = grub_strdup (pptr); - } + image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (!image) + return; + *device = grub_efidisk_get_device_name (image->device_handle); + *path = grub_efi_get_filename (image->file_path); + if (!*device && grub_efi_net_config) + grub_efi_net_config (image->device_handle, device, path); - if ((!device || device[0] == ',' || !device[0]) || !path) - image = grub_efi_get_loaded_image (grub_efi_image_handle); - if (image) - { - if (!device) - device = grub_efidisk_get_device_name (image->device_handle); - else if (device[0] == ',' || !device[0]) - { - /* We have a partition, but still need to fill in the drive. */ - char *image_device, *comma, *new_device; - - image_device = grub_efidisk_get_device_name (image->device_handle); - comma = grub_strchr (image_device, ','); - if (comma) - { - char *drive = grub_strndup (image_device, comma - image_device); - new_device = grub_xasprintf ("%s%s", drive, device); - grub_free (drive); - } - else - new_device = grub_xasprintf ("%s%s", image_device, device); - - grub_free (image_device); - grub_free (device); - device = new_device; - } - } - - if (image && !path) - { - char *p; - - path = grub_efi_get_filename (image->file_path); - - /* Get the directory. */ - p = grub_strrchr (path, '/'); - if (p) - *p = '\0'; - } - - if (device && path) - { - char *prefix; - - prefix = grub_xasprintf ("(%s)%s", device, path); - if (prefix) - { - grub_env_set ("prefix", prefix); - grub_free (prefix); - } - } - - grub_free (device); - grub_free (path); + /* Get the directory. */ + p = grub_strrchr (*path, '/'); + if (p) + *p = '\0'; } void diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index c845d7df1..8b9e6ec25 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -25,26 +25,13 @@ #define NEXT_MEMORY_DESCRIPTOR(desc, size) \ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) -#define BYTES_TO_PAGES(bytes) ((bytes) >> 12) +#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) #define PAGES_TO_BYTES(pages) ((pages) << 12) /* The size of a memory map obtained from the firmware. This must be a multiplier of 4KB. */ #define MEMORY_MAP_SIZE 0x3000 -/* Maintain the list of allocated pages. */ -struct allocated_page -{ - grub_efi_physical_address_t addr; - grub_efi_uint64_t num_pages; -}; - -#define ALLOCATED_PAGES_SIZE 0x1000 -#define MAX_ALLOCATED_PAGES \ - (ALLOCATED_PAGES_SIZE / sizeof (struct allocated_page)) - -static struct allocated_page *allocated_pages = 0; - /* The minimum and maximum heap size for GRUB itself. */ #define MIN_HEAP_SIZE 0x100000 #define MAX_HEAP_SIZE (1600 * 0x100000) @@ -65,13 +52,13 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, grub_efi_status_t status; grub_efi_boot_services_t *b; -#if GRUB_TARGET_SIZEOF_VOID_P < 8 +#if 1 /* Limit the memory access to less than 4GB for 32-bit platforms. */ if (address > 0xffffffff) return 0; #endif -#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL) +#if 1 if (address == 0) { type = GRUB_EFI_ALLOCATE_MAX_ADDRESS; @@ -102,22 +89,6 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, return 0; } - if (allocated_pages) - { - unsigned i; - - for (i = 0; i < MAX_ALLOCATED_PAGES; i++) - if (allocated_pages[i].addr == 0) - { - allocated_pages[i].addr = address; - allocated_pages[i].num_pages = pages; - break; - } - - if (i == MAX_ALLOCATED_PAGES) - grub_fatal ("too many page allocations"); - } - return (void *) ((grub_addr_t) address); } @@ -128,20 +99,6 @@ grub_efi_free_pages (grub_efi_physical_address_t address, { grub_efi_boot_services_t *b; - if (allocated_pages - && ((grub_efi_physical_address_t) ((grub_addr_t) allocated_pages) - != address)) - { - unsigned i; - - for (i = 0; i < MAX_ALLOCATED_PAGES; i++) - if (allocated_pages[i].addr == address) - { - allocated_pages[i].addr = 0; - break; - } - } - b = grub_efi_system_table->boot_services; efi_call_2 (b->free_pages, address, pages); } @@ -294,7 +251,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY -#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL) +#if 1 && desc->physical_start <= 0xffffffff #endif && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 @@ -310,7 +267,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, desc->physical_start = 0x100000; } -#if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL) +#if 1 if (BYTES_TO_PAGES (filtered_desc->physical_start) + filtered_desc->num_pages > BYTES_TO_PAGES (0x100000000LL)) @@ -422,14 +379,6 @@ grub_efi_mm_init (void) grub_efi_uint64_t required_pages; int mm_status; - /* First of all, allocate pages to maintain allocations. */ - allocated_pages - = grub_efi_allocate_pages (0, BYTES_TO_PAGES (ALLOCATED_PAGES_SIZE)); - if (! allocated_pages) - grub_fatal ("cannot allocate memory"); - - grub_memset (allocated_pages, 0, ALLOCATED_PAGES_SIZE); - /* Prepare a memory region to store two memory maps. */ memory_map = grub_efi_allocate_pages (0, 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); @@ -447,6 +396,9 @@ grub_efi_mm_init (void) ((grub_efi_physical_address_t) ((grub_addr_t) memory_map), 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + /* Freeing/allocating operations may increase memory map size. */ + map_size += desc_size * 32; + memory_map = grub_efi_allocate_pages (0, 2 * BYTES_TO_PAGES (map_size)); if (! memory_map) grub_fatal ("cannot allocate memory"); @@ -499,24 +451,3 @@ grub_efi_mm_init (void) grub_efi_free_pages ((grub_addr_t) memory_map, 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); } - -void -grub_efi_mm_fini (void) -{ - if (allocated_pages) - { - unsigned i; - - for (i = 0; i < MAX_ALLOCATED_PAGES; i++) - { - struct allocated_page *p; - - p = allocated_pages + i; - if (p->addr != 0) - grub_efi_free_pages ((grub_addr_t) p->addr, p->num_pages); - } - - grub_efi_free_pages ((grub_addr_t) allocated_pages, - BYTES_TO_PAGES (ALLOCATED_PAGES_SIZE)); - } -} diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 4be408c31..9c7b8cec2 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -23,6 +23,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* Check if EHDR is a valid ELF header. */ static grub_err_t @@ -171,11 +174,12 @@ grub_elf32_phdr_iterate (grub_elf_t elf, /* Calculate the amount of memory spanned by the segments. */ grub_size_t -grub_elf32_size (grub_elf_t elf, Elf32_Addr *base) +grub_elf32_size (grub_elf_t elf, Elf32_Addr *base, grub_uint32_t *max_align) { Elf32_Addr segments_start = (Elf32_Addr) -1; Elf32_Addr segments_end = 0; int nr_phdrs = 0; + grub_uint32_t curr_align = 1; /* Run through the program headers to calculate the total memory size we * should claim. */ @@ -192,6 +196,8 @@ grub_elf32_size (grub_elf_t elf, Elf32_Addr *base) segments_start = phdr->p_paddr; if (phdr->p_paddr + phdr->p_memsz > segments_end) segments_end = phdr->p_paddr + phdr->p_memsz; + if (curr_align < phdr->p_align) + curr_align = phdr->p_align; return 0; } @@ -215,7 +221,8 @@ grub_elf32_size (grub_elf_t elf, Elf32_Addr *base) if (base) *base = segments_start; - + if (max_align) + *max_align = curr_align; return segments_end - segments_start; } @@ -290,7 +297,6 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook, return err; } - /* 64-bit */ @@ -357,16 +363,17 @@ grub_elf64_phdr_iterate (grub_elf_t elf, /* Calculate the amount of memory spanned by the segments. */ grub_size_t -grub_elf64_size (grub_elf_t elf, Elf64_Addr *base) +grub_elf64_size (grub_elf_t elf, Elf64_Addr *base, grub_uint64_t *max_align) { Elf64_Addr segments_start = (Elf64_Addr) -1; Elf64_Addr segments_end = 0; int nr_phdrs = 0; + grub_uint64_t curr_align = 1; /* Run through the program headers to calculate the total memory size we * should claim. */ auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg); - int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)), + int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf __attribute__ ((unused)), Elf64_Phdr *phdr, void *_arg __attribute__ ((unused))) { @@ -378,6 +385,8 @@ grub_elf64_size (grub_elf_t elf, Elf64_Addr *base) segments_start = phdr->p_paddr; if (phdr->p_paddr + phdr->p_memsz > segments_end) segments_end = phdr->p_paddr + phdr->p_memsz; + if (curr_align < phdr->p_align) + curr_align = phdr->p_align; return 0; } @@ -401,11 +410,11 @@ grub_elf64_size (grub_elf_t elf, Elf64_Addr *base) if (base) *base = segments_start; - + if (max_align) + *max_align = curr_align; return segments_end - segments_start; } - /* Load every loadable segment into memory specified by `_load_hook'. */ grub_err_t grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook, diff --git a/grub-core/kern/emu/cache.c b/grub-core/kern/emu/cache.c new file mode 100644 index 000000000..543e457e5 --- /dev/null +++ b/grub-core/kern/emu/cache.c @@ -0,0 +1,13 @@ + +#if defined(__ia64__) +#include + +void __clear_cache (char *beg, char *end); + +void +grub_arch_sync_caches (void *address, grub_size_t len) +{ + __clear_cache (address, (char *) address + len); +} +#endif + diff --git a/grub-core/kern/emu/cache.S b/grub-core/kern/emu/cache_s.S similarity index 96% rename from grub-core/kern/emu/cache.S rename to grub-core/kern/emu/cache_s.S index abd81c910..8ca695c28 100644 --- a/grub-core/kern/emu/cache.S +++ b/grub-core/kern/emu/cache_s.S @@ -23,6 +23,7 @@ FUNCTION (grub_arch_sync_caches) .set macro #elif defined(__powerpc__) #include "../powerpc/cache.S" +#elif defined(__ia64__) #else #error "No target cpu type is defined" #endif diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c index 70bcae78f..1ecd34f7d 100644 --- a/grub-core/kern/emu/full.c +++ b/grub-core/kern/emu/full.c @@ -50,6 +50,15 @@ grub_emu_init (void) grub_no_autoload = 1; } +#ifdef __ia64__ +void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)), + grub_size_t *tramp, grub_size_t *got) +{ + *tramp = 0; + *got = 0; +} +#endif + #ifdef GRUB_LINKER_HAVE_INIT void grub_arch_dl_init_linker (void) @@ -63,8 +72,8 @@ grub_emu_post_init (void) grub_lvm_fini (); grub_mdraid09_fini (); grub_mdraid1x_fini (); - grub_raid_fini (); - grub_raid_init (); + grub_diskfilter_fini (); + grub_diskfilter_init (); grub_mdraid09_init (); grub_mdraid1x_init (); grub_lvm_init (); diff --git a/grub-core/kern/emu/getroot.c b/grub-core/kern/emu/getroot.c deleted file mode 100644 index 0433d49ed..000000000 --- a/grub-core/kern/emu/getroot.c +++ /dev/null @@ -1,840 +0,0 @@ -/* getroot.c - Get root device */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * 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 - -#ifdef __GNU__ -#include -#include -#include -#include -#endif - -#ifdef __linux__ -# include -# include -#endif - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) -# include -# include -#endif - -#include -#include -#include -#include -#include - -static void -strip_extra_slashes (char *dir) -{ - char *p = dir; - - while ((p = strchr (p, '/')) != 0) - { - if (p[1] == '/') - { - memmove (p, p + 1, strlen (p)); - continue; - } - else if (p[1] == '\0') - { - if (p > dir) - p[0] = '\0'; - break; - } - - p++; - } -} - -static char * -xgetcwd (void) -{ - size_t size = 10; - char *path; - - path = xmalloc (size); - while (! getcwd (path, size)) - { - size <<= 1; - path = xrealloc (path, size); - } - - return path; -} - -#ifdef __linux__ - -/* Statting something on a btrfs filesystem always returns a virtual device - major/minor pair rather than the real underlying device, because btrfs - can span multiple underlying devices (and even if it's currently only - using a single device it can be dynamically extended onto another). We - can't deal with the multiple-device case yet, but in the meantime, we can - at least cope with the single-device case by scanning - /proc/self/mountinfo. */ -static char * -find_root_device_from_mountinfo (const char *dir) -{ - FILE *fp; - char *buf = NULL; - size_t len = 0; - char *ret = NULL; - - fp = fopen ("/proc/self/mountinfo", "r"); - if (! fp) - return NULL; /* fall through to other methods */ - - while (getline (&buf, &len, fp) > 0) - { - int mnt_id, parent_mnt_id; - unsigned int major, minor; - char enc_root[PATH_MAX], enc_path[PATH_MAX]; - int count; - size_t enc_path_len; - const char *sep; - char fstype[PATH_MAX], device[PATH_MAX]; - struct stat st; - - if (sscanf (buf, "%d %d %u:%u %s %s%n", - &mnt_id, &parent_mnt_id, &major, &minor, enc_root, enc_path, - &count) < 6) - continue; - - if (strcmp (enc_root, "/") != 0) - continue; /* only a subtree is mounted */ - - enc_path_len = strlen (enc_path); - if (strncmp (dir, enc_path, enc_path_len) != 0 || - (dir[enc_path_len] && dir[enc_path_len] != '/')) - continue; - - /* This is a parent of the requested directory. /proc/self/mountinfo - is in mount order, so it must be the closest parent we've - encountered so far. If it's virtual, return its device node; - otherwise, carry on to try to find something closer. */ - - free (ret); - ret = NULL; - - if (major != 0) - continue; /* not a virtual device */ - - sep = strstr (buf + count, " - "); - if (!sep) - continue; - - sep += sizeof (" - ") - 1; - if (sscanf (sep, "%s %s", fstype, device) != 2) - continue; - - if (stat (device, &st) < 0) - continue; - - if (!S_ISBLK (st.st_mode)) - continue; /* not a block device */ - - ret = strdup (device); - } - - free (buf); - fclose (fp); - return ret; -} - -#endif /* __linux__ */ - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) -static char * -find_root_device_from_libzfs (const char *dir) -{ - char *device; - char *poolname; - char *poolfs; - - grub_find_zpool_from_dir (dir, &poolname, &poolfs); - if (! poolname) - return NULL; - - { - zpool_handle_t *zpool; - libzfs_handle_t *libzfs; - nvlist_t *config, *vdev_tree; - nvlist_t **children, **path; - unsigned int nvlist_count; - unsigned int i; - - libzfs = grub_get_libzfs_handle (); - if (! libzfs) - return NULL; - - zpool = zpool_open (libzfs, poolname); - config = zpool_get_config (zpool, NULL); - - if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0) - error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); - - if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0) - error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); - assert (nvlist_count > 0); - - while (nvlist_lookup_nvlist_array (children[0], "children", - &children, &nvlist_count) == 0) - assert (nvlist_count > 0); - - for (i = 0; i < nvlist_count; i++) - { - if (nvlist_lookup_string (children[i], "path", &device) != 0) - error (1, errno, "nvlist_lookup_string (\"path\")"); - - struct stat st; - if (stat (device, &st) == 0) - break; - - device = NULL; - } - - zpool_close (zpool); - } - - free (poolname); - if (poolfs) - free (poolfs); - - return device; -} -#endif - -#ifdef __MINGW32__ - -char * -grub_find_device (const char *dir __attribute__ ((unused)), - dev_t dev __attribute__ ((unused))) -{ - return 0; -} - -#elif ! defined(__CYGWIN__) - -char * -grub_find_device (const char *dir, dev_t dev) -{ - DIR *dp; - char *saved_cwd; - struct dirent *ent; - - if (! dir) - { -#ifdef __CYGWIN__ - return NULL; -#else - dir = "/dev"; -#endif - } - - dp = opendir (dir); - if (! dp) - return 0; - - saved_cwd = xgetcwd (); - - grub_util_info ("changing current directory to %s", dir); - if (chdir (dir) < 0) - { - free (saved_cwd); - closedir (dp); - return 0; - } - - while ((ent = readdir (dp)) != 0) - { - struct stat st; - - /* Avoid: - - dotfiles (like "/dev/.tmp.md0") since they could be duplicates. - - dotdirs (like "/dev/.static") since they could contain duplicates. */ - if (ent->d_name[0] == '.') - continue; - - if (lstat (ent->d_name, &st) < 0) - /* Ignore any error. */ - continue; - - if (S_ISLNK (st.st_mode)) { -#ifdef __linux__ - if (strcmp (dir, "mapper") == 0) { - /* Follow symbolic links under /dev/mapper/; the canonical name - may be something like /dev/dm-0, but the names under - /dev/mapper/ are more human-readable and so we prefer them if - we can get them. */ - if (stat (ent->d_name, &st) < 0) - continue; - } else -#endif /* __linux__ */ - /* Don't follow other symbolic links. */ - continue; - } - - if (S_ISDIR (st.st_mode)) - { - /* Find it recursively. */ - char *res; - - res = grub_find_device (ent->d_name, dev); - - if (res) - { - if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); - - free (saved_cwd); - closedir (dp); - return res; - } - } - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) - if (S_ISCHR (st.st_mode) && st.st_rdev == dev) -#else - if (S_ISBLK (st.st_mode) && st.st_rdev == dev) -#endif - { -#ifdef __linux__ - /* Skip device names like /dev/dm-0, which are short-hand aliases - to more descriptive device names, e.g. those under /dev/mapper */ - if (ent->d_name[0] == 'd' && - ent->d_name[1] == 'm' && - ent->d_name[2] == '-' && - ent->d_name[3] >= '0' && - ent->d_name[3] <= '9') - continue; -#endif - - /* Found! */ - char *res; - char *cwd; -#if defined(__NetBSD__) - /* Convert this block device to its character (raw) device. */ - const char *template = "%s/r%s"; -#else - /* Keep the device name as it is. */ - const char *template = "%s/%s"; -#endif - - cwd = xgetcwd (); - res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3); - sprintf (res, template, cwd, ent->d_name); - strip_extra_slashes (res); - free (cwd); - - /* /dev/root is not a real block device keep looking, takes care - of situation where root filesystem is on the same partition as - grub files */ - - if (strcmp(res, "/dev/root") == 0) - continue; - - if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); - - free (saved_cwd); - closedir (dp); - return res; - } - } - - if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); - - free (saved_cwd); - closedir (dp); - return 0; -} - -#else /* __CYGWIN__ */ - -/* Read drive/partition serial number from mbr/boot sector, - return 0 on read error, ~0 on unknown serial. */ -static unsigned -get_bootsec_serial (const char *os_dev, int mbr) -{ - /* Read boot sector. */ - int fd = open (os_dev, O_RDONLY); - if (fd < 0) - return 0; - unsigned char buf[0x200]; - int n = read (fd, buf, sizeof (buf)); - close (fd); - if (n != sizeof(buf)) - return 0; - - /* Check signature. */ - if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa)) - return ~0; - - /* Serial number offset depends on boot sector type. */ - if (mbr) - n = 0x1b8; - else if (memcmp (buf + 0x03, "NTFS", 4) == 0) - n = 0x048; - else if (memcmp (buf + 0x52, "FAT32", 5) == 0) - n = 0x043; - else if (memcmp (buf + 0x36, "FAT", 3) == 0) - n = 0x027; - else - return ~0; - - unsigned serial = *(unsigned *)(buf + n); - if (serial == 0) - return ~0; - return serial; -} - -char * -grub_find_device (const char *path, dev_t dev) -{ - /* No root device for /cygdrive. */ - if (dev == (DEV_CYGDRIVE_MAJOR << 16)) - return 0; - - /* Convert to full POSIX and Win32 path. */ - char fullpath[PATH_MAX], winpath[PATH_MAX]; - cygwin_conv_to_full_posix_path (path, fullpath); - cygwin_conv_to_full_win32_path (fullpath, winpath); - - /* If identical, this is no real filesystem path. */ - if (strcmp (fullpath, winpath) == 0) - return 0; - - /* Check for floppy drive letter. */ - if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0])) - return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1"); - - /* Cygwin returns the partition serial number in stat.st_dev. - This is never identical to the device number of the emulated - /dev/sdXN device, so above grub_find_device () does not work. - Search the partition with the same serial in boot sector instead. */ - char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */ - int d; - for (d = 'a'; d <= 'z'; d++) - { - sprintf (devpath, "/dev/sd%c", d); - if (get_bootsec_serial (devpath, 1) == 0) - continue; - int p; - for (p = 1; p <= 15; p++) - { - sprintf (devpath, "/dev/sd%c%d", d, p); - unsigned ser = get_bootsec_serial (devpath, 0); - if (ser == 0) - break; - if (ser != (unsigned)~0 && dev == (dev_t)ser) - return xstrdup (devpath); - } - } - return 0; -} - -#endif /* __CYGWIN__ */ - -char * -grub_guess_root_device (const char *dir) -{ - char *os_dev; -#ifdef __GNU__ - file_t file; - mach_port_t *ports; - int *ints; - loff_t *offsets; - char *data; - error_t err; - mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0; - size_t name_len; - - file = file_name_lookup (dir, 0, 0); - if (file == MACH_PORT_NULL) - return 0; - - err = file_get_storage_info (file, - &ports, &num_ports, - &ints, &num_ints, - &offsets, &num_offsets, - &data, &data_len); - - if (num_ints < 1) - grub_util_error ("Storage info for `%s' does not include type", dir); - if (ints[0] != STORAGE_DEVICE) - grub_util_error ("Filesystem of `%s' is not stored on local disk", dir); - - if (num_ints < 5) - grub_util_error ("Storage info for `%s' does not include name", dir); - name_len = ints[4]; - if (name_len < data_len) - grub_util_error ("Bogus name length for storage info for `%s'", dir); - if (data[name_len - 1] != '\0') - grub_util_error ("Storage name for `%s' not NUL-terminated", dir); - - os_dev = xmalloc (strlen ("/dev/") + data_len); - memcpy (os_dev, "/dev/", strlen ("/dev/")); - memcpy (os_dev + strlen ("/dev/"), data, data_len); - - if (ports && num_ports > 0) - { - mach_msg_type_number_t i; - for (i = 0; i < num_ports; i++) - { - mach_port_t port = ports[i]; - if (port != MACH_PORT_NULL) - mach_port_deallocate (mach_task_self(), port); - } - munmap ((caddr_t) ports, num_ports * sizeof (*ports)); - } - - if (ints && num_ints > 0) - munmap ((caddr_t) ints, num_ints * sizeof (*ints)); - if (offsets && num_offsets > 0) - munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets)); - if (data && data_len > 0) - munmap (data, data_len); - mach_port_deallocate (mach_task_self (), file); -#else /* !__GNU__ */ - struct stat st; - -#ifdef __linux__ - os_dev = find_root_device_from_mountinfo (dir); - if (os_dev) - return os_dev; -#endif /* __linux__ */ - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - os_dev = find_root_device_from_libzfs (dir); - if (os_dev) - return os_dev; -#endif - - if (stat (dir, &st) < 0) - grub_util_error ("cannot stat `%s'", dir); - -#ifdef __CYGWIN__ - /* Cygwin specific function. */ - os_dev = grub_find_device (dir, st.st_dev); - -#else - - /* This might be truly slow, but is there any better way? */ - os_dev = grub_find_device ("/dev", st.st_dev); -#endif -#endif /* !__GNU__ */ - - return os_dev; -} - -static int -grub_util_is_dmraid (const char *os_dev) -{ - if (! strncmp (os_dev, "/dev/mapper/nvidia_", 19)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/isw_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/hpt37x_", 19)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/hpt45x_", 19)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/via_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/lsi_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/pdc_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/jmicron_", 20)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/asr_", 16)) - return 1; - else if (! strncmp (os_dev, "/dev/mapper/sil_", 16)) - return 1; - - return 0; -} - -int -grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) -{ -#ifdef __linux__ - /* User explicitly claims that this drive is visible by BIOS. */ - if (grub_util_biosdisk_is_present (os_dev)) - return GRUB_DEV_ABSTRACTION_NONE; - - /* Check for LVM. */ - if (!strncmp (os_dev, "/dev/mapper/", 12) - && ! grub_util_is_dmraid (os_dev) - && strncmp (os_dev, "/dev/mapper/mpath", 17) != 0) - return GRUB_DEV_ABSTRACTION_LVM; - - /* Check for RAID. */ - if (!strncmp (os_dev, "/dev/md", 7)) - return GRUB_DEV_ABSTRACTION_RAID; -#endif - - /* No abstraction found. */ - return GRUB_DEV_ABSTRACTION_NONE; -} - -#ifdef __linux__ -static char * -get_mdadm_name (const char *os_dev) -{ - int mdadm_pipe[2]; - pid_t mdadm_pid; - char *name = NULL; - - if (pipe (mdadm_pipe) < 0) - { - grub_util_warn ("Unable to create pipe for mdadm: %s", strerror (errno)); - return NULL; - } - - mdadm_pid = fork (); - if (mdadm_pid < 0) - grub_util_warn ("Unable to fork mdadm: %s", strerror (errno)); - else if (mdadm_pid == 0) - { - /* Child. */ - char *argv[5]; - - close (mdadm_pipe[0]); - dup2 (mdadm_pipe[1], STDOUT_FILENO); - close (mdadm_pipe[1]); - - /* execvp has inconvenient types, hence the casts. None of these - strings will actually be modified. */ - argv[0] = (char *) "mdadm"; - argv[1] = (char *) "--detail"; - argv[2] = (char *) "--export"; - argv[3] = (char *) os_dev; - argv[4] = NULL; - execvp ("mdadm", argv); - exit (127); - } - else - { - /* Parent. Read mdadm's output. */ - FILE *mdadm; - char *buf = NULL; - size_t len = 0; - - close (mdadm_pipe[1]); - mdadm = fdopen (mdadm_pipe[0], "r"); - if (! mdadm) - { - grub_util_warn ("Unable to open stream from mdadm: %s", - strerror (errno)); - goto out; - } - - while (getline (&buf, &len, mdadm) > 0) - { - if (strncmp (buf, "MD_NAME=", sizeof ("MD_NAME=") - 1) == 0) - { - char *name_start, *colon; - size_t name_len; - - free (name); - name_start = buf + sizeof ("MD_NAME=") - 1; - /* Strip off the homehost if present. */ - colon = strchr (name_start, ':'); - name = strdup (colon ? colon + 1 : name_start); - name_len = strlen (name); - if (name[name_len - 1] == '\n') - name[name_len - 1] = '\0'; - } - } - -out: - close (mdadm_pipe[0]); - waitpid (mdadm_pid, NULL, 0); - } - - return name; -} -#endif /* __linux__ */ - -char * -grub_util_get_grub_dev (const char *os_dev) -{ - char *grub_dev = NULL; - - switch (grub_util_get_dev_abstraction (os_dev)) - { - case GRUB_DEV_ABSTRACTION_LVM: - - { - unsigned short i, len; - grub_size_t offset = sizeof ("/dev/mapper/") - 1; - - len = strlen (os_dev) - offset + 1; - grub_dev = xmalloc (len); - - for (i = 0; i < len; i++, offset++) - { - grub_dev[i] = os_dev[offset]; - if (os_dev[offset] == '-' && os_dev[offset + 1] == '-') - offset++; - } - } - - break; - - case GRUB_DEV_ABSTRACTION_RAID: - - if (os_dev[7] == '_' && os_dev[8] == 'd') - { - /* This a partitionable RAID device of the form /dev/md_dNNpMM. */ - - char *p, *q; - - p = strdup (os_dev + sizeof ("/dev/md_d") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] == '/' && os_dev[8] == 'd') - { - /* This a partitionable RAID device of the form /dev/md/dNNpMM. */ - - char *p, *q; - - p = strdup (os_dev + sizeof ("/dev/md/d") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] >= '0' && os_dev[7] <= '9') - { - char *p , *q; - - p = strdup (os_dev + sizeof ("/dev/md") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9') - { - char *p , *q; - - p = strdup (os_dev + sizeof ("/dev/md/") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md%s", p); - free (p); - } - else if (os_dev[7] == '/') - { - /* mdraid 1.x with a free name. */ - char *p , *q; - - p = strdup (os_dev + sizeof ("/dev/md/") - 1); - - q = strchr (p, 'p'); - if (q) - *q = ','; - - grub_dev = xasprintf ("md/%s", p); - free (p); - } - else - grub_util_error ("unknown kind of RAID device `%s'", os_dev); - -#ifdef __linux__ - { - char *mdadm_name = get_mdadm_name (os_dev); - - if (mdadm_name) - { - free (grub_dev); - grub_dev = xasprintf ("md/%s", mdadm_name); - free (mdadm_name); - } - } -#endif /* __linux__ */ - - break; - - default: /* GRUB_DEV_ABSTRACTION_NONE */ - grub_dev = grub_util_biosdisk_get_grub_dev (os_dev); - } - - return grub_dev; -} - -const char * -grub_util_check_block_device (const char *blk_dev) -{ - struct stat st; - - if (stat (blk_dev, &st) < 0) - grub_util_error ("cannot stat `%s'", blk_dev); - - if (S_ISBLK (st.st_mode)) - return (blk_dev); - else - return 0; -} - -const char * -grub_util_check_char_device (const char *blk_dev) -{ - struct stat st; - - if (stat (blk_dev, &st) < 0) - grub_util_error ("cannot stat `%s'", blk_dev); - - if (S_ISCHR (st.st_mode)) - return (blk_dev); - else - return 0; -} diff --git a/grub-core/kern/emu/hostdisk.c b/grub-core/kern/emu/hostdisk.c index 08f60ee66..704911e12 100644 --- a/grub-core/kern/emu/hostdisk.c +++ b/grub-core/kern/emu/hostdisk.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #ifdef __linux__ # include /* ioctl */ +# include # if !defined(__GLIBC__) || \ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) /* Maybe libc doesn't have large file support. */ @@ -66,32 +68,24 @@ struct hd_geometry # ifndef BLKGETSIZE64 # define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */ # endif /* ! BLKGETSIZE64 */ -# ifndef MAJOR -# ifndef MINORBITS -# define MINORBITS 8 -# endif /* ! MINORBITS */ -# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS)) -# endif /* ! MAJOR */ -# ifndef FLOPPY_MAJOR -# define FLOPPY_MAJOR 2 -# endif /* ! FLOPPY_MAJOR */ -# ifndef LOOP_MAJOR -# define LOOP_MAJOR 7 -# endif /* ! LOOP_MAJOR */ #endif /* __linux__ */ #ifdef __CYGWIN__ # include # include /* BLKGETSIZE64 */ # include /* HDIO_GETGEO */ -# define MAJOR(dev) ((unsigned) ((dev) >> 16)) -# define FLOPPY_MAJOR 2 #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) # include /* DIOCGMEDIASIZE */ # include # include +# include +#include +#endif + +#if defined (__sun__) +# include #endif #if defined(__APPLE__) @@ -102,7 +96,7 @@ struct hd_geometry # include #endif -#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__NetBSD__) # define HAVE_DIOCGDINFO # include # include /* struct disklabel */ @@ -115,9 +109,6 @@ struct hd_geometry # include /* getrawpartition */ # endif /* HAVE_GETRAWPARTITION */ # include -# ifndef FLOPPY_MAJOR -# define FLOPPY_MAJOR 2 -# endif /* ! FLOPPY_MAJOR */ # ifndef RAW_FLOPPY_MAJOR # define RAW_FLOPPY_MAJOR 9 # endif /* ! RAW_FLOPPY_MAJOR */ @@ -127,6 +118,7 @@ struct { char *drive; char *device; + int device_map; } map[256]; struct grub_util_biosdisk_data @@ -134,6 +126,8 @@ struct grub_util_biosdisk_data char *dev; int access_mode; int fd; + int is_disk; + int device_map; }; #ifdef __linux__ @@ -179,6 +173,27 @@ configure_device_driver (int fd) } #endif /* defined(__NetBSD__) */ +static int +unescape_cmp (const char *a, const char *b_escaped) +{ + while (*a || *b_escaped) + { + if (*b_escaped == '\\' && b_escaped[1] != 0) + b_escaped++; + if (*a < *b_escaped) + return -1; + if (*a > *b_escaped) + return +1; + a++; + b_escaped++; + } + if (*a) + return +1; + if (*b_escaped) + return -1; + return 0; +} + static int find_grub_drive (const char *name) { @@ -187,7 +202,7 @@ find_grub_drive (const char *name) if (name) { for (i = 0; i < ARRAY_SIZE (map); i++) - if (map[i].drive && ! strcmp (map[i].drive, name)) + if (map[i].drive && unescape_cmp (map[i].drive, name) == 0) return i; } @@ -207,10 +222,14 @@ find_free_slot (void) } static int -grub_util_biosdisk_iterate (int (*hook) (const char *name)) +grub_util_biosdisk_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { unsigned i; + if (pull != GRUB_DISK_PULL_NONE) + return 0; + for (i = 0; i < sizeof (map) / sizeof (map[0]); i++) if (map[i].drive && hook (map[i].drive)) return 1; @@ -218,6 +237,98 @@ grub_util_biosdisk_iterate (int (*hook) (const char *name)) return 0; } +#if !defined(__MINGW32__) +grub_uint64_t +grub_util_get_fd_sectors (int fd, unsigned *log_secsize) +{ +# if defined(__NetBSD__) + struct disklabel label; +# elif defined (__sun__) + struct dk_minfo minfo; +#else + unsigned long long nr; +# endif + unsigned sector_size, log_sector_size; + struct stat st; + + if (fstat (fd, &st) < 0) + grub_util_error (_("fstat failed")); + +#if defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) \ + || defined (__sun__) + +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__) + if (! S_ISCHR (st.st_mode)) +# else + if (! S_ISBLK (st.st_mode)) +# endif + goto fail; + +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + if (ioctl (fd, DIOCGMEDIASIZE, &nr)) +# elif defined(__APPLE__) + if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr)) +# elif defined(__NetBSD__) + configure_device_driver (fd); + if (ioctl (fd, DIOCGDINFO, &label) == -1) +# elif defined (__sun__) + if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo)) +# else + if (ioctl (fd, BLKGETSIZE64, &nr)) +# endif + goto fail; + +# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + if (ioctl (fd, DIOCGSECTORSIZE, §or_size)) + goto fail; +# elif defined(__sun__) + sector_size = minfo.dki_lbsize; +# elif defined(__NetBSD__) + sector_size = label.d_secsize; +# else + if (ioctl (fd, BLKSSZGET, §or_size)) + goto fail; +# endif + if (sector_size & (sector_size - 1) || !sector_size) + goto fail; + for (log_sector_size = 0; + (1 << log_sector_size) < sector_size; + log_sector_size++); + + if (log_secsize) + *log_secsize = log_sector_size; + +# if defined (__APPLE__) + return nr; +# elif defined(__NetBSD__) + return label.d_secperunit; +# elif defined (__sun__) + return minfo.dki_capacity; +# else + if (nr & ((1 << log_sector_size) - 1)) + grub_util_error (_("unaligned device size")); + + return (nr >> log_sector_size); +# endif + + fail: + + /* In GNU/Hurd, stat() will return the right size. */ +#elif !defined (__GNU__) +# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal." +#endif + + sector_size = 512; + log_sector_size = 9; + + if (log_secsize) + *log_secsize = 9; + + return st.st_size >> 9; +} +#endif + static grub_err_t grub_util_biosdisk_open (const char *name, grub_disk_t disk) { @@ -235,6 +346,8 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) data->dev = NULL; data->access_mode = 0; data->fd = -1; + data->is_disk = 0; + data->device_map = map[drive].device_map; /* Get the size. */ #if defined(__MINGW32__) @@ -244,7 +357,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) size = grub_util_get_disk_size (map[drive].device); if (size % 512) - grub_util_error ("unaligned device size"); + grub_util_error (_("unaligned device size")); disk->total_sectors = size >> 9; @@ -252,97 +365,122 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) return GRUB_ERR_NONE; } -#elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) +#else { -# if defined(__NetBSD__) - struct disklabel label; -# else - unsigned long long nr; -# endif int fd; fd = open (map[drive].device, O_RDONLY); if (fd == -1) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device); + disk->total_sectors = grub_util_get_fd_sectors (fd, &disk->log_sector_size); + # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode)) # else if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode)) # endif - { - close (fd); - goto fail; - } - -# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - if (ioctl (fd, DIOCGMEDIASIZE, &nr)) -# elif defined(__APPLE__) - if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr)) -# elif defined(__NetBSD__) - configure_device_driver (fd); - if (ioctl (fd, DIOCGDINFO, &label) == -1) -# else - if (ioctl (fd, BLKGETSIZE64, &nr)) -# endif - { - close (fd); - goto fail; - } + data->is_disk = 1; close (fd); -# if defined (__APPLE__) - disk->total_sectors = nr; -# elif defined(__NetBSD__) - disk->total_sectors = label.d_secperunit; -# else - disk->total_sectors = nr / 512; - - if (nr % 512) - grub_util_error ("unaligned device size"); -# endif - grub_util_info ("the size of %s is %llu", name, disk->total_sectors); return GRUB_ERR_NONE; } - - fail: - /* In GNU/Hurd, stat() will return the right size. */ -#elif !defined (__GNU__) -# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal." #endif - if (stat (map[drive].device, &st) < 0) - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device); - - disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS; - - grub_util_info ("the size of %s is %lu", name, disk->total_sectors); - - return GRUB_ERR_NONE; } -#ifdef HAVE_DEVICE_MAPPER -static int -device_is_mapped (const char *dev) +int +grub_util_device_is_mapped (const char *dev) { +#ifdef HAVE_DEVICE_MAPPER struct stat st; + if (!grub_device_mapper_supported ()) + return 0; + if (stat (dev, &st) < 0) return 0; return dm_is_dm_major (major (st.st_rdev)); -} +#else + return 0; #endif /* HAVE_DEVICE_MAPPER */ +} -#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) -static grub_disk_addr_t -find_partition_start (const char *dev) + +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) + +/* FIXME: geom actually gives us the whole container hierarchy. + It can be used more efficiently than this. */ +void +grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out) +{ + struct gmesh mesh; + struct gclass *class; + int error; + struct ggeom *geom; + + grub_util_info ("following geom '%s'", name); + + error = geom_gettree (&mesh); + if (error != 0) + grub_util_error (_("couldn't open geom")); + + LIST_FOREACH (class, &mesh.lg_class, lg_class) + if (strcasecmp (class->lg_name, "part") == 0) + break; + if (!class) + grub_util_error (_("couldn't open geom part")); + + LIST_FOREACH (geom, &class->lg_geom, lg_geom) + { + struct gprovider *provider; + LIST_FOREACH (provider, &geom->lg_provider, lg_provider) + if (strcmp (provider->lg_name, name) == 0) + { + char *name_tmp = xstrdup (geom->lg_name); + grub_disk_addr_t off = 0; + struct gconfig *config; + grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name); + + grub_util_follow_gpart_up (name_tmp, &off, name_out); + free (name_tmp); + LIST_FOREACH (config, &provider->lg_config, lg_config) + if (strcasecmp (config->lg_name, "start") == 0) + off += strtoull (config->lg_val, 0, 10); + if (off_out) + *off_out = off; + return; + } + } + grub_util_info ("geom '%s' has no parent", name); + if (name_out) + *name_out = xstrdup (name); + if (off_out) + *off_out = 0; +} + +grub_disk_addr_t +grub_hostdisk_find_partition_start (const char *dev) +{ + grub_disk_addr_t out; + if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0) + return 0; + grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL); + + return out; +} + +#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__) +grub_disk_addr_t +grub_hostdisk_find_partition_start (const char *dev) { int fd; -# if !defined(HAVE_DIOCGDINFO) +#ifdef __sun__ + struct extpart_info pinfo; +# elif !defined(HAVE_DIOCGDINFO) struct hd_geometry hdg; # else /* defined(HAVE_DIOCGDINFO) */ struct disklabel label; @@ -350,7 +488,7 @@ find_partition_start (const char *dev) # endif /* !defined(HAVE_DIOCGDINFO) */ # ifdef HAVE_DEVICE_MAPPER - if (grub_device_mapper_supported () && device_is_mapped (dev)) { + if (grub_util_device_is_mapped (dev)) { struct dm_task *task = NULL; grub_uint64_t start, length; char *target_type, *params, *space; @@ -429,7 +567,9 @@ devmapper_fail: return 0; } -# if !defined(HAVE_DIOCGDINFO) +#if defined(__sun__) + if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo)) +# elif !defined(HAVE_DIOCGDINFO) if (ioctl (fd, HDIO_GETGEO, &hdg)) # else /* defined(HAVE_DIOCGDINFO) */ # if defined(__NetBSD__) @@ -450,12 +590,17 @@ devmapper_fail: close (fd); -# if !defined(HAVE_DIOCGDINFO) +#ifdef __sun__ + return pinfo.p_start; +# elif !defined(HAVE_DIOCGDINFO) return hdg.start; # else /* defined(HAVE_DIOCGDINFO) */ - p_index = dev[strlen(dev) - 1] - 'a'; - - if (p_index >= label.d_npartitions) + if (dev[0]) + p_index = dev[strlen(dev) - 1] - 'a'; + else + p_index = -1; + + if (p_index >= label.d_npartitions || p_index < 0) { grub_error (GRUB_ERR_BAD_DEVICE, "no disk label entry for `%s'", dev); @@ -471,6 +616,7 @@ devmapper_fail: struct linux_partition_cache { struct linux_partition_cache *next; + struct linux_partition_cache **prev; char *dev; unsigned long start; int partno; @@ -479,7 +625,7 @@ struct linux_partition_cache struct linux_partition_cache *linux_partition_cache_list; static int -linux_find_partition (char *dev, unsigned long sector) +linux_find_partition (char *dev, grub_disk_addr_t sector) { size_t len = strlen (dev); const char *format; @@ -487,6 +633,7 @@ linux_find_partition (char *dev, unsigned long sector) int i; char real_dev[PATH_MAX]; struct linux_partition_cache *cache; + int missing = 0; strcpy(real_dev, dev); @@ -495,6 +642,12 @@ linux_find_partition (char *dev, unsigned long sector) p = real_dev + len - 4; format = "part%d"; } + else if (strncmp (real_dev, "/dev/disk/by-id/", + sizeof ("/dev/disk/by-id/") - 1) == 0) + { + p = real_dev + len; + format = "-part%d"; + } else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9') { p = real_dev + len; @@ -525,10 +678,16 @@ linux_find_partition (char *dev, unsigned long sector) fd = open (real_dev, O_RDONLY); if (fd == -1) - return 0; + { + if (missing++ < 10) + continue; + else + return 0; + } + missing = 0; close (fd); - start = find_partition_start (real_dev); + start = grub_hostdisk_find_partition_start (real_dev); /* We don't care about errors here. */ grub_errno = GRUB_ERR_NONE; @@ -552,6 +711,63 @@ linux_find_partition (char *dev, unsigned long sector) } #endif /* __linux__ */ +#if defined(__linux__) && (!defined(__GLIBC__) || \ + ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) + /* Maybe libc doesn't have large file support. */ +grub_err_t +grub_util_fd_seek (int fd, const char *name, grub_uint64_t off) +{ + loff_t offset, result; + static int _llseek (uint filedes, ulong hi, ulong lo, + loff_t *res, uint wh); + _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); + + offset = (loff_t) off; + if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) + { + return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name); + } + return GRUB_ERR_NONE; +} +#else +grub_err_t +grub_util_fd_seek (int fd, const char *name, grub_uint64_t off) +{ + off_t offset = (off_t) off; + + if (lseek (fd, offset, SEEK_SET) != offset) + return grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", name); + return 0; +} +#endif + +const char * +grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (map); i++) + if (! map[i].device) + break; + else if (strcmp (map[i].device, os_disk) == 0) + return map[i].drive; + + if (!add) + return NULL; + + if (i == ARRAY_SIZE (map)) + grub_util_error (_("device count exceeds limit")); + + map[i].device = xstrdup (os_disk); + map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk)); + strcpy (map[i].drive, "hostdisk/"); + strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk); + map[i].device_map = 0; + + return map[i].drive; +} + static int open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { @@ -596,7 +812,19 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { free (data->dev); if (data->fd != -1) - close (data->fd); + { + if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY) + { + fsync (data->fd); +#ifdef __linux__ + if (data->is_disk) + ioctl (data->fd, BLKFLSBUF, 0); +#endif + } + + close (data->fd); + data->fd = -1; + } /* Open the partition. */ grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev); @@ -607,10 +835,6 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) return -1; } - /* Flush the buffer cache to the physical disk. - XXX: This also empties the buffer cache. */ - ioctl (fd, BLKFLSBUF, 0); - data->dev = xstrdup (dev); data->access_mode = (flags & O_ACCMODE); data->fd = fd; @@ -648,7 +872,18 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { free (data->dev); if (data->fd != -1) - close (data->fd); + { + if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY) + { + fsync (data->fd); +#ifdef __linux__ + if (data->is_disk) + ioctl (data->fd, BLKFLSBUF, 0); +#endif + } + close (data->fd); + data->fd = -1; + } fd = open (map[disk->id].device, flags); if (fd >= 0) @@ -685,44 +920,20 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) configure_device_driver (fd); #endif /* defined(__NetBSD__) */ -#if defined(__linux__) && (!defined(__GLIBC__) || \ - ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) - /* Maybe libc doesn't have large file support. */ - { - loff_t offset, result; - static int _llseek (uint filedes, ulong hi, ulong lo, - loff_t *res, uint wh); - _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, - loff_t *, res, uint, wh); - - offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS; - if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); - close (fd); - return -1; - } - } -#else - { - off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS; - - if (lseek (fd, offset, SEEK_SET) != offset) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device); - close (fd); - return -1; - } - } -#endif + if (grub_util_fd_seek (fd, map[disk->id].device, + sector << disk->log_sector_size)) + { + close (fd); + return -1; + } return fd; } /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an error occurs, otherwise return LEN. */ -static ssize_t -nread (int fd, char *buf, size_t len) +ssize_t +grub_util_fd_read (int fd, char *buf, size_t len) { ssize_t size = len; @@ -747,8 +958,8 @@ nread (int fd, char *buf, size_t len) /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an error occurs, otherwise return LEN. */ -static ssize_t -nwrite (int fd, const char *buf, size_t len) +ssize_t +grub_util_fd_write (int fd, const char *buf, size_t len) { ssize_t size = len; @@ -805,20 +1016,20 @@ grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, sectors that are read together with the MBR in one read. It should only remap the MBR, so we split the read in two parts. -jochen */ - if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) + if (grub_util_fd_read (fd, buf, (1 << disk->log_sector_size)) + != (1 << disk->log_sector_size)) { grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device); - close (fd); return grub_errno; } - buf += GRUB_DISK_SECTOR_SIZE; + buf += (1 << disk->log_sector_size); size--; } #endif /* __linux__ */ - if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS) - != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + if (grub_util_fd_read (fd, buf, size << disk->log_sector_size) + != (ssize_t) (size << disk->log_sector_size)) grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device); return grub_errno; @@ -851,13 +1062,34 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, if (fd < 0) return grub_errno; - if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS) - != (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + if (grub_util_fd_write (fd, buf, size << disk->log_sector_size) + != (ssize_t) (size << disk->log_sector_size)) grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device); return grub_errno; } +grub_err_t +grub_util_biosdisk_flush (struct grub_disk *disk) +{ + struct grub_util_biosdisk_data *data = disk->data; + + if (disk->dev->id != GRUB_DISK_DEVICE_BIOSDISK_ID) + return GRUB_ERR_NONE; + if (data->fd == -1) + { + data->fd = open_device (disk, 0, O_RDONLY); + if (data->fd < 0) + return grub_errno; + } + fsync (data->fd); +#ifdef __linux__ + if (data->is_disk) + ioctl (data->fd, BLKFLSBUF, 0); +#endif + return GRUB_ERR_NONE; +} + static void grub_util_biosdisk_close (struct grub_disk *disk) { @@ -865,14 +1097,18 @@ grub_util_biosdisk_close (struct grub_disk *disk) free (data->dev); if (data->fd != -1) - close (data->fd); + { + if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY) + grub_util_biosdisk_flush (disk); + close (data->fd); + } free (data); } static struct grub_disk_dev grub_util_biosdisk_dev = { - .name = "biosdisk", - .id = GRUB_DISK_DEVICE_BIOSDISK_ID, + .name = "hostdisk", + .id = GRUB_DISK_DEVICE_HOSTDISK_ID, .iterate = grub_util_biosdisk_iterate, .open = grub_util_biosdisk_open, .close = grub_util_biosdisk_close, @@ -895,6 +1131,12 @@ read_device_map (const char *dev_map) grub_util_error ("%s:%d: %s", dev_map, lineno, msg); } + if (dev_map[0] == '\0') + { + grub_util_info (_("no device.map")); + return; + } + fp = fopen (dev_map, "r"); if (! fp) { @@ -919,22 +1161,23 @@ read_device_map (const char *dev_map) continue; if (*p != '(') - show_error ("No open parenthesis found"); + show_error (_("No open parenthesis found")); p++; /* Find a free slot. */ drive = find_free_slot (); if (drive < 0) - show_error ("Map table size exceeded"); + show_error (_("Map table size exceeded")); e = p; p = strchr (p, ')'); if (! p) - show_error ("No close parenthesis found"); + show_error (_("No close parenthesis found")); map[drive].drive = xmalloc (p - e + sizeof ('\0')); strncpy (map[drive].drive, e, p - e + sizeof ('\0')); map[drive].drive[p - e] = '\0'; + map[drive].device_map = 1; p++; /* Skip leading spaces. */ @@ -942,7 +1185,7 @@ read_device_map (const char *dev_map) p++; if (*p == '\0') - show_error ("No filename found"); + show_error (_("No filename found")); /* NUL-terminate the filename. */ e = p; @@ -971,7 +1214,7 @@ read_device_map (const char *dev_map) { map[drive].device = xmalloc (PATH_MAX); if (! realpath (p, map[drive].device)) - grub_util_error ("cannot get the real path of `%s'", p); + grub_util_error (_("cannot get the real path of `%s'"), p); } else #endif @@ -1005,639 +1248,19 @@ grub_util_biosdisk_fini (void) grub_disk_dev_unregister (&grub_util_biosdisk_dev); } -/* - * Note: we do not use the new partition naming scheme as dos_part does not - * necessarily correspond to an msdos partition. - */ -static char * -make_device_name (int drive, int dos_part, int bsd_part) +const char * +grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk) { - char *ret; - char *dos_part_str = NULL; - char *bsd_part_str = NULL; - - if (dos_part >= 0) - dos_part_str = xasprintf (",%d", dos_part + 1); - - if (bsd_part >= 0) - bsd_part_str = xasprintf (",%d", bsd_part + 1); - - ret = xasprintf ("%s%s%s", map[drive].drive, - dos_part_str ? : "", - bsd_part_str ? : ""); - - if (dos_part_str) - free (dos_part_str); - - if (bsd_part_str) - free (bsd_part_str); - - return ret; -} - -static char * -convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) -{ -#if defined(__linux__) - char *path = xmalloc (PATH_MAX); - if (! realpath (os_dev, path)) - return NULL; - - if (strncmp ("/dev/", path, 5) == 0) - { - char *p = path + 5; - - /* If this is an IDE disk. */ - if (strncmp ("ide/", p, 4) == 0) - { - p = strstr (p, "part"); - if (p) - strcpy (p, "disc"); - - return path; - } - - /* If this is a SCSI disk. */ - if (strncmp ("scsi/", p, 5) == 0) - { - p = strstr (p, "part"); - if (p) - strcpy (p, "disc"); - - return path; - } - - /* If this is a DAC960 disk. */ - if (strncmp ("rd/c", p, 4) == 0) - { - /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is a Mylex AcceleRAID Array. */ - if (strncmp ("rs/c", p, 4) == 0) - { - /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - /* If this is a CCISS disk. */ - if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0) - { - /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is a Compaq Intelligent Drive Array. */ - if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0) - { - /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - /* If this is an I2O disk. */ - if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0) - { - /* /dev/i2o/hd[a-z]([0-9]+)? */ - p[sizeof ("i2o/hda") - 1] = '\0'; - return path; - } - - /* If this is a MultiMediaCard (MMC). */ - if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0) - { - /* /dev/mmcblk[0-9]+(p[0-9]+)? */ - p = strchr (p, 'p'); - if (p) - *p = '\0'; - - return path; - } - - if (strncmp ("md", p, 2) == 0 - && p[2] >= '0' && p[2] <= '9') - { - char *ptr = p + 2; - while (*ptr >= '0' && *ptr <= '9') - ptr++; - *ptr = 0; - return path; - } - - /* If this is an IDE, SCSI or Virtio disk. */ - if (strncmp ("vdisk", p, 5) == 0 - && p[5] >= 'a' && p[5] <= 'z') - { - /* /dev/vdisk[a-z][0-9]* */ - p[6] = '\0'; - return path; - } - if ((strncmp ("hd", p, 2) == 0 - || strncmp ("vd", p, 2) == 0 - || strncmp ("sd", p, 2) == 0) - && p[2] >= 'a' && p[2] <= 'z') - { - /* /dev/[hsv]d[a-z][0-9]* */ - p[3] = '\0'; - return path; - } - - /* If this is a Xen virtual block device. */ - if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z') - { - /* /dev/xvd[a-z][0-9]* */ - p[4] = '\0'; - return path; - } - -#ifdef HAVE_DEVICE_MAPPER - /* If this is a DM-RAID device. - Compare os_dev rather than path here, since nodes under - /dev/mapper/ are often symlinks. */ - if ((strncmp ("/dev/mapper/", os_dev, 12) == 0)) - { - struct dm_tree *tree; - uint32_t maj, min; - struct dm_tree_node *node = NULL, *child; - void *handle; - const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name; - - tree = dm_tree_create (); - if (! tree) - { - grub_dprintf ("hostdisk", "dm_tree_create failed\n"); - goto devmapper_out; - } - - maj = major (st->st_rdev); - min = minor (st->st_rdev); - if (! dm_tree_add_dev (tree, maj, min)) - { - grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n"); - goto devmapper_out; - } - - node = dm_tree_find_node (tree, maj, min); - if (! node) - { - grub_dprintf ("hostdisk", "dm_tree_find_node failed\n"); - goto devmapper_out; - } - node_uuid = dm_tree_node_get_uuid (node); - if (! node_uuid) - { - grub_dprintf ("hostdisk", "%s has no DM uuid\n", path); - node = NULL; - goto devmapper_out; - } - else if (strncmp (node_uuid, "DMRAID-", 7) != 0) - { - grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path); - node = NULL; - goto devmapper_out; - } - - handle = NULL; - /* Counter-intuitively, device-mapper refers to the disk-like - device containing a DM-RAID partition device as a "child" of - the partition device. */ - child = dm_tree_next_child (&handle, node, 0); - if (! child) - { - grub_dprintf ("hostdisk", "%s has no DM children\n", path); - goto devmapper_out; - } - child_uuid = dm_tree_node_get_uuid (child); - if (! child_uuid) - { - grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path); - goto devmapper_out; - } - else if (strncmp (child_uuid, "DMRAID-", 7) != 0) - { - grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path); - goto devmapper_out; - } - child_name = dm_tree_node_get_name (child); - if (! child_name) - { - grub_dprintf ("hostdisk", "%s child has no DM name\n", path); - goto devmapper_out; - } - mapper_name = child_name; - -devmapper_out: - if (! mapper_name && node) - { - /* This is a DM-RAID disk, not a partition. */ - mapper_name = dm_tree_node_get_name (node); - if (! mapper_name) - grub_dprintf ("hostdisk", "%s has no DM name\n", path); - } - if (tree) - dm_tree_free (tree); - free (path); - if (mapper_name) - return xasprintf ("/dev/mapper/%s", mapper_name); - else - return NULL; - } -#endif /* HAVE_DEVICE_MAPPER */ - } - - return path; - -#elif defined(__GNU__) - char *path = xstrdup (os_dev); - if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0) - { - char *p = strchr (path + 7, 's'); - if (p) - *p = '\0'; - } - return path; - -#elif defined(__CYGWIN__) - char *path = xstrdup (os_dev); - if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z') - path[8] = 0; - return path; - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) - char *path = xstrdup (os_dev); - if (strncmp ("/dev/", path, 5) == 0) - { - char *p; - for (p = path + 5; *p; ++p) - if (grub_isdigit(*p)) - { - p = strpbrk (p, "sp"); - if (p) - *p = '\0'; - break; - } - } - return path; - -#elif defined(__NetBSD__) - /* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */ - char *path = xstrdup (os_dev); - if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 && - (path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') && - strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */ - { - char *p; - for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++); - if (grub_isdigit(*p)) - { - p++; - if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0')) - { - /* path matches the required regular expression and - p points to its last character. */ - int rawpart = -1; -# ifdef HAVE_GETRAWPARTITION - rawpart = getrawpartition(); -# endif /* HAVE_GETRAWPARTITION */ - if (rawpart >= 0) - *p = 'a' + rawpart; - } - } - } - return path; - -#else -# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly." - return xstrdup (os_dev); -#endif -} - -#if defined(__linux__) || defined(__CYGWIN__) -static int -device_is_wholedisk (const char *os_dev) -{ - int len = strlen (os_dev); - - if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9') - return 1; + if (disk->dev != &grub_util_biosdisk_dev || map[disk->id].device_map) + return disk->name; return 0; } -#endif - -#if defined(__NetBSD__) -/* Try to determine whether a given device name corresponds to a whole disk. - This function should give in most cases a definite answer, but it may - actually give an approximate one in the following sense: if the return - value is 0 then the device name does not correspond to a whole disk. */ -static int -device_is_wholedisk (const char *os_dev) -{ - int len = strlen (os_dev); - int rawpart = -1; - -# ifdef HAVE_GETRAWPARTITION - rawpart = getrawpartition(); -# endif /* HAVE_GETRAWPARTITION */ - if (rawpart < 0) - return 1; - return (os_dev[len - 1] == ('a' + rawpart)); -} -#endif /* defined(__NetBSD__) */ - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -static int -device_is_wholedisk (const char *os_dev) -{ - const char *p; - - if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0) - return 0; - - for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p) - if (grub_isdigit (*p)) - { - if (strchr (p, 's')) - return 0; - break; - } - - return 1; -} -#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ - -static int -find_system_device (const char *os_dev, struct stat *st, int convert, int add) -{ - unsigned int i; - char *os_disk; - - if (convert) - os_disk = convert_system_partition_to_system_disk (os_dev, st); - else - os_disk = xstrdup (os_dev); - if (! os_disk) - return -1; - - for (i = 0; i < ARRAY_SIZE (map); i++) - if (! map[i].device) - break; - else if (strcmp (map[i].device, os_disk) == 0) - { - free (os_disk); - return i; - } - - if (!add) - return -1; - - if (i == ARRAY_SIZE (map)) - grub_util_error (_("device count exceeds limit")); - - map[i].device = os_disk; - map[i].drive = xstrdup (os_disk); - - return i; -} - -int -grub_util_biosdisk_is_present (const char *os_dev) -{ - struct stat st; - - if (stat (os_dev, &st) < 0) - return 0; - - return find_system_device (os_dev, &st, 1, 0) != -1; -} - -char * -grub_util_biosdisk_get_grub_dev (const char *os_dev) -{ - struct stat st; - int drive; - - if (stat (os_dev, &st) < 0) - { - grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev); - return 0; - } - - drive = find_system_device (os_dev, &st, 1, 1); - if (drive < 0) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "no mapping exists for `%s'", os_dev); - return 0; - } - - if (grub_strcmp (os_dev, - convert_system_partition_to_system_disk (os_dev, &st)) == 0) - return make_device_name (drive, -1, -1); - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) - if (! S_ISCHR (st.st_mode)) -#else - if (! S_ISBLK (st.st_mode)) -#endif - return make_device_name (drive, -1, -1); - -#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) - /* Linux counts partitions uniformly, whether a BSD partition or a DOS - partition, so mapping them to GRUB devices is not trivial. - Here, get the start sector of a partition by HDIO_GETGEO, and - compare it with each partition GRUB recognizes. - - Cygwin /dev/sdXN emulation uses Windows partition mapping. It - does not count the extended partition and missing primary - partitions. Use same method as on Linux here. - - For NetBSD and FreeBSD, proceed as for Linux, except that the start - sector is obtained from the disk label. */ - { - char *name, *partname; - grub_disk_t disk; - grub_disk_addr_t start; - auto int find_partition (grub_disk_t dsk, - const grub_partition_t partition); - - int find_partition (grub_disk_t dsk __attribute__ ((unused)), - const grub_partition_t partition) - { - grub_disk_addr_t part_start = 0; - grub_util_info ("Partition %d starts from %lu", - partition->number, partition->start); - - part_start = grub_partition_get_start (partition); - - if (start == part_start) - { - partname = grub_partition_get_name (partition); - return 1; - } - - return 0; - } - - name = make_device_name (drive, -1, -1); - -# if !defined(HAVE_DIOCGDINFO) - if (MAJOR (st.st_rdev) == FLOPPY_MAJOR) - return name; -# else /* defined(HAVE_DIOCGDINFO) */ - /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are - * different, we know that os_dev cannot be a floppy device. */ -# endif /* !defined(HAVE_DIOCGDINFO) */ - - start = find_partition_start (os_dev); - if (grub_errno != GRUB_ERR_NONE) - { - free (name); - return 0; - } - - grub_util_info ("%s starts from %lu", os_dev, start); - - if (start == 0 && device_is_wholedisk (os_dev)) - return name; - - grub_util_info ("opening the device %s", name); - disk = grub_disk_open (name); - free (name); - - if (! disk) - { - /* We already know that the partition exists. Given that we already - checked the device map above, we can only get - GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist. - This can happen on Xen, where disk images in the host can be - assigned to devices that have partition-like names in the guest - but are really more like disks. */ - if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE) - { - grub_util_warn - ("disk does not exist, so falling back to partition device %s", - os_dev); - - drive = find_system_device (os_dev, &st, 0, 1); - if (drive < 0) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "no mapping exists for `%s'", os_dev); - return 0; - } - - return make_device_name (drive, -1, -1); - } - else - return 0; - } - - partname = NULL; - grub_partition_iterate (disk, find_partition); - if (grub_errno != GRUB_ERR_NONE) - { - grub_disk_close (disk); - return 0; - } - - if (partname == NULL) - { - grub_disk_close (disk); - grub_error (GRUB_ERR_BAD_DEVICE, - "cannot find the partition of `%s'", os_dev); - return 0; - } - - name = grub_xasprintf ("%s,%s", disk->name, partname); - free (partname); - return name; - } - -#elif defined(__GNU__) - /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */ - { - char *p; - int dos_part = -1; - int bsd_part = -1; - - p = strrchr (os_dev, 's'); - if (p) - { - long int n; - char *q; - - p++; - n = strtol (p, &q, 10); - if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) - { - dos_part = (int) n - 1; - - if (*q >= 'a' && *q <= 'g') - bsd_part = *q - 'a'; - } - } - - return make_device_name (drive, dos_part, bsd_part); - } - -#else -# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly." - return make_device_name (drive, -1, -1); -#endif -} const char * grub_util_biosdisk_get_osdev (grub_disk_t disk) { + if (disk->dev != &grub_util_biosdisk_dev) + return 0; + return map[disk->id].device; } - -int -grub_util_biosdisk_is_floppy (grub_disk_t disk) -{ - struct stat st; - int fd; - - fd = open (map[disk->id].device, O_RDONLY); - /* Shouldn't happen. */ - if (fd == -1) - return 0; - - /* Shouldn't happen either. */ - if (fstat (fd, &st) < 0) - return 0; - -#if defined(__NetBSD__) - if (major(st.st_rdev) == RAW_FLOPPY_MAJOR) - return 1; -#endif - -#if defined(FLOPPY_MAJOR) - if (major(st.st_rdev) == FLOPPY_MAJOR) -#else - /* Some kernels (e.g. kFreeBSD) don't have a static major number - for floppies, but they still use a "fd[0-9]" pathname. */ - if (map[disk->id].device[5] == 'f' - && map[disk->id].device[6] == 'd' - && map[disk->id].device[7] >= '0' - && map[disk->id].device[7] <= '9') -#endif - return 1; - - return 0; -} diff --git a/grub-core/kern/emu/lite.c b/grub-core/kern/emu/lite.c index 32e12a079..947c669aa 100644 --- a/grub-core/kern/emu/lite.c +++ b/grub-core/kern/emu/lite.c @@ -15,6 +15,8 @@ #include "../mips/dl.c" #elif defined(__powerpc__) #include "../powerpc/dl.c" +#elif defined(__ia64__) +#include "../ia64/dl.c" #else #error "No target cpu type is defined" #endif diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c index 0a7645992..64e72dff6 100644 --- a/grub-core/kern/emu/main.c +++ b/grub-core/kern/emu/main.c @@ -49,15 +49,11 @@ static jmp_buf main_env; /* Store the prefix specified by an argument. */ -static char *prefix = NULL; +static char *root_dev = NULL, *dir = NULL; int grub_no_autoload; -grub_addr_t -grub_arch_modules_addr (void) -{ - return 0; -} +grub_addr_t grub_modbase = 0; void grub_reboot (void) @@ -71,11 +67,10 @@ grub_machine_init (void) } void -grub_machine_set_prefix (void) +grub_machine_get_bootlocation (char **device, char **path) { - grub_env_set ("prefix", prefix); - free (prefix); - prefix = 0; + *device = root_dev; + *path = dir; } void @@ -103,14 +98,14 @@ usage (int status) { if (status) fprintf (stderr, - "Try `%s --help' for more information.\n", program_name); + _("Try `%s --help' for more information.\n"), program_name); else printf ( - "Usage: %s [OPTION]...\n" + _("Usage: %s [OPTION]...\n" "\n" "GRUB emulator.\n" "\n" - " -r, --root-device=DEV use DEV as the root device [default=guessed]\n" + " -r, --root-device=DEV use DEV as the root device [default=host]\n" " -m, --device-map=FILE use FILE as the device map [default=%s]\n" " -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n" " -v, --verbose print verbose messages\n" @@ -118,7 +113,7 @@ usage (int status) " -h, --help display this message and exit\n" " -V, --version print version information and exit\n" "\n" - "Report bugs to <%s>.\n", program_name, DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); + "Report bugs to <%s>.\n"), program_name, DEFAULT_DEVICE_MAP, DEFAULT_DIRECTORY, PACKAGE_BUGREPORT); return status; } @@ -132,22 +127,24 @@ void grub_emu_init (void); int main (int argc, char *argv[]) { - char *root_dev = 0; - char *dir = DEFAULT_DIRECTORY; - char *dev_map = DEFAULT_DEVICE_MAP; + const char *dev_map = DEFAULT_DEVICE_MAP; volatile int hold = 0; int opt; set_program_name (argv[0]); + dir = xstrdup (DEFAULT_DIRECTORY); + while ((opt = getopt_long (argc, argv, "r:d:m:vH:hV", options, 0)) != -1) switch (opt) { case 'r': - root_dev = optarg; + free (root_dev); + root_dev = xstrdup (optarg); break; case 'd': - dir = optarg; + free (dir); + dir = xstrdup (optarg); break; case 'm': dev_map = optarg; @@ -169,13 +166,13 @@ main (int argc, char *argv[]) if (optind < argc) { - fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind]); + fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind]); return usage (1); } /* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */ if (hold && verbosity > 0) - printf ("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n", + printf (_("Run \"gdb %s %d\", and set ARGS.HOLD to zero.\n"), program_name, (int) getpid ()); while (hold) { @@ -201,27 +198,9 @@ main (int argc, char *argv[]) /* Make sure that there is a root device. */ if (! root_dev) - { - char *device_name = grub_guess_root_device (dir); - if (! device_name) - grub_util_error ("cannot find a device for %s", dir); + root_dev = grub_strdup ("host"); - root_dev = grub_util_get_grub_dev (device_name); - if (! root_dev) - { - grub_util_info ("guessing the root device failed, because of `%s'", - grub_errmsg); - grub_util_error ("cannot guess the root device. Specify the option `--root-device'"); - } - } - - if (strcmp (root_dev, "host") == 0) - dir = xstrdup (dir); - else - dir = grub_make_system_path_relative_to_its_root (dir); - prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1); - sprintf (prefix, "(%s)%s", root_dev, dir); - free (dir); + dir = xstrdup (dir); /* Start GRUB! */ if (setjmp (main_env) == 0) diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c index d8db3be9d..21f314d55 100644 --- a/grub-core/kern/emu/misc.c +++ b/grub-core/kern/emu/misc.c @@ -46,14 +46,6 @@ # include #endif -#ifdef HAVE_LIBZFS -# include -#endif - -#ifdef HAVE_LIBNVPAIR -# include -#endif - #ifdef HAVE_SYS_PARAM_H # include #endif @@ -125,7 +117,7 @@ xmalloc (grub_size_t size) p = malloc (size); if (! p) - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); return p; } @@ -135,7 +127,7 @@ xrealloc (void *ptr, grub_size_t size) { ptr = realloc (ptr, size); if (! ptr) - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); return ptr; } @@ -193,7 +185,7 @@ xasprintf (const char *fmt, ...) if (vasprintf (&result, fmt, ap) < 0) { if (errno == ENOMEM) - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); return NULL; } @@ -232,7 +224,11 @@ char * canonicalize_file_name (const char *path) { char *ret; -#ifdef PATH_MAX +#ifdef __MINGW32__ + ret = xmalloc (PATH_MAX); + if (!_fullpath (ret, path, PATH_MAX)) + return NULL; +#elif defined (PATH_MAX) ret = xmalloc (PATH_MAX); if (!realpath (path, ret)) return NULL; @@ -242,233 +238,6 @@ canonicalize_file_name (const char *path) return ret; } -#ifdef __CYGWIN__ -/* Convert POSIX path to Win32 path, - remove drive letter, replace backslashes. */ -static char * -get_win32_path (const char *path) -{ - char winpath[PATH_MAX]; - if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath))) - grub_util_error ("cygwin_conv_path() failed"); - - int len = strlen (winpath); - int offs = (len > 2 && winpath[1] == ':' ? 2 : 0); - - int i; - for (i = offs; i < len; i++) - if (winpath[i] == '\\') - winpath[i] = '/'; - return xstrdup (winpath + offs); -} -#endif - -#ifdef HAVE_LIBZFS -static libzfs_handle_t *__libzfs_handle; - -static void -fini_libzfs (void) -{ - libzfs_fini (__libzfs_handle); -} - -libzfs_handle_t * -grub_get_libzfs_handle (void) -{ - if (! __libzfs_handle) - { - __libzfs_handle = libzfs_init (); - - if (__libzfs_handle) - atexit (fini_libzfs); - } - - return __libzfs_handle; -} -#endif /* HAVE_LIBZFS */ - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) -/* ZFS has similar problems to those of btrfs (see above). */ -void -grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs) -{ - char *slash; - - *poolname = *poolfs = NULL; - -#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME) - /* FreeBSD and GNU/kFreeBSD. */ - { - struct statfs mnt; - - if (statfs (dir, &mnt) != 0) - return; - - if (strcmp (mnt.f_fstypename, "zfs") != 0) - return; - - *poolname = xstrdup (mnt.f_mntfromname); - } -#elif defined(HAVE_GETEXTMNTENT) - /* Solaris. */ - { - struct stat st; - struct extmnttab mnt; - - if (stat (dir, &st) != 0) - return; - - FILE *mnttab = fopen ("/etc/mnttab", "r"); - if (! mnttab) - return; - - while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0) - { - if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev - && !strcmp (mnt.mnt_fstype, "zfs")) - { - *poolname = xstrdup (mnt.mnt_special); - break; - } - } - - fclose (mnttab); - } -#endif - - if (! *poolname) - return; - - slash = strchr (*poolname, '/'); - if (slash) - { - *slash = '\0'; - *poolfs = xstrdup (slash + 1); - } - else - *poolfs = xstrdup (""); -} -#endif - -/* This function never prints trailing slashes (so that its output - can be appended a slash unconditionally). */ -char * -grub_make_system_path_relative_to_its_root (const char *path) -{ - struct stat st; - char *p, *buf, *buf2, *buf3, *ret; - uintptr_t offset = 0; - dev_t num; - size_t len; - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - char *poolfs = NULL; -#endif - - /* canonicalize. */ - p = canonicalize_file_name (path); - if (p == NULL) - grub_util_error ("failed to get canonical path of %s", path); - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - /* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */ - { - char *dummy; - grub_find_zpool_from_dir (p, &dummy, &poolfs); - } -#endif - - len = strlen (p) + 1; - buf = xstrdup (p); - free (p); - - if (stat (buf, &st) < 0) - grub_util_error ("cannot stat %s: %s", buf, strerror (errno)); - - buf2 = xstrdup (buf); - num = st.st_dev; - - /* This loop sets offset to the number of chars of the root - directory we're inspecting. */ - while (1) - { - p = strrchr (buf, '/'); - if (p == NULL) - /* This should never happen. */ - grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)"); - if (p != buf) - *p = 0; - else - *++p = 0; - - if (stat (buf, &st) < 0) - grub_util_error ("cannot stat %s: %s", buf, strerror (errno)); - - /* buf is another filesystem; we found it. */ - if (st.st_dev != num) - { - /* offset == 0 means path given is the mount point. - This works around special-casing of "/" in Un*x. This function never - prints trailing slashes (so that its output can be appended a slash - unconditionally). Each slash in is considered a preceding slash, and - therefore the root directory is an empty string. */ - if (offset == 0) - { - free (buf); - free (buf2); - return xstrdup (""); - } - else - break; - } - - offset = p - buf; - /* offset == 1 means root directory. */ - if (offset == 1) - { - /* Include leading slash. */ - offset = 0; - break; - } - } - free (buf); - buf3 = xstrdup (buf2 + offset); - free (buf2); - -#ifdef __CYGWIN__ - if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16)) - { - /* Reached some mount point not below /cygdrive. - GRUB does not know Cygwin's emulated mounts, - convert to Win32 path. */ - grub_util_info ("Cygwin path = %s\n", buf3); - char * temp = get_win32_path (buf3); - free (buf3); - buf3 = temp; - } -#endif - - /* Remove trailing slashes, return empty string if root directory. */ - len = strlen (buf3); - while (len > 0 && buf3[len - 1] == '/') - { - buf3[len - 1] = '\0'; - len--; - } - -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - if (poolfs) - { - ret = xasprintf ("/%s/@%s", poolfs, buf3); - free (buf3); - } - else -#endif - ret = buf3; - - return ret; -} - #ifdef HAVE_DEVICE_MAPPER static void device_mapper_null_log (int level __attribute__ ((unused)), const char *file __attribute__ ((unused)), diff --git a/grub-core/kern/emu/mm.c b/grub-core/kern/emu/mm.c index 6a70efb4c..b58ccc794 100644 --- a/grub-core/kern/emu/mm.c +++ b/grub-core/kern/emu/mm.c @@ -77,7 +77,7 @@ grub_memalign (grub_size_t align, grub_size_t size) #else (void) align; (void) size; - grub_util_error ("grub_memalign is not supported"); + grub_util_error (_("grub_memalign is not supported")); #endif if (!p) diff --git a/grub-core/kern/env.c b/grub-core/kern/env.c index 84b3a001d..96b730d35 100644 --- a/grub-core/kern/env.c +++ b/grub-core/kern/env.c @@ -132,7 +132,7 @@ grub_env_set (const char *name, const char *val) return grub_errno; } -char * +const char * grub_env_get (const char *name) { struct grub_env_var *var; @@ -240,3 +240,23 @@ grub_register_variable_hook (const char *name, return GRUB_ERR_NONE; } + +grub_err_t +grub_env_export (const char *name) +{ + struct grub_env_var *var; + + var = grub_env_find (name); + if (! var) + { + grub_err_t err; + + err = grub_env_set (name, ""); + if (err) + return err; + var = grub_env_find (name); + } + var->global = 1; + + return GRUB_ERR_NONE; +} diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index c93fbf737..f69ef6fd4 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -20,10 +20,13 @@ #include #include #include +#include #include #include #include +void (*EXPORT_VAR (grub_grubnet_fini)) (void); + grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX]; grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX]; @@ -68,7 +71,7 @@ grub_file_open (const char *name) goto fail; /* Get the file part of NAME. */ - file_name = grub_strchr (name, ')'); + file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL; if (file_name) file_name++; else @@ -148,7 +151,6 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) if (len == 0) return 0; - res = (file->fs->read) (file, buf, len); if (res > 0) file->offset += res; @@ -179,8 +181,9 @@ grub_file_seek (grub_file_t file, grub_off_t offset) "attempt to seek outside of the file"); return -1; } - + old = file->offset; file->offset = offset; + return old; } diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c index cf800f4cc..14d389e07 100644 --- a/grub-core/kern/fs.c +++ b/grub-core/kern/fs.c @@ -94,7 +94,7 @@ grub_fs_probe (grub_device_t device) count--; } } - else if (device->net->fs) + else if (device->net && device->net->fs) return device->net->fs; grub_error (GRUB_ERR_UNKNOWN_FS, "unknown filesystem"); diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c index 434b9b5a8..95209bb70 100644 --- a/grub-core/kern/i386/coreboot/init.c +++ b/grub-core/kern/i386/coreboot/init.c @@ -38,8 +38,9 @@ #include #endif -extern char _start[]; -extern char _end[]; +extern grub_uint8_t _start[]; +extern grub_uint8_t _end[]; +extern grub_uint8_t _edata[]; grub_uint32_t grub_get_rtc (void) @@ -56,10 +57,18 @@ grub_exit (void) grub_cpu_idle (); } +#ifdef GRUB_MACHINE_QEMU +grub_addr_t grub_modbase; +#else +grub_addr_t grub_modbase = ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN); +#endif + void grub_machine_init (void) { #ifdef GRUB_MACHINE_QEMU + grub_modbase = grub_core_entry_addr + (_edata - _start); + grub_qemu_init_cirrus (); #endif /* Initialize the console as early as possible. */ @@ -107,10 +116,9 @@ grub_machine_init (void) } void -grub_machine_set_prefix (void) +grub_machine_get_bootlocation (char **device __attribute__ ((unused)), + char **path __attribute__ ((unused))) { - /* Initialize the prefix. */ - grub_env_set ("prefix", grub_prefix); } void @@ -119,14 +127,3 @@ grub_machine_fini (void) grub_vga_text_fini (); grub_stop_floppy (); } - -/* Return the end of the core image. */ -grub_addr_t -grub_arch_modules_addr (void) -{ -#ifdef GRUB_MACHINE_QEMU - return grub_core_entry_addr + grub_kernel_image_size; -#else - return ALIGN_UP((grub_addr_t) _end, GRUB_KERNEL_MACHINE_MOD_ALIGN); -#endif -} diff --git a/grub-core/kern/i386/coreboot/startup.S b/grub-core/kern/i386/coreboot/startup.S index cac023ddf..dc2c62a25 100644 --- a/grub-core/kern/i386/coreboot/startup.S +++ b/grub-core/kern/i386/coreboot/startup.S @@ -38,36 +38,6 @@ .globl start, _start start: _start: - jmp codestart - - /* - * This is a special data area at a fixed offset from the beginning. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX - -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END - -/* - * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). - */ - .p2align 2 /* force 4-byte alignment */ -multiboot_header: - /* magic */ - .long 0x1BADB002 - /* flags */ - .long MULTIBOOT_MEMORY_INFO - /* checksum */ - .long -0x1BADB002 - MULTIBOOT_MEMORY_INFO - -codestart: #ifdef GRUB_MACHINE_MULTIBOOT cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax jne 0f @@ -81,9 +51,22 @@ codestart: /* jump to the main body of C code */ jmp EXT_C(grub_main) +/* + * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). + */ + .p2align 2 /* force 4-byte alignment */ +multiboot_header: + /* magic */ + .long 0x1BADB002 + /* flags */ + .long MULTIBOOT_MEMORY_INFO + /* checksum */ + .long -0x1BADB002 - MULTIBOOT_MEMORY_INFO + /* * prot_to_real and associated structures (but NOT real_to_prot, that is * only needed for BIOS gates). */ #include "../realmode.S" +#include "../int.S" diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c index f73f828c6..6bd8f3e87 100644 --- a/grub-core/kern/i386/efi/init.c +++ b/grub-core/kern/i386/efi/init.c @@ -39,9 +39,3 @@ grub_machine_fini (void) { grub_efi_fini (); } - -void -grub_machine_set_prefix (void) -{ - grub_efi_set_prefix (); -} diff --git a/grub-core/kern/i386/efi/startup.S b/grub-core/kern/i386/efi/startup.S index 5b464ab83..fc5ea3dac 100644 --- a/grub-core/kern/i386/efi/startup.S +++ b/grub-core/kern/i386/efi/startup.S @@ -19,40 +19,12 @@ #include #include -#include .file "startup.S" .text .globl start, _start start: _start: - jmp codestart - - /* - * Compatibility version number - * - * These MUST be at byte offset 6 and 7 of the executable - * DO NOT MOVE !!! - */ - . = _start + 0x6 - .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR - - /* - * This is a special data area 8 bytes from the beginning. - */ - - . = _start + 0x8 - -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + 0x50 - -codestart: /* * EFI_SYSTEM_TABLE * and EFI_HANDLE are passed on the stack. */ @@ -62,5 +34,3 @@ codestart: movl %eax, EXT_C(grub_efi_system_table) call EXT_C(grub_main) ret - -#include "../realmode.S" diff --git a/grub-core/kern/i386/ieee1275/startup.S b/grub-core/kern/i386/ieee1275/startup.S index 82087323b..245583bdb 100644 --- a/grub-core/kern/i386/ieee1275/startup.S +++ b/grub-core/kern/i386/ieee1275/startup.S @@ -36,30 +36,6 @@ start: _start: - jmp codestart - - /* - * This is a special data area at a fixed offset from the beginning. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX - -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END - -codestart: movl %eax, EXT_C(grub_ieee1275_entry_fn) jmp EXT_C(grub_main) -/* - * prot_to_real and associated structures (but NOT real_to_prot, that is - * only needed for BIOS gates). - */ -#include "../realmode.S" - diff --git a/grub-core/kern/i386/int.S b/grub-core/kern/i386/int.S new file mode 100644 index 000000000..7a2b7808a --- /dev/null +++ b/grub-core/kern/i386/int.S @@ -0,0 +1,140 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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(grub_bios_interrupt) + pushf + cli +#ifndef GRUB_MACHINE_PCBIOS + sidt protidt +#endif + popf + 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 + + PROT_TO_REAL + .code16 + pushf + cli +#ifndef GRUB_MACHINE_PCBIOS + lidt realidt +#endif + + 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) + + popf + 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 +#ifndef GRUB_MACHINE_PCBIOS + lidt protidt +#endif + ret +#ifndef GRUB_MACHINE_PCBIOS +realidt: + .word 0x100 + .long 0 +protidt: + .word 0 + .long 0 +#endif diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index 122c2c556..c6492619f 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -45,52 +45,62 @@ struct mem_region static struct mem_region mem_regions[MAX_REGIONS]; static int num_regions; -static char * -make_install_device (void) +void (*grub_pc_net_config) (char **device, char **path); + +/* + * return the real time in ticks, of which there are about + * 18-20 per second + */ +grub_uint32_t +grub_get_rtc (void) { + struct grub_bios_int_registers regs; + + regs.eax = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x1a, ®s); + + return (regs.ecx << 16) | (regs.edx & 0xffff); +} + +void +grub_machine_get_bootlocation (char **device, char **path) +{ + char *ptr; + grub_uint8_t boot_drive, dos_part, bsd_part; + + boot_drive = (grub_boot_device >> 24); + dos_part = (grub_boot_device >> 16); + bsd_part = (grub_boot_device >> 8); + + /* No hardcoded root partition - make it from the boot drive and the + partition number encoded at the install time. */ + if (boot_drive == GRUB_BOOT_MACHINE_PXE_DL) + { + if (grub_pc_net_config) + grub_pc_net_config (device, path); + return; + } + /* XXX: This should be enough. */ - char dev[100], *ptr = dev; +#define DEV_SIZE 100 + *device = grub_malloc (DEV_SIZE); + ptr = *device; + grub_snprintf (*device, DEV_SIZE, + "%cd%u", (boot_drive & 0x80) ? 'h' : 'f', + boot_drive & 0x7f); + ptr += grub_strlen (ptr); - if (grub_prefix[0] != '(') - { - /* No hardcoded root partition - make it from the boot drive and the - partition number encoded at the install time. */ - if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL) - { - grub_strcpy (dev, "(pxe"); - ptr += sizeof ("(pxe") - 1; - } - else - { - grub_snprintf (dev, sizeof (dev), - "(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f', - grub_boot_drive & 0x7f); - ptr += grub_strlen (ptr); + if (dos_part != 0xff) + grub_snprintf (ptr, DEV_SIZE - (ptr - *device), + ",%u", dos_part + 1); + ptr += grub_strlen (ptr); - if (grub_install_dos_part >= 0) - grub_snprintf (ptr, sizeof (dev) - (ptr - dev), - ",%u", grub_install_dos_part + 1); - ptr += grub_strlen (ptr); - - if (grub_install_bsd_part >= 0) - grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%u", - grub_install_bsd_part + 1); - ptr += grub_strlen (ptr); - } - - grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix); - grub_strcpy (grub_prefix, dev); - } - else if (grub_prefix[1] == ',' || grub_prefix[1] == ')') - { - /* We have a prefix, but still need to fill in the boot drive. */ - grub_snprintf (dev, sizeof (dev), - "(%cd%u%s", (grub_boot_drive & 0x80) ? 'h' : 'f', - grub_boot_drive & 0x7f, grub_prefix + 1); - grub_strcpy (grub_prefix, dev); - } - - return grub_prefix; + if (bsd_part != 0xff) + grub_snprintf (ptr, DEV_SIZE - (ptr - *device), ",%u", + bsd_part + 1); + ptr += grub_strlen (ptr); + *ptr = 0; } /* Add a memory region. */ @@ -140,36 +150,32 @@ 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; -} +grub_addr_t grub_modbase; +extern grub_uint8_t _start[], _edata[]; void grub_machine_init (void) { int i; +#if 0 int grub_lower_mem; +#endif + + grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); /* Initialize the console as early as possible. */ grub_console_init (); + /* This sanity check is useless since top of GRUB_MEMORY_MACHINE_RESERVED_END + is used for stack and if it's unavailable we wouldn't have gotten so far. + */ +#if 0 grub_lower_mem = grub_get_conv_memsize () << 10; /* Sanity check. */ if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END) grub_fatal ("too small memory"); +#endif /* FIXME: This prevents loader/i386/linux.c from using low memory. When our heap implements support for requesting a chunk in low memory, this should @@ -220,24 +226,9 @@ grub_machine_init (void) grub_tsc_init (); } -void -grub_machine_set_prefix (void) -{ - /* Initialize the prefix. */ - grub_env_set ("prefix", make_install_device ()); -} - void grub_machine_fini (void) { grub_console_fini (); grub_stop_floppy (); } - -/* Return the end of the core image. */ -grub_addr_t -grub_arch_modules_addr (void) -{ - return GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR - + (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE); -} diff --git a/grub-core/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c index a305d4511..480ffa949 100644 --- a/grub-core/kern/i386/pc/mmap.c +++ b/grub-core/kern/i386/pc/mmap.c @@ -36,6 +36,22 @@ struct grub_machine_mmap_entry } __attribute__((packed)); +/* + * + * 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; +} + /* * grub_get_ext_memsize() : return the extended memory size in KB. * BIOS call "INT 15H, AH=88H" to get extended memory size @@ -155,6 +171,10 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) { grub_uint32_t eisa_mmap = grub_get_eisa_mmap (); + if (hook (0x0, ((grub_uint32_t) grub_get_conv_memsize ()) << 10, + GRUB_MEMORY_AVAILABLE)) + return 0; + if (eisa_mmap) { if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, @@ -162,7 +182,8 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MEMORY_AVAILABLE); } else - hook (0x100000, grub_get_ext_memsize () << 10, GRUB_MEMORY_AVAILABLE); + hook (0x100000, ((grub_uint32_t) grub_get_ext_memsize ()) << 10, + GRUB_MEMORY_AVAILABLE); } return 0; diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index c4abc31b8..51e19b7f0 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009,2011 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 @@ -43,212 +43,30 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include - -#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) .file "startup.S" .text - /* Tell GAS to generate 16-bit instructions so that this code works - in real mode. */ - .code16 - .globl start, _start start: _start: -LOCAL (base): - /* - * Guarantee that "main" is loaded at 0x0:0x8200. - */ -#ifdef __APPLE__ - ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000) -#else - ljmp $0, $ABS(LOCAL (codestart)) -#endif - /* - * Compatibility version number - * - * These MUST be at byte offset 6 and 7 of the executable - * DO NOT MOVE !!! - */ - . = _start + 0x6 - .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR - - /* - * This is a special data area 8 bytes from the beginning. - */ - - . = _start + 0x8 - -VARIABLE(grub_total_module_size) - .long 0 -VARIABLE(grub_kernel_image_size) - .long 0 -VARIABLE(grub_compressed_size) - .long 0 -VARIABLE(grub_install_dos_part) - .long 0xFFFFFFFF -VARIABLE(grub_install_bsd_part) - .long 0xFFFFFFFF -reed_solomon_redundancy: - .long 0 - -#ifdef APPLE_CC -bss_start: - .long 0 -bss_end: - .long 0 -#endif -/* - * This is the area for all of the special variables. - */ - -VARIABLE(grub_boot_drive) - .byte 0 - -/* the real mode code continues... */ -LOCAL (codestart): - cli /* we're not safe here! */ - - /* set up %ds, %ss, and %es */ - xorw %ax, %ax - movw %ax, %ds - movw %ax, %ss - movw %ax, %es - - /* set up the real mode/BIOS stack */ - movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp - movl %ebp, %esp - - sti /* we're safe again */ - - /* save the boot drive */ - ADDR32 movb %dl, EXT_C(grub_boot_drive) - - /* reset disk system (%ah = 0) */ - int $0x13 - - /* transition to protected mode */ - DATA32 call real_to_prot - - /* The ".code32" directive takes GAS out of 16-bit mode. */ .code32 - incl %eax - call grub_gate_a20 - - movl EXT_C(grub_compressed_size), %edx - addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx - movl reed_solomon_redundancy, %ecx - leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax - testl %edx, %edx - jz post_reed_solomon - call EXT_C (grub_reed_solomon_recover) - jmp post_reed_solomon - -#include - - .text - - . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART -/* - * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). - * This uses the a.out kludge to load raw binary to the area starting at 1MB, - * and relocates itself after loaded. - */ - .p2align 2 /* force 4-byte alignment */ -multiboot_header: - /* magic */ - .long 0x1BADB002 - /* flags */ - .long (1 << 16) - /* checksum */ - .long -0x1BADB002 - (1 << 16) - /* header addr */ - .long multiboot_header - _start + 0x100000 + 0x200 - /* load addr */ - .long 0x100000 - /* load end addr */ - .long 0 - /* bss end addr */ - .long 0 - /* entry addr */ - .long multiboot_entry - _start + 0x100000 + 0x200 - -multiboot_entry: - .code32 - /* obtain the boot device */ - movl 12(%ebx), %edx - - movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp - movl %ebp, %esp - - /* relocate the code */ - movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx - addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx - movl $0x100000, %esi - movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi - cld - rep - movsb - /* jump to the real address */ - movl $multiboot_trampoline, %eax - jmp *%eax - -multiboot_trampoline: - /* fill the boot information */ - movl %edx, %eax - shrl $8, %eax - xorl %ebx, %ebx - cmpb $0xFF, %ah - je 1f - movb %ah, %bl - movl %ebx, EXT_C(grub_install_dos_part) -1: - cmpb $0xFF, %al - je 2f - movb %al, %bl - movl %ebx, EXT_C(grub_install_bsd_part) -2: - shrl $24, %edx - movb $0xFF, %dh - /* enter the usual booting */ - call prot_to_real - -post_reed_solomon: - -#ifdef ENABLE_LZMA - movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi - movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi - pushl %edi - pushl %esi - movl EXT_C(grub_kernel_image_size), %ecx - addl EXT_C(grub_total_module_size), %ecx - subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx - pushl %ecx - leal (%edi, %ecx), %ebx - call _LzmaDecodeA - /* _LzmaDecodeA clears DF, so no need to run cld */ - popl %ecx - popl %edi - popl %esi -#endif + movl %ecx, (LOCAL(real_to_prot_addr) - _start) (%esi) + movl %edi, (LOCAL(prot_to_real_addr) - _start) (%esi) /* copy back the decompressed part (except the modules) */ - subl EXT_C(grub_total_module_size), %ecx + movl $(_edata - _start), %ecx + movl $(_start), %edi rep movsb + movl $LOCAL (cont), %esi + jmp *%esi +LOCAL(cont): + #if 0 /* copy modules before cleaning out the bss */ movl EXT_C(grub_total_module_size), %ecx @@ -264,24 +82,12 @@ post_reed_solomon: movsb #endif -#ifdef APPLE_CC - /* clean out the bss */ - bss_start_abs = ABS (bss_start) - bss_end_abs = ABS (bss_end) - - movl bss_start_abs, %edi - - /* compute the bss length */ - movl bss_end_abs, %ecx - subl %edi, %ecx -#else /* clean out the bss */ movl $BSS_START_SYMBOL, %edi /* compute the bss length */ movl $END_SYMBOL, %ecx subl %edi, %ecx -#endif /* clean out */ xorl %eax, %eax @@ -289,183 +95,27 @@ post_reed_solomon: rep stosb + movl %edx, EXT_C(grub_boot_device) + /* * Call the start of main body of C code. */ call EXT_C(grub_main) -#include "../realmode.S" - -/* - * grub_gate_a20(int on) - * - * Gate address-line 20 for high memory. - * - * This routine is probably overconservative in what it does, but so what? - * - * It also eats any keystrokes in the keyboard buffer. :-( - */ - -grub_gate_a20: - movl %eax, %edx - -gate_a20_test_current_state: - /* first of all, test if already in a good state */ - call gate_a20_check_state - cmpb %al, %dl - jnz gate_a20_try_bios - ret - -gate_a20_try_bios: - /* second, try a BIOS call */ - pushl %ebp - call prot_to_real - - .code16 - movw $0x2400, %ax - testb %dl, %dl - jz 1f - incw %ax -1: int $0x15 - - DATA32 call real_to_prot - .code32 - - popl %ebp - call gate_a20_check_state - cmpb %al, %dl - jnz gate_a20_try_system_control_port_a - ret - -gate_a20_try_system_control_port_a: - /* - * In macbook, the keyboard test would hang the machine, so we move - * this forward. - */ - /* fourth, try the system control port A */ - inb $0x92 - andb $(~0x03), %al - testb %dl, %dl - jz 6f - orb $0x02, %al -6: outb $0x92 - - /* When turning off Gate A20, do not check the state strictly, - because a failure is not fatal usually, and Gate A20 is always - on some modern machines. */ - testb %dl, %dl - jz 7f - call gate_a20_check_state - cmpb %al, %dl - jnz gate_a20_try_keyboard_controller -7: ret - -gate_a20_flush_keyboard_buffer: - inb $0x64 - andb $0x02, %al - jnz gate_a20_flush_keyboard_buffer -2: - inb $0x64 - andb $0x01, %al - jz 3f - inb $0x60 - jmp 2b -3: - ret - -gate_a20_try_keyboard_controller: - /* third, try the keyboard controller */ - call gate_a20_flush_keyboard_buffer - - movb $0xd1, %al - outb $0x64 -4: - inb $0x64 - andb $0x02, %al - jnz 4b - - movb $0xdd, %al - testb %dl, %dl - jz 5f - orb $0x02, %al -5: outb $0x60 - call gate_a20_flush_keyboard_buffer - - /* output a dummy command (USB keyboard hack) */ - movb $0xff, %al - outb $0x64 - call gate_a20_flush_keyboard_buffer - - call gate_a20_check_state - cmpb %al, %dl - /* everything failed, so restart from the beginning */ - jnz gate_a20_try_bios - ret - -gate_a20_check_state: - /* iterate the checking for a while */ - movl $100, %ecx -1: - call 3f - cmpb %al, %dl - jz 2f - loop 1b -2: - ret -3: - pushl %ebx - pushl %ecx - xorl %eax, %eax - /* compare the byte at 0x8000 with that at 0x108000 */ - movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx - pushl %ebx - /* save the original byte in CL */ - movb (%ebx), %cl - /* store the value at 0x108000 in AL */ - addl $0x100000, %ebx - movb (%ebx), %al - /* try to set one less value at 0x8000 */ - popl %ebx - movb %al, %ch - decb %ch - movb %ch, (%ebx) - /* serialize */ - outb %al, $0x80 - outb %al, $0x80 - /* obtain the value at 0x108000 in CH */ - pushl %ebx - addl $0x100000, %ebx - movb (%ebx), %ch - /* this result is 1 if A20 is on or 0 if it is off */ - subb %ch, %al - xorb $1, %al - /* restore the original */ - popl %ebx - movb %cl, (%ebx) - popl %ecx - popl %ebx - ret - -#ifdef ENABLE_LZMA -#include "lzma_decode.S" -#endif - -/* - * The code beyond this point is compressed. Assert that the uncompressed - * code fits GRUB_KERNEL_MACHINE_RAW_SIZE. - */ - . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE - - . = _start + GRUB_KERNEL_MACHINE_PREFIX -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END +LOCAL(real_to_prot_addr): + .long 0 +LOCAL(prot_to_real_addr): + .long 0 + .macro PROT_TO_REAL + movl LOCAL(prot_to_real_addr), %eax + call *%eax + .endm + .macro REAL_TO_PROT + movl LOCAL(real_to_prot_addr), %eax + DATA32 call *%ax + .endm /* * grub_exit() @@ -473,396 +123,17 @@ VARIABLE(grub_prefix) * Exit the system. */ FUNCTION(grub_exit) - call prot_to_real + PROT_TO_REAL .code16 /* Tell the BIOS a boot failure. If this does not work, reboot. */ int $0x18 - jmp cold_reboot + /* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */ + xorw %ax, %ax + movw $0x0472, %di + movw %ax, (%di) + ljmp $0xf000, $0xfff0 .code32 -/* - * void grub_chainloader_real_boot (int drive, void *part_addr) - * - * This starts another boot loader. - */ - -FUNCTION(grub_chainloader_real_boot) - pushl %edx - pushl %eax - - /* Turn off Gate A20 */ - xorl %eax, %eax - call grub_gate_a20 - - /* set up to pass boot drive */ - popl %edx - - /* ESI must point to a partition table entry */ - popl %esi - - call prot_to_real - .code16 - ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR - .code32 - -/* - * 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. - * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh - * (TELETYPE OUTPUT). Otherwise, save the original position, put a space, - * save the current position, restore the original position, write the - * character and the attribute, and restore the current position. - * - * The reason why this is so complicated is that there is no easy way to - * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't - * support setting a background attribute. - */ -FUNCTION(grub_console_putchar) - /* Retrieve the base character. */ - movl 0(%edx), %edx - pusha - movb EXT_C(grub_console_cur_color), %bl - - call prot_to_real - .code16 - movb %dl, %al - xorb %bh, %bh - - /* use teletype output if control character */ - cmpb $0x7, %al - je 1f - cmpb $0x8, %al - je 1f - cmpb $0xa, %al - je 1f - cmpb $0xd, %al - je 1f - - /* save the character and the attribute on the stack */ - pushw %ax - pushw %bx - - /* get the current position */ - movb $0x3, %ah - int $0x10 - - /* check the column with the width */ - cmpb $79, %dl - jl 2f - - /* print CR and LF, if next write will exceed the width */ - movw $0x0e0d, %ax - int $0x10 - movb $0x0a, %al - int $0x10 - - /* get the current position */ - movb $0x3, %ah - int $0x10 - -2: - /* restore the character and the attribute */ - popw %bx - popw %ax - - /* write the character with the attribute */ - movb $0x9, %ah - movw $1, %cx - int $0x10 - - /* move the cursor forward */ - incb %dl - movb $0x2, %ah - int $0x10 - - jmp 3f - -1: movw $1, %bx - movb $0xe, %ah - int $0x10 - -3: DATA32 call real_to_prot - .code32 - - popa - ret - - -LOCAL(bypass_table): - .word 0x0100 | '\e',0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r' - .word 0x1c00 | '\n' -LOCAL(bypass_table_end): - -/* - * int grub_console_getkey (void) - * if there is a character pending, return it; otherwise return -1 - * BIOS call "INT 16H Function 01H" to check whether a character is pending - * Call with %ah = 0x1 - * Return: - * If key waiting to be input: - * %ah = keyboard scan code - * %al = ASCII character - * Zero flag = clear - * else - * Zero flag = set - * BIOS call "INT 16H Function 00H" to read character from keyboard - * Call with %ah = 0x0 - * Return: %ah = keyboard scan code - * %al = ASCII character - */ - -FUNCTION(grub_console_getkey) - pushl %ebp - - call prot_to_real - .code16 - - /* - * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would - * cause the machine to hang at the second keystroke. However, we can - * work around this problem by ensuring the presence of keystroke with - * INT 16/AH = 1 before calling INT 16/AH = 0. - */ - - movb $1, %ah - int $0x16 - jz notpending - - movb $0, %ah - int $0x16 - - xorl %edx, %edx - movw %ax, %dx /* real_to_prot uses %eax */ - - DATA32 call real_to_prot - .code32 - - movl $0xff, %eax - testl %eax, %edx - jz 1f - - andl %edx, %eax - cmp %eax, 0x20 - ja 2f - movl %edx, %eax - leal LOCAL(bypass_table), %esi - movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx - repne cmpsw - jz 3f - - addl $('a' - 1 | GRUB_TERM_CTRL), %eax - jmp 2f -3: - andl $0xff, %eax - jmp 2f - -1: movl %edx, %eax - shrl $8, %eax - orl $GRUB_TERM_EXTENDED, %eax -2: - popl %ebp - ret - -notpending: - .code16 - DATA32 call real_to_prot - .code32 -#if GRUB_TERM_NO_KEY != 0 -#error Fix this asm code -#endif - jmp 2b - - -/* - * grub_uint16_t grub_console_getxy (void) - * BIOS call "INT 10H Function 03h" to get cursor position - * Call with %ah = 0x03 - * %bh = page - * Returns %ch = starting scan line - * %cl = ending scan line - * %dh = row (0 is top) - * %dl = column (0 is left) - */ - - -FUNCTION(grub_console_getxy) - pushl %ebp - pushl %ebx /* save EBX */ - - call prot_to_real - .code16 - - xorb %bh, %bh /* set page to 0 */ - movb $0x3, %ah - int $0x10 /* get cursor position */ - - DATA32 call real_to_prot - .code32 - - movb %dl, %ah - movb %dh, %al - - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y) - * BIOS call "INT 10H Function 02h" to set cursor position - * Call with %ah = 0x02 - * %bh = page - * %dh = row (0 is top) - * %dl = column (0 is left) - */ - - -FUNCTION(grub_console_gotoxy) - pushl %ebp - pushl %ebx /* save EBX */ - - movb %cl, %dh /* %dh = y */ - /* %dl = x */ - - call prot_to_real - .code16 - - xorb %bh, %bh /* set page to 0 */ - movb $0x2, %ah - int $0x10 /* set cursor position */ - - DATA32 call real_to_prot - .code32 - - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_cls (void) - * BIOS call "INT 10H Function 09h" to write character and attribute - * Call with %ah = 0x09 - * %al = (character) - * %bh = (page number) - * %bl = (attribute) - * %cx = (number of times) - */ - -FUNCTION(grub_console_cls) - pushl %ebp - pushl %ebx /* save EBX */ - - call prot_to_real - .code16 - - /* move the cursor to the beginning */ - movb $0x02, %ah - xorb %bh, %bh - xorw %dx, %dx - int $0x10 - - /* write spaces to the entire screen */ - movw $0x0920, %ax - movw $0x07, %bx - movw $(80 * 25), %cx - int $0x10 - - /* move back the cursor */ - movb $0x02, %ah - int $0x10 - - DATA32 call real_to_prot - .code32 - - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_setcursor (int on) - * BIOS call "INT 10H Function 01h" to set cursor type - * Call with %ah = 0x01 - * %ch = cursor starting scanline - * %cl = cursor ending scanline - */ - -console_cursor_state: - .byte 1 -console_cursor_shape: - .word 0 - -FUNCTION(grub_console_setcursor) - pushl %ebp - pushl %ebx - - /* push ON */ - pushl %edx - - /* check if the standard cursor shape has already been saved */ - movw console_cursor_shape, %ax - testw %ax, %ax - jne 1f - - call prot_to_real - .code16 - - movb $0x03, %ah - xorb %bh, %bh - int $0x10 - - DATA32 call real_to_prot - .code32 - - movw %cx, console_cursor_shape -1: - /* set %cx to the designated cursor shape */ - movw $0x2000, %cx - popl %eax - testl %eax, %eax - jz 2f - movw console_cursor_shape, %cx -2: - call prot_to_real - .code16 - - movb $0x1, %ah - int $0x10 - - DATA32 call real_to_prot - .code32 - - popl %ebx - popl %ebp - ret - -/* - * grub_get_rtc() - * return the real time in ticks, of which there are about - * 18-20 per second - */ -FUNCTION(grub_get_rtc) - pushl %ebp - - call prot_to_real /* enter real mode */ - .code16 - - /* %ax is already zero */ - int $0x1a - - DATA32 call real_to_prot - .code32 - - movl %ecx, %eax - shll $16, %eax - movw %dx, %ax - - popl %ebp - ret - /* * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry); */ @@ -881,7 +152,7 @@ FUNCTION(grub_pxe_call) shll $16, %edx addl %eax, %edx - call prot_to_real + PROT_TO_REAL .code16 pushl %ebx @@ -893,7 +164,7 @@ FUNCTION(grub_pxe_call) addw $10, %sp movw %ax, %cx - DATA32 call real_to_prot + REAL_TO_PROT .code32 movzwl %cx, %eax @@ -904,102 +175,8 @@ FUNCTION(grub_pxe_call) 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) +#include "../int.S" - 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 + .bss +VARIABLE(grub_boot_device) + .long 0 diff --git a/grub-core/kern/i386/qemu/mmap.c b/grub-core/kern/i386/qemu/mmap.c index 208f36b7e..2b0c7f6a7 100644 --- a/grub-core/kern/i386/qemu/mmap.c +++ b/grub-core/kern/i386/qemu/mmap.c @@ -41,8 +41,11 @@ static grub_uint64_t mem_size, above_4g; void grub_machine_mmap_init () { - mem_size = ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH)) << 24 - | ((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW)) << 16; + grub_uint8_t high, low, b, c, d; + grub_cmos_read (QEMU_CMOS_MEMSIZE_HIGH, &high); + grub_cmos_read (QEMU_CMOS_MEMSIZE_LOW, &low); + mem_size = ((grub_uint64_t) high) << 24 + | ((grub_uint64_t) low) << 16; if (mem_size > 0) { /* Don't ask... */ @@ -50,15 +53,19 @@ grub_machine_mmap_init () } else { + grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH, &high); + grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW, &low); mem_size - = ((((grub_uint64_t) grub_cmos_read (QEMU_CMOS_MEMSIZE2_HIGH)) << 18) - | ((grub_uint64_t) (grub_cmos_read (QEMU_CMOS_MEMSIZE2_LOW)) << 10)) + = ((((grub_uint64_t) high) << 18) | (((grub_uint64_t) low) << 10)) + 1024 * 1024; } - above_4g = (((grub_uint64_t) grub_cmos_read (0x5b)) << 16) - | (((grub_uint64_t) grub_cmos_read (0x5c)) << 24) - | (((grub_uint64_t) grub_cmos_read (0x5d)) << 32); + grub_cmos_read (0x5b, &b); + grub_cmos_read (0x5c, &c); + grub_cmos_read (0x5d, &d); + above_4g = (((grub_uint64_t) b) << 16) + | (((grub_uint64_t) c) << 24) + | (((grub_uint64_t) d) << 32); } grub_err_t diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S index 7834d1df5..0761807ed 100644 --- a/grub-core/kern/i386/qemu/startup.S +++ b/grub-core/kern/i386/qemu/startup.S @@ -32,16 +32,6 @@ _start: . = _start + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR VARIABLE(grub_core_entry_addr) .long 0 -VARIABLE(grub_kernel_image_size) - .long 0 -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END codestart: /* Relocate to low memory. First we figure out our location. @@ -53,11 +43,7 @@ codestart: value of `grub_core_entry_addr' in %esi. */ xorw %si, %si - /* ... which allows us to access `grub_kernel_image_size' - before relocation. */ - movl (grub_kernel_image_size - _start)(%esi), %ecx - - + movl $(_edata - _start), %ecx movl $_start, %edi cld rep @@ -65,24 +51,12 @@ codestart: ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $1f 1: -#ifdef APPLE_CC - /* clean out the bss */ - bss_start_abs = ABS (bss_start) - bss_end_abs = ABS (bss_end) - - movl bss_start_abs, %edi - - /* compute the bss length */ - movl bss_end_abs, %ecx - subl %edi, %ecx -#else /* clean out the bss */ movl $BSS_START_SYMBOL, %edi /* compute the bss length */ movl $END_SYMBOL, %ecx subl %edi, %ecx -#endif /* clean out */ xorl %eax, %eax diff --git a/grub-core/kern/i386/realmode.S b/grub-core/kern/i386/realmode.S index 578c8d2a8..36d41e7de 100644 --- a/grub-core/kern/i386/realmode.S +++ b/grub-core/kern/i386/realmode.S @@ -46,11 +46,19 @@ * This is the area for all of the special variables. */ - .p2align 2 /* force 4-byte alignment */ + .p2align 5 /* force 4-byte alignment */ protstack: .long GRUB_MEMORY_MACHINE_PROT_STACK + .macro PROT_TO_REAL + call prot_to_real + .endm + + .macro REAL_TO_PROT + DATA32 call real_to_prot + .endm + /* * This is the Global Descriptor Table * @@ -71,7 +79,7 @@ protstack: * description. */ - .p2align 2 /* force 4-byte alignment */ + .p2align 5 /* force 4-byte alignment */ gdt: .word 0, 0 .byte 0, 0, 0, 0 @@ -105,6 +113,7 @@ gdt: .byte 0, 0x92, 0, 0 + .p2align 5 /* this is the GDT descriptor */ gdtdesc: .word 0x27 /* limit */ @@ -162,6 +171,25 @@ protcseg: /* return on the old (or initialized) stack! */ ret +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,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 prot_to_real: /* just in case, set GDT */ @@ -225,18 +253,3 @@ realcseg: DATA32 ret .code32 - -/* - * grub_reboot() - * - * Reboot the system. At the moment, rely on BIOS. - */ -FUNCTION(grub_reboot) - call prot_to_real - .code16 -cold_reboot: - /* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */ - movw $0x0472, %di - movw %ax, (%di) - ljmp $0xf000, $0xfff0 - .code32 diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c new file mode 100644 index 000000000..31b5f94cf --- /dev/null +++ b/grub-core/kern/ia64/dl.c @@ -0,0 +1,276 @@ +/* dl.c - arch-dependent part of loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +/* Check if EHDR is a valid ELF header. */ +grub_err_t +grub_arch_dl_check_header (void *ehdr) +{ + Elf_Ehdr *e = ehdr; + + /* Check the magic numbers. */ + if (e->e_ident[EI_CLASS] != ELFCLASS64 + || e->e_ident[EI_DATA] != ELFDATA2LSB + || e->e_machine != EM_IA_64) + return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic"); + + return GRUB_ERR_NONE; +} + +#define MASK20 ((1 << 20) - 1) +#define MASK19 ((1 << 19) - 1) + +struct unaligned_uint32 +{ + grub_uint32_t val; +} __attribute__ ((packed)); + +static void +add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value) +{ + struct unaligned_uint32 *p; + switch (addr & 3) + { + case 0: + p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2); + p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2) + | (p->val & ~(MASK20 << 2))); + break; + case 1: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7); + p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3) + | (p->val & ~(MASK20 << 3))); + break; + case 2: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12); + p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4) + | (p->val & ~(MASK20 << 4))); + break; + } +} + +#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) ) + +static grub_uint32_t +add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value) +{ + grub_uint32_t high, mid, low, c; + low = (a & 0x00007f); + mid = (a & 0x7fc000) >> 7; + high = (a & 0x003e00) << 7; + c = (low | mid | high) + value; + return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00 +} + +static void +add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value) +{ + struct unaligned_uint32 *p; + switch (addr & 3) + { + case 0: + p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2); + p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2)); + break; + case 1: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7); + p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3)); + break; + case 2: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12); + p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4)); + break; + } +} + +static const grub_uint8_t nopm[5] = + { + /* [MLX] nop.m 0x0 */ + 0x05, 0x00, 0x00, 0x00, 0x01 + }; + +static const grub_uint8_t jump[0x20] = + { + /* ld8 r16=[r15],8 */ + 0x02, 0x80, 0x20, 0x1e, 0x18, 0x14, + /* mov r14=r1;; */ + 0xe0, 0x00, 0x04, 0x00, 0x42, 0x00, + /* nop.i 0x0 */ + 0x00, 0x00, 0x04, 0x00, + /* ld8 r1=[r15] */ + 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, + /* mov b6=r16 */ + 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, + /* br.few b6;; */ + 0x60, 0x00, 0x80, 0x00 + }; + +struct ia64_trampoline +{ + /* nop.m */ + grub_uint8_t nop[5]; + /* movl r15 = addr*/ + grub_uint8_t addr_hi[6]; + grub_uint8_t e0; + grub_uint8_t addr_lo[4]; + grub_uint8_t jump[0x20]; +}; + +static void +make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr) +{ + COMPILE_TIME_ASSERT (sizeof (struct ia64_trampoline) + == GRUB_IA64_DL_TRAMP_SIZE); + grub_memcpy (tr->nop, nopm, sizeof (tr->nop)); + tr->addr_hi[0] = ((addr & 0xc00000) >> 16); + tr->addr_hi[1] = (addr >> 24) & 0xff; + tr->addr_hi[2] = (addr >> 32) & 0xff; + tr->addr_hi[3] = (addr >> 40) & 0xff; + tr->addr_hi[4] = (addr >> 48) & 0xff; + tr->addr_hi[5] = (addr >> 56) & 0xff; + tr->e0 = 0xe0; + tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01; + tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11) + | ((addr & 0x200000) >> 17)); + tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19); + tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60; + grub_memcpy (tr->jump, jump, sizeof (tr->jump)); +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +{ + Elf_Ehdr *e = ehdr; + Elf_Shdr *s; + Elf_Word entsize; + unsigned i; + grub_uint64_t *gp, *gpptr; + struct ia64_trampoline *tr; + + gp = (grub_uint64_t *) mod->base; + gpptr = (grub_uint64_t *) mod->got; + tr = mod->tramp; + + /* Find a symbol table. */ + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + + if (i == e->e_shnum) + return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found"); + + entsize = s->sh_entsize; + + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) + if (s->sh_type == SHT_RELA) + { + grub_dl_segment_t seg; + + /* Find the target segment. */ + for (seg = mod->segment; seg; seg = seg->next) + if (seg->section == s->sh_info) + break; + + if (seg) + { + Elf_Rela *rel, *max; + + for (rel = (Elf_Rela *) ((char *) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel++) + { + grub_addr_t addr; + Elf_Sym *sym; + grub_uint64_t value; + + if (seg->size < (rel->r_offset & ~3)) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + addr = (grub_addr_t) seg->addr + rel->r_offset; + sym = (Elf_Sym *) ((char *) mod->symtab + + entsize * ELF_R_SYM (rel->r_info)); + + /* On the PPC the value does not have an explicit + addend, add it. */ + value = sym->st_value + rel->r_addend; + + switch (ELF_R_TYPE (rel->r_info)) + { + case R_IA64_PCREL21B: + { + grub_uint64_t noff; + make_trampoline (tr, value); + noff = ((char *) tr - (char *) (addr & ~3)) >> 4; + tr++; + if (noff & ~MASK19) + return grub_error (GRUB_ERR_BAD_OS, + "trampoline offset too big (%lx)", noff); + add_value_to_slot_20b (addr, noff); + } + break; + case R_IA64_SEGREL64LSB: + *(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr; + break; + case R_IA64_FPTR64LSB: + case R_IA64_DIR64LSB: + *(grub_uint64_t *) addr += value; + break; + case R_IA64_PCREL64LSB: + *(grub_uint64_t *) addr += value - addr; + break; + case R_IA64_GPREL22: + add_value_to_slot_21 (addr, value - (grub_addr_t) gp); + break; + + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + value = *(grub_uint64_t *) sym->st_value + rel->r_addend; + case R_IA64_LTOFF_FPTR22: + *gpptr = value; + add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp); + gpptr++; + break; + + /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */ + case R_IA64_LDXMOV: + break; + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "this relocation (0x%x) is not implemented yet", + ELF_R_TYPE (rel->r_info)); + } + } + } + } + + return GRUB_ERR_NONE; +} diff --git a/grub-core/kern/ia64/dl_helper.c b/grub-core/kern/ia64/dl_helper.c new file mode 100644 index 000000000..958cdb25e --- /dev/null +++ b/grub-core/kern/ia64/dl_helper.c @@ -0,0 +1,70 @@ +/* dl.c - arch-dependent part of loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +void +grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got) +{ + const Elf64_Ehdr *e = ehdr; + grub_size_t cntt = 0, cntg = 0;; + const Elf64_Shdr *s; + unsigned i; + + /* Find a symbol table. */ + for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu32 (e->e_shoff)); + i < grub_le_to_cpu16 (e->e_shnum); + i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize))) + if (grub_le_to_cpu32 (s->sh_type) == SHT_SYMTAB) + break; + + if (i == grub_le_to_cpu16 (e->e_shnum)) + return; + + for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu32 (e->e_shoff)); + i < grub_le_to_cpu16 (e->e_shnum); + i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16 (e->e_shentsize))) + if (grub_le_to_cpu32 (s->sh_type) == SHT_RELA) + { + Elf64_Rela *rel, *max; + + for (rel = (Elf64_Rela *) ((char *) e + grub_le_to_cpu32 (s->sh_offset)), + max = rel + grub_le_to_cpu32 (s->sh_size) / grub_le_to_cpu16 (s->sh_entsize); + rel < max; rel++) + switch (ELF64_R_TYPE (grub_le_to_cpu32 (rel->r_info))) + { + case R_IA64_PCREL21B: + cntt++; + break; + case R_IA64_LTOFF_FPTR22: + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + cntg++; + break; + } + } + *tramp = cntt; + *got = cntg; +} + diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c new file mode 100644 index 000000000..e2fa58090 --- /dev/null +++ b/grub-core/kern/ia64/efi/init.c @@ -0,0 +1,54 @@ +/* init.c - initialize an ia64-based EFI system */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void +grub_machine_init (void) +{ + grub_efi_init (); + grub_install_get_time_ms (grub_rtc_get_time_ms); +} + +void +grub_machine_fini (void) +{ + grub_efi_fini (); +} + +void +grub_arch_sync_caches (void *address, grub_size_t len) +{ + /* Cache line length is at least 32. */ + grub_uint64_t a = (grub_uint64_t)address & ~0x1f; + + /* Flush data. */ + for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20) + asm volatile ("fc.i %0" : : "r" (a)); + /* Sync and serialize. Maybe extra. */ + asm volatile (";; sync.i;; srlz.i;;"); +} diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S new file mode 100644 index 000000000..d75c6d7cc --- /dev/null +++ b/grub-core/kern/ia64/efi/startup.S @@ -0,0 +1,44 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +#include +#include +#include + + .text + .psr abi64 + .psr lsb + .lsb + + .global _start + .proc _start +_start: + alloc loc0=ar.pfs,2,4,0,0 + mov loc1=rp + addl loc2=@gprel(grub_efi_image_handle),gp + addl loc3=@gprel(grub_efi_system_table),gp + ;; + st8 [loc2]=in0 + st8 [loc3]=in1 + br.call.sptk.few rp=grub_main + ;; + mov ar.pfs=loc0 + mov rp=loc1 + ;; + br.ret.sptk.few rp + + .endp _start diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c index 30eacbbdd..9e80757f4 100644 --- a/grub-core/kern/ieee1275/cmain.c +++ b/grub-core/kern/ieee1275/cmain.c @@ -60,6 +60,10 @@ grub_ieee1275_find_options (void) int is_olpc = 0; int is_qemu = 0; +#ifdef __sparc__ + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0); +#endif + grub_ieee1275_finddevice ("/", &root); grub_ieee1275_finddevice ("/options", &options); grub_ieee1275_finddevice ("/openprom", &openprom); @@ -84,6 +88,9 @@ grub_ieee1275_find_options (void) if (rc >= 0 && !grub_strcmp (tmp, "Emulated PC")) is_qemu = 1; + if (grub_strncmp (tmp, "PowerMac", sizeof ("PowerMac") - 1) == 0) + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS); + if (is_smartfirmware) { /* Broken in all versions */ diff --git a/grub-core/kern/ieee1275/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c index 9e2919172..98217029f 100644 --- a/grub-core/kern/ieee1275/ieee1275.c +++ b/grub-core/kern/ieee1275/ieee1275.c @@ -27,7 +27,7 @@ int -grub_ieee1275_finddevice (char *name, grub_ieee1275_phandle_t *phandlep) +grub_ieee1275_finddevice (const char *name, grub_ieee1275_phandle_t *phandlep) { struct find_device_args { @@ -232,7 +232,7 @@ grub_ieee1275_instance_to_path (grub_ieee1275_ihandle_t ihandle, } int -grub_ieee1275_write (grub_ieee1275_ihandle_t ihandle, void *buffer, +grub_ieee1275_write (grub_ieee1275_ihandle_t ihandle, const void *buffer, grub_size_t len, grub_ssize_t *actualp) { struct write_args @@ -532,7 +532,7 @@ grub_ieee1275_release (grub_addr_t addr, grub_size_t size) int grub_ieee1275_set_property (grub_ieee1275_phandle_t phandle, - const char *propname, void *buf, + const char *propname, const void *buf, grub_size_t size, grub_ssize_t *actual) { struct set_property_args diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 682a8b5a4..76f932d09 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -31,8 +31,12 @@ #include #include #include +#include #include #include +#ifdef __sparc__ +#include +#endif /* The minimal heap size we can live with. */ #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) @@ -47,6 +51,10 @@ extern char _start[]; extern char _end[]; +#ifdef __sparc__ +grub_addr_t grub_ieee1275_original_stack; +#endif + void grub_exit (void) { @@ -68,37 +76,51 @@ grub_translate_ieee1275_path (char *filepath) } } +void (*grub_ieee1275_net_config) (const char *dev, + char **device, + char **path); void -grub_machine_set_prefix (void) +grub_machine_get_bootlocation (char **device, char **path) { char bootpath[64]; /* XXX check length */ char *filename; - char *prefix; - - if (grub_prefix[0]) - { - grub_env_set ("prefix", grub_prefix); - /* Prefix is hardcoded in the core image. */ - return; - } - + char *type; + if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", &bootpath, sizeof (bootpath), 0)) { /* Should never happen. */ grub_printf ("/chosen/bootpath property missing!\n"); - grub_env_set ("prefix", ""); return; } /* Transform an OF device path to a GRUB path. */ - prefix = grub_ieee1275_encode_devname (bootpath); + type = grub_ieee1275_get_device_type (bootpath); + if (type && grub_strcmp (type, "network") == 0) + { + char *dev, *canon; + char *ptr; + dev = grub_ieee1275_get_aliasdevname (bootpath); + canon = grub_ieee1275_canonicalise_devname (dev); + ptr = canon + grub_strlen (canon) - 1; + while (ptr > canon && (*ptr == ',' || *ptr == ':')) + ptr--; + ptr++; + *ptr = 0; + + if (grub_ieee1275_net_config) + grub_ieee1275_net_config (canon, device, path); + grub_free (dev); + grub_free (canon); + } + else + *device = grub_ieee1275_encode_devname (bootpath); + grub_free (type); filename = grub_ieee1275_get_filename (bootpath); if (filename) { - char *newprefix; char *lastslash = grub_strrchr (filename, '\\'); /* Truncate at last directory. */ @@ -107,23 +129,22 @@ grub_machine_set_prefix (void) *lastslash = '\0'; grub_translate_ieee1275_path (filename); - newprefix = grub_xasprintf ("%s%s", prefix, filename); - if (newprefix) - { - grub_free (prefix); - prefix = newprefix; - } + *path = filename; } } - - grub_env_set ("prefix", prefix); - - grub_free (filename); - grub_free (prefix); } /* Claim some available memory in the first /memory node. */ -static void grub_claim_heap (void) +#ifdef __sparc__ +static void +grub_claim_heap (void) +{ + grub_mm_init_region ((void *) (grub_modules_get_end () + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); +} +#else +static void +grub_claim_heap (void) { unsigned long total = 0; @@ -191,23 +212,14 @@ static void grub_claim_heap (void) else grub_machine_mmap_iterate (heap_init); } +#endif -static grub_uint64_t ieee1275_get_time_ms (void); - -void -grub_machine_init (void) +static void +grub_parse_cmdline (void) { - char args[256]; grub_ssize_t actual; + char args[256]; - grub_ieee1275_init (); - - grub_console_init_early (); - grub_claim_heap (); - grub_console_init_lately (); - grub_ofdisk_init (); - - /* Process commandline. */ if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args, sizeof args, &actual) == 0 && actual > 1) @@ -240,6 +252,26 @@ grub_machine_init (void) } } } +} + +static grub_uint64_t ieee1275_get_time_ms (void); + +grub_addr_t grub_modbase; + +void +grub_machine_init (void) +{ + grub_modbase = ALIGN_UP((grub_addr_t) _end + + GRUB_KERNEL_MACHINE_MOD_GAP, + GRUB_KERNEL_MACHINE_MOD_ALIGN); + grub_ieee1275_init (); + + grub_console_init_early (); + grub_claim_heap (); + grub_console_init_lately (); + grub_ofdisk_init (); + + grub_parse_cmdline (); grub_install_get_time_ms (ieee1275_get_time_ms); } @@ -266,9 +298,3 @@ grub_get_rtc (void) { return ieee1275_get_time_ms (); } - -grub_addr_t -grub_arch_modules_addr (void) -{ - return ALIGN_UP((grub_addr_t) _end + GRUB_KERNEL_MACHINE_MOD_GAP, GRUB_KERNEL_MACHINE_MOD_ALIGN); -} diff --git a/grub-core/kern/ieee1275/mmap.c b/grub-core/kern/ieee1275/mmap.c index 942e5a354..2e4e085bb 100644 --- a/grub-core/kern/ieee1275/mmap.c +++ b/grub-core/kern/ieee1275/mmap.c @@ -50,6 +50,12 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /memory/available property"); + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS)) + { + address_cells = 1; + size_cells = 1; + } + /* Decode each entry and call `hook'. */ i = 0; available_size /= sizeof (grub_uint32_t); diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c index f5dc8efb1..1dc932e49 100644 --- a/grub-core/kern/ieee1275/openfw.c +++ b/grub-core/kern/ieee1275/openfw.c @@ -22,16 +22,19 @@ #include #include #include +#include enum grub_ieee1275_parse_type { GRUB_PARSE_FILENAME, GRUB_PARSE_PARTITION, + GRUB_PARSE_DEVICE, + GRUB_PARSE_DEVICE_TYPE }; /* Walk children of 'devpath', calling hook for each. */ int -grub_children_iterate (char *devpath, +grub_children_iterate (const char *devpath, int (*hook) (struct grub_ieee1275_devalias *alias)) { grub_ieee1275_phandle_t dev; @@ -161,7 +164,7 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) strings, so we will add a NULL byte at the end explicitly. */ pathlen += 1; - devpath = grub_malloc (pathlen); + devpath = grub_malloc (pathlen + 1); if (! devpath) { grub_free (devtype); @@ -170,12 +173,15 @@ grub_devalias_iterate (int (*hook) (struct grub_ieee1275_devalias *alias)) } if (grub_ieee1275_get_property (aliases, aliasname, devpath, pathlen, - &actual)) + &actual) || actual < 0) { grub_dprintf ("devalias", "get_property (%s) failed\n", aliasname); goto nextprop; } - devpath [actual] = '\0'; + if (actual > pathlen) + actual = pathlen; + devpath[actual] = '\0'; + devpath[pathlen] = '\0'; if (grub_ieee1275_finddevice (devpath, &dev)) { @@ -291,7 +297,8 @@ grub_ieee1275_get_devname (const char *path) int match_alias (struct grub_ieee1275_devalias *curalias) { /* briQ firmware can change capitalization in /chosen/bootpath. */ - if (! grub_strncasecmp (curalias->path, path, pathlen)) + if (grub_strncasecmp (curalias->path, path, pathlen) == 0 + && curalias->path[pathlen] == 0) { newpath = grub_strdup (curalias->name); return 1; @@ -317,14 +324,9 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype) { char type[64]; /* XXX check size. */ char *device = grub_ieee1275_get_devname (path); - char *args = grub_ieee1275_get_devargs (path); char *ret = 0; grub_ieee1275_phandle_t dev; - if (!args) - /* Shouldn't happen. */ - return 0; - /* We need to know what type of device it is in order to parse the full file path properly. */ if (grub_ieee1275_finddevice (device, &dev)) @@ -339,48 +341,93 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype) goto fail; } - if (!grub_strcmp ("block", type)) + switch (ptype) { - /* The syntax of the device arguments is defined in the CHRP and PReP - IEEE1275 bindings: "[partition][,[filename]]". */ - char *comma = grub_strchr (args, ','); + case GRUB_PARSE_DEVICE: + ret = grub_strdup (device); + break; + case GRUB_PARSE_DEVICE_TYPE: + ret = grub_strdup (type); + break; + case GRUB_PARSE_FILENAME: + { + char *comma; + char *args; - if (ptype == GRUB_PARSE_FILENAME) - { - if (comma) - { - char *filepath = comma + 1; + if (grub_strcmp ("block", type) != 0) + goto unknown; - /* Make sure filepath has leading backslash. */ - if (filepath[0] != '\\') - ret = grub_xasprintf ("\\%s", filepath); - else - ret = grub_strdup (filepath); + args = grub_ieee1275_get_devargs (path); + if (!args) + /* Shouldn't happen. */ + return 0; + + /* The syntax of the device arguments is defined in the CHRP and PReP + IEEE1275 bindings: "[partition][,[filename]]". */ + comma = grub_strchr (args, ','); + + if (comma) + { + char *filepath = comma + 1; + + /* Make sure filepath has leading backslash. */ + if (filepath[0] != '\\') + ret = grub_xasprintf ("\\%s", filepath); + else + ret = grub_strdup (filepath); } + grub_free (args); } - else if (ptype == GRUB_PARSE_PARTITION) - { - if (!comma) - ret = grub_strdup (args); - else - ret = grub_strndup (args, (grub_size_t)(comma - args)); - } - } - else - { - /* XXX Handle net devices by configuring & registering a grub_net_dev - here, then return its name? - Example path: "net:,,,,,". */ - grub_printf ("Unsupported type %s for device %s\n", type, device); + break; + case GRUB_PARSE_PARTITION: + { + char *comma; + char *args; + + if (grub_strcmp ("block", type) != 0) + goto unknown; + + args = grub_ieee1275_get_devargs (path); + if (!args) + /* Shouldn't happen. */ + return 0; + + comma = grub_strchr (args, ','); + if (!comma) + ret = grub_strdup (args); + else + ret = grub_strndup (args, (grub_size_t)(comma - args)); + /* Consistently provide numbered partitions to GRUB. + OpenBOOT traditionally uses alphabetical partition + specifiers. */ + if (ret[0] >= 'a' && ret[0] <= 'z') + ret[0] = '1' + (ret[0] - 'a'); + grub_free (args); + } + break; + default: + unknown: + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported type %s for device %s", type, device); } fail: grub_free (device); - grub_free (args); return ret; } +char * +grub_ieee1275_get_device_type (const char *path) +{ + return grub_ieee1275_parse_args (path, GRUB_PARSE_DEVICE_TYPE); +} + +char * +grub_ieee1275_get_aliasdevname (const char *path) +{ + return grub_ieee1275_parse_args (path, GRUB_PARSE_DEVICE); +} + char * grub_ieee1275_get_filename (const char *path) { @@ -403,10 +450,10 @@ grub_ieee1275_encode_devname (const char *path) /* GRUB partition 1 is OF partition 0. */ partno++; - encoding = grub_xasprintf ("(%s,%d)", device, partno); + encoding = grub_xasprintf ("ieee1275/%s,%d", device, partno); } else - encoding = grub_xasprintf ("(%s)", device); + encoding = grub_xasprintf ("ieee1275/%s", device); grub_free (partition); grub_free (device); @@ -414,16 +461,6 @@ grub_ieee1275_encode_devname (const char *path) return encoding; } -/* On i386, a firmware-independant grub_reboot() is provided by realmode.S. */ -#ifndef __i386__ -void -grub_reboot (void) -{ - grub_ieee1275_interpret ("reset-all", 0); - for (;;) ; -} -#endif - /* Resolve aliases. */ char * grub_ieee1275_canonicalise_devname (const char *path) @@ -467,3 +504,4 @@ grub_ieee1275_canonicalise_devname (const char *path) grub_free (buf); return NULL; } + diff --git a/grub-core/kern/list.c b/grub-core/kern/list.c index 33c334166..f7c4e6bbe 100644 --- a/grub-core/kern/list.c +++ b/grub-core/kern/list.c @@ -21,26 +21,6 @@ #include #include -void -grub_list_push (grub_list_t *head, grub_list_t item) -{ - item->next = *head; - *head = item; -} - -void -grub_list_remove (grub_list_t *head, grub_list_t item) -{ - grub_list_t *p, q; - - for (p = head, q = *p; q; p = &(q->next), q = q->next) - if (q == item) - { - *p = q->next; - break; - } -} - void * grub_named_list_find (grub_named_list_t head, const char *name) { @@ -81,6 +61,9 @@ grub_prio_list_insert (grub_prio_list_t *head, grub_prio_list_t nitem) *p = nitem; nitem->next = q; + if (q) + q->prev = &nitem->next; + nitem->prev = p; if (! inactive) nitem->prio |= GRUB_PRIO_LIST_FLAG_ACTIVE; diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c index 8b6c8a180..185230c5c 100644 --- a/grub-core/kern/main.c +++ b/grub-core/kern/main.c @@ -30,45 +30,20 @@ #include #include -void -grub_module_iterate (int (*hook) (struct grub_module_header *header)) -{ - struct grub_module_info *modinfo; - struct grub_module_header *header; - grub_addr_t modbase; - - modbase = grub_arch_modules_addr (); - modinfo = (struct grub_module_info *) modbase; - - /* Check if there are any modules. */ - if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC) - return; - - for (header = (struct grub_module_header *) (modbase + modinfo->offset); - header < (struct grub_module_header *) (modbase + modinfo->size); - header = (struct grub_module_header *) ((char *) header + header->size)) - { - if (hook (header)) - break; - } -} - -/* This is actualy platform-independant but used only on yeeloong and sparc. */ -#if defined (GRUB_MACHINE_MIPS_YEELOONG) || defined (GRUB_MACHINE_SPARC64) +/* This is actualy platform-independant but used only on loongson and sparc. */ +#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_SPARC64) grub_addr_t grub_modules_get_end (void) { struct grub_module_info *modinfo; - grub_addr_t modbase; - modbase = grub_arch_modules_addr (); - modinfo = (struct grub_module_info *) modbase; + modinfo = (struct grub_module_info *) grub_modbase; /* Check if there are any modules. */ if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC) - return modbase; + return grub_modbase; - return modbase + modinfo->size; + return grub_modbase + modinfo->size; } #endif @@ -76,42 +51,36 @@ grub_modules_get_end (void) static void grub_load_modules (void) { - auto int hook (struct grub_module_header *); - int hook (struct grub_module_header *header) - { - /* Not an ELF module, skip. */ - if (header->type != OBJ_TYPE_ELF) - return 0; + struct grub_module_header *header; + FOR_MODULES (header) + { + /* Not an ELF module, skip. */ + if (header->type != OBJ_TYPE_ELF) + continue; - if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header), - (header->size - sizeof (struct grub_module_header)))) - grub_fatal ("%s", grub_errmsg); + if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header), + (header->size - sizeof (struct grub_module_header)))) + grub_fatal ("%s", grub_errmsg); - if (grub_errno) - grub_print_error (); - - return 0; - } - - grub_module_iterate (hook); + if (grub_errno) + grub_print_error (); + } } static void grub_load_config (void) { - auto int hook (struct grub_module_header *); - int hook (struct grub_module_header *header) - { - /* Not an embedded config, skip. */ - if (header->type != OBJ_TYPE_CONFIG) - return 0; - - grub_parser_execute ((char *) header + - sizeof (struct grub_module_header)); - return 1; - } - - grub_module_iterate (hook); + struct grub_module_header *header; + FOR_MODULES (header) + { + /* Not an embedded config, skip. */ + if (header->type != OBJ_TYPE_CONFIG) + continue; + + grub_parser_execute ((char *) header + + sizeof (struct grub_module_header)); + break; + } } /* Write hook for the environment variables of root. Remove surrounding @@ -129,27 +98,81 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)), return grub_strdup (val); } -/* Set the root device according to the dl prefix. */ static void -grub_set_root_dev (void) +grub_set_prefix_and_root (void) { - const char *prefix; + char *device = NULL; + char *path = NULL; + char *fwdevice = NULL; + char *fwpath = NULL; + char *prefix = NULL; + struct grub_module_header *header; + + FOR_MODULES (header) + if (header->type == OBJ_TYPE_PREFIX) + prefix = (char *) header + sizeof (struct grub_module_header); grub_register_variable_hook ("root", 0, grub_env_write_root); - prefix = grub_env_get ("prefix"); - if (prefix) { - char *dev; - - dev = grub_file_get_device_name (prefix); - if (dev) + char *pptr = NULL; + if (prefix[0] == '(') { - grub_env_set ("root", dev); - grub_free (dev); + pptr = grub_strrchr (prefix, ')'); + if (pptr) + { + device = grub_strndup (prefix + 1, pptr - prefix - 1); + pptr++; + } } + if (!pptr) + pptr = prefix; + if (pptr[0]) + path = grub_strdup (pptr); } + if ((!device || device[0] == ',' || !device[0]) || !path) + grub_machine_get_bootlocation (&fwdevice, &fwpath); + + if (!device && fwdevice) + device = fwdevice; + else if (fwdevice && (device[0] == ',' || !device[0])) + { + /* We have a partition, but still need to fill in the drive. */ + char *comma, *new_device; + + comma = grub_strchr (fwdevice, ','); + if (comma) + { + char *drive = grub_strndup (fwdevice, comma - fwdevice); + new_device = grub_xasprintf ("%s%s", drive, device); + grub_free (drive); + } + else + new_device = grub_xasprintf ("%s%s", fwdevice, device); + + grub_free (fwdevice); + grub_free (device); + device = new_device; + } + if (fwpath && !path) + path = fwpath; + if (device) + { + char *prefix_set; + + prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); + if (prefix_set) + { + grub_env_set ("prefix", prefix_set); + grub_free (prefix_set); + } + grub_env_set ("root", device); + } + + grub_free (device); + grub_free (path); + grub_print_error (); } /* Load the normal mode module and execute the normal mode if possible. */ @@ -159,7 +182,7 @@ grub_load_normal_mode (void) /* Load the module. */ grub_dl_load ("normal"); - /* Something went wrong. Print errors here to let user know why we're entering rescue mode. */ + /* Print errors if any. */ grub_print_error (); grub_errno = 0; @@ -167,7 +190,7 @@ grub_load_normal_mode (void) } /* The main routine. */ -void +void __attribute__ ((noreturn)) grub_main (void) { /* First of all, initialize the machine. */ @@ -187,8 +210,9 @@ grub_main (void) /* It is better to set the root device as soon as possible, for convenience. */ - grub_machine_set_prefix (); - grub_set_root_dev (); + grub_set_prefix_and_root (); + grub_env_export ("root"); + grub_env_export ("prefix"); grub_register_core_commands (); diff --git a/grub-core/kern/mips/arc/init.c b/grub-core/kern/mips/arc/init.c new file mode 100644 index 000000000..657a68ecd --- /dev/null +++ b/grub-core/kern/mips/arc/init.c @@ -0,0 +1,198 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *type_names[] = { +#ifdef GRUB_CPU_WORDS_BIGENDIAN + NULL, +#endif + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "eisa", "tc", "scsi", "dti", "multi", "disk", "tape", "cdrom", "worm", + "serial", "net", "video", "par", "point", "key", "audio", "other", + "rdisk", "fdisk", "tape", "modem", "monitor", "print", "pointer", + "keyboard", "term", "other", "line", "network", NULL +}; + +static int +iterate_rec (const char *prefix, const struct grub_arc_component *parent, + int (*hook) (const char *name, + const struct grub_arc_component *comp), + int alt_names) +{ + const struct grub_arc_component *comp; + FOR_ARC_CHILDREN(comp, parent) + { + char *name; + const char *cname = NULL; + if (comp->type < ARRAY_SIZE (type_names)) + cname = type_names[comp->type]; + if (!cname) + cname = "unknown"; + if (alt_names) + name = grub_xasprintf ("%s/%s%lu", prefix, cname, comp->key); + else + name = grub_xasprintf ("%s%s(%lu)", prefix, cname, comp->key); + if (!name) + return 1; + if (hook (name, comp)) + { + grub_free (name); + return 1; + } + if (iterate_rec ((parent ? name : prefix), comp, hook, alt_names)) + { + grub_free (name); + return 1; + } + grub_free (name); + } + return 0; +} + +int +grub_arc_iterate_devs (int (*hook) (const char *name, + const struct grub_arc_component *comp), + int alt_names) +{ + return iterate_rec ((alt_names ? "arc" : ""), NULL, hook, alt_names); +} + +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook) +{ + struct grub_arc_memory_descriptor *cur = NULL; + while (1) + { + grub_memory_type_t type; + cur = GRUB_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur); + if (!cur) + return GRUB_ERR_NONE; + switch (cur->type) + { + case GRUB_ARC_MEMORY_EXCEPTION_BLOCK: + case GRUB_ARC_MEMORY_SYSTEM_PARAMETER_BLOCK: + case GRUB_ARC_MEMORY_FW_PERMANENT: + default: + type = GRUB_MEMORY_RESERVED; + break; + + case GRUB_ARC_MEMORY_FW_TEMPORARY: + case GRUB_ARC_MEMORY_FREE: + case GRUB_ARC_MEMORY_LOADED: + case GRUB_ARC_MEMORY_FREE_CONTIGUOUS: + type = GRUB_MEMORY_AVAILABLE; + break; + case GRUB_ARC_MEMORY_BADRAM: + type = GRUB_MEMORY_BADRAM; + break; + } + if (hook (((grub_uint64_t) cur->start_page) << 12, + ((grub_uint64_t) cur->num_pages) << 12, type)) + return GRUB_ERR_NONE; + } +} + +extern grub_uint32_t grub_total_modules_size __attribute__ ((section(".text"))); +grub_addr_t grub_modbase; + +void +grub_machine_init (void) +{ + struct grub_arc_memory_descriptor *cur = NULL; + + grub_modbase = GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size; + grub_console_init_early (); + + /* FIXME: measure this. */ + grub_arch_cpuclock = 64000000; + grub_install_get_time_ms (grub_rtc_get_time_ms); + + while (1) + { + grub_uint64_t start, end; + cur = GRUB_ARC_FIRMWARE_VECTOR->getmemorydescriptor (cur); + if (!cur) + break; + if (cur->type != GRUB_ARC_MEMORY_FREE + && cur->type != GRUB_ARC_MEMORY_LOADED + && cur->type != GRUB_ARC_MEMORY_FREE_CONTIGUOUS) + continue; + start = ((grub_uint64_t) cur->start_page) << 12; + end = ((grub_uint64_t) cur->num_pages) << 12; + end += start; + if ((grub_uint64_t) end > ((GRUB_KERNEL_MIPS_ARC_LINK_ADDR + - grub_total_modules_size) & 0x1fffffff)) + end = ((GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size) + & 0x1fffffff); + if (end > start) + grub_mm_init_region ((void *) (grub_addr_t) (start | 0x80000000), + end - start); + } + + grub_console_init_lately (); + + grub_arcdisk_init (); +} + +void +grub_machine_fini (void) +{ +} + +void +grub_halt (void) +{ + GRUB_ARC_FIRMWARE_VECTOR->powerdown (); + + grub_millisleep (1500); + + grub_puts_ (N_("Shutdown failed")); + grub_refresh (); + while (1); +} + +void +grub_exit (void) +{ + GRUB_ARC_FIRMWARE_VECTOR->exit (); + + grub_millisleep (1500); + + grub_puts_ (N_("Exit failed")); + grub_refresh (); + while (1); +} + diff --git a/grub-core/kern/mips/cache.S b/grub-core/kern/mips/cache.S index 999872f6b..a4aa06fb0 100644 --- a/grub-core/kern/mips/cache.S +++ b/grub-core/kern/mips/cache.S @@ -8,3 +8,38 @@ FUNCTION (grub_cpu_flush_cache) FUNCTION (grub_arch_sync_caches) #include "cache_flush.S" j $ra + +FUNCTION (grub_arch_sync_dma_caches) + move $t2, $a0 + addu $t3, $a0, $a1 + srl $t2, $t2, 5 + sll $t2, $t2, 5 + addu $t3, $t3, 0x1f + srl $t3, $t3, 5 + sll $t3, $t3, 5 + move $t0, $t2 + subu $t1, $t3, $t2 +1: + cache 1, 0($t0) + addiu $t1, $t1, 0xffff + bne $t1, $zero, 1b + addiu $t0, $t0, 0x1 + sync + move $t0, $t2 + subu $t1, $t3, $t2 +2: + cache 0, 0($t0) + addiu $t1, $t1, 0xffff + bne $t1, $zero, 2b + addiu $t0, $t0, 0x1 + sync + move $t0, $t2 + subu $t1, $t3, $t2 +2: + cache 23, 0($t0) + addiu $t1, $t1, 0xffff + bne $t1, $zero, 2b + addiu $t0, $t0, 0x1 + sync + + jr $ra \ No newline at end of file diff --git a/grub-core/kern/mips/cache_flush.S b/grub-core/kern/mips/cache_flush.S index 11096c035..c03c337b5 100644 --- a/grub-core/kern/mips/cache_flush.S +++ b/grub-core/kern/mips/cache_flush.S @@ -9,15 +9,22 @@ subu $t1, $t3, $t2 1: cache 1, 0($t0) - addiu $t1, $t1, 0xffff + /* All four ways. */ +#ifdef GRUB_MACHINE_MIPS_LOONGSON + cache 1, 1($t0) + cache 1, 2($t0) + cache 1, 3($t0) +#endif + + addiu $t1, $t1, -0x4 bne $t1, $zero, 1b - addiu $t0, $t0, 0x1 + addiu $t0, $t0, 0x4 sync move $t0, $t2 subu $t1, $t3, $t2 2: cache 0, 0($t0) - addiu $t1, $t1, 0xffff + addiu $t1, $t1, -0x4 bne $t1, $zero, 2b - addiu $t0, $t0, 0x1 + addiu $t0, $t0, 0x4 sync diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c index 485955e7f..ad9340683 100644 --- a/grub-core/kern/mips/dl.c +++ b/grub-core/kern/mips/dl.c @@ -34,7 +34,7 @@ grub_arch_dl_check_header (void *ehdr) Elf_Ehdr *e = ehdr; /* Check the magic numbers. */ -#ifdef WORDS_BIGENDIAN +#ifdef GRUB_CPU_WORDS_BIGENDIAN if (e->e_ident[EI_CLASS] != ELFCLASS32 || e->e_ident[EI_DATA] != ELFDATA2MSB || e->e_machine != EM_MIPS) @@ -144,14 +144,14 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) rel < max; rel++) { - Elf_Word *addr; + grub_uint8_t *addr; Elf_Sym *sym; if (seg->size < rel->r_offset) return grub_error (GRUB_ERR_BAD_MODULE, "reloc offset is out of the segment"); - addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset); + addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset); sym = (Elf_Sym *) ((char *) mod->symtab + entsize * ELF_R_SYM (rel->r_info)); if (sym->st_value == (grub_addr_t) &__gnu_local_gp_dummy) @@ -163,7 +163,11 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) { grub_uint32_t value; Elf_Rel *rel2; - + +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif + /* Handle partner lo16 relocation. Lower part is treated as signed. Hence add 0x8000 to compensate. */ @@ -175,13 +179,20 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) && ELF_R_TYPE (rel2->r_info) == R_MIPS_LO16) { value += *(grub_int16_t *) - ((char *) seg->addr + rel2->r_offset); + ((char *) seg->addr + rel2->r_offset +#ifdef GRUB_CPU_WORDS_BIGENDIAN + + 2 +#endif + ); break; } *(grub_uint16_t *) addr = (value >> 16) & 0xffff; } break; case R_MIPS_LO16: +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif *(grub_uint16_t *) addr += (sym->st_value) & 0xffff; break; case R_MIPS_32: @@ -208,11 +219,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) case R_MIPS_GOT16: case R_MIPS_CALL16: /* FIXME: reuse*/ +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif *gpptr = sym->st_value + *(grub_uint16_t *) addr; *(grub_uint16_t *) addr = sizeof (grub_uint32_t) * (gpptr - gp); gpptr++; break; + case R_MIPS_JALR: + break; default: { grub_free (gp); @@ -232,6 +248,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) void grub_arch_dl_init_linker (void) { - grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0); + grub_dl_register_symbol ("__gnu_local_gp", &__gnu_local_gp_dummy, 0, 0); } diff --git a/grub-core/kern/mips/init.c b/grub-core/kern/mips/init.c index f220108d4..353f679e6 100644 --- a/grub-core/kern/mips/init.c +++ b/grub-core/kern/mips/init.c @@ -18,17 +18,27 @@ #include #include +#include +#include + +/* FIXME: use interrupt to count high. */ +grub_uint64_t +grub_get_rtc (void) +{ + static grub_uint32_t high = 0; + static grub_uint32_t last = 0; + grub_uint32_t low; + + asm volatile ("mfc0 %0, " GRUB_CPU_MIPS_COP0_TIMER_COUNT : "=r" (low)); + if (low < last) + high++; + last = low; + + return (((grub_uint64_t) high) << 32) | low; +} void -grub_machine_set_prefix (void) +grub_machine_get_bootlocation (char **device __attribute__ ((unused)), + char **path __attribute__ ((unused))) { - grub_env_set ("prefix", grub_prefix); -} - -extern char _end[]; - -grub_addr_t -grub_arch_modules_addr (void) -{ - return (grub_addr_t) _end; } diff --git a/grub-core/kern/mips/yeeloong/init.c b/grub-core/kern/mips/loongson/init.c similarity index 77% rename from grub-core/kern/mips/yeeloong/init.c rename to grub-core/kern/mips/loongson/init.c index cc7c16806..3b282e1e0 100644 --- a/grub-core/kern/mips/yeeloong/init.c +++ b/grub-core/kern/mips/loongson/init.c @@ -30,9 +30,12 @@ #include #include #include -#include +#include +#include extern void grub_video_sm712_init (void); +extern void grub_video_sis315pro_init (void); +extern void grub_video_radeon_fuloong2e_init (void); extern void grub_video_init (void); extern void grub_bitmap_init (void); extern void grub_font_init (void); @@ -41,22 +44,7 @@ extern void grub_at_keyboard_init (void); extern void grub_serial_init (void); extern void grub_terminfo_init (void); extern void grub_keylayouts_init (void); - -/* FIXME: use interrupt to count high. */ -grub_uint64_t -grub_get_rtc (void) -{ - static grub_uint32_t high = 0; - static grub_uint32_t last = 0; - grub_uint32_t low; - - asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_TIMER_COUNT : "=r" (low)); - if (low < last) - high++; - last = low; - - return (((grub_uint64_t) high) << 32) | low; -} +extern void grub_boot_init (void); grub_err_t grub_machine_mmap_iterate (grub_memory_hook_t hook) @@ -78,7 +66,7 @@ init_pci (void) /* FIXME: autoscan for BARs and devices. */ switch (pciid) { - case GRUB_YEELOONG_OHCI_PCIID: + case GRUB_LOONGSON_OHCI_PCIID: addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); grub_pci_write (addr, 0x5025000); addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); @@ -90,7 +78,7 @@ init_pci (void) addr = grub_pci_make_address (dev, GRUB_PCI_REG_STATUS); grub_pci_write_word (addr, 0x0200 | GRUB_PCI_STATUS_CAPABILITIES); break; - case GRUB_YEELOONG_EHCI_PCIID: + case GRUB_LOONGSON_EHCI_PCIID: addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); grub_pci_write (addr, 0x5026000); addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); @@ -136,6 +124,23 @@ void grub_machine_init (void) { grub_addr_t modend; + grub_uint32_t prid; + + asm volatile ("mfc0 %0, " GRUB_CPU_LOONGSON_COP0_PRID : "=r" (prid)); + + switch (prid) + { + /* Loongson 2E. */ + case 0x6302: + grub_arch_machine = GRUB_ARCH_MACHINE_FULOONG2E; + break; + /* Loongson 2F. */ + case 0x6303: + if (grub_arch_machine != GRUB_ARCH_MACHINE_FULOONG2F + && grub_arch_machine != GRUB_ARCH_MACHINE_YEELOONG) + grub_arch_machine = GRUB_ARCH_MACHINE_YEELOONG; + break; + } /* FIXME: measure this. */ if (grub_arch_busclock == 0) @@ -162,7 +167,7 @@ grub_machine_init (void) if (err) grub_fatal ("Couldn't init SMBus: %s\n", grub_errmsg); - /* Yeeloong has only one memory slot. */ + /* Yeeloong and Fuloong have only one memory slot. */ err = grub_cs5536_read_spd (smbbase, GRUB_SMB_RAM_START_ADDR, &spd); if (err) grub_fatal ("Couldn't read SPD: %s\n", grub_errmsg); @@ -183,7 +188,7 @@ grub_machine_init (void) } else { - grub_arch_memsize = (totalmem >> 20); + grub_arch_memsize = totalmem; grub_arch_highmemsize = 0; } @@ -201,15 +206,20 @@ grub_machine_init (void) relies on a working heap. */ grub_video_init (); grub_video_sm712_init (); + grub_video_sis315pro_init (); + grub_video_radeon_fuloong2e_init (); grub_bitmap_init (); grub_font_init (); grub_gfxterm_init (); grub_keylayouts_init (); - grub_at_keyboard_init (); + if (grub_arch_machine == GRUB_ARCH_MACHINE_YEELOONG) + grub_at_keyboard_init (); grub_terminfo_init (); grub_serial_init (); + + grub_boot_init (); } void @@ -220,10 +230,32 @@ grub_machine_fini (void) void grub_halt (void) { - grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG) - & ~GRUB_CPU_LOONGSON_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG); + switch (grub_arch_machine) + { + case GRUB_ARCH_MACHINE_FULOONG2E: + break; + case GRUB_ARCH_MACHINE_FULOONG2F: + { + grub_pci_device_t dev; + grub_port_t p; + if (grub_cs5536_find (&dev)) + { + p = (grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_GPIO_BAR) + & GRUB_CS5536_LBAR_ADDR_MASK) + GRUB_MACHINE_PCI_IO_BASE; + grub_outl ((1 << 13), p + 4); + grub_outl ((1 << 29), p); + grub_millisleep (5000); + } + } + break; + case GRUB_ARCH_MACHINE_YEELOONG: + grub_outb (grub_inb (GRUB_CPU_LOONGSON_GPIOCFG) + & ~GRUB_CPU_YEELOONG_SHUTDOWN_GPIO, GRUB_CPU_LOONGSON_GPIOCFG); + grub_millisleep (1500); + break; + } - grub_printf ("Shutdown failed\n"); + grub_puts_ (N_("Shutdown failed")); grub_refresh (); while (1); } @@ -234,13 +266,6 @@ grub_exit (void) grub_halt (); } -void -grub_reboot (void) -{ - grub_write_ec (GRUB_MACHINE_EC_COMMAND_REBOOT); - - grub_printf ("Reboot failed\n"); - grub_refresh (); - while (1); -} +extern char _end[]; +grub_addr_t grub_modbase = (grub_addr_t) _end; diff --git a/grub-core/kern/mips/qemu-mips/init.c b/grub-core/kern/mips/qemu-mips/init.c deleted file mode 100644 index f2bb652a8..000000000 --- a/grub-core/kern/mips/qemu-mips/init.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RAMSIZE (*(grub_uint32_t *) ((16 << 20) - 264)) - -grub_uint32_t -grub_get_rtc (void) -{ - static int calln = 0; - return calln++; -} - -void -grub_machine_init (void) -{ - grub_mm_init_region ((void *) GRUB_MACHINE_MEMORY_USABLE, - RAMSIZE - (GRUB_MACHINE_MEMORY_USABLE & 0x7fffffff)); - grub_install_get_time_ms (grub_rtc_get_time_ms); -} - -void -grub_machine_fini (void) -{ -} - -void -grub_exit (void) -{ - while (1); -} - -void -grub_halt (void) -{ - while (1); -} - -void -grub_reboot (void) -{ - while (1); -} - -grub_err_t -grub_machine_mmap_iterate (grub_memory_hook_t hook) -{ - hook (0, RAMSIZE, GRUB_MEMORY_AVAILABLE); - return GRUB_ERR_NONE; -} diff --git a/grub-core/kern/mips/qemu_mips/init.c b/grub-core/kern/mips/qemu_mips/init.c new file mode 100644 index 000000000..120b450f5 --- /dev/null +++ b/grub-core/kern/mips/qemu_mips/init.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void grub_serial_init (void); +extern void grub_terminfo_init (void); +extern void grub_at_keyboard_init (void); +extern void grub_video_init (void); +extern void grub_bitmap_init (void); +extern void grub_font_init (void); +extern void grub_gfxterm_init (void); +extern void grub_keylayouts_init (void); +extern void grub_boot_init (void); +extern void grub_vga_text_init (void); + +static inline int +probe_mem (grub_addr_t addr) +{ + volatile grub_uint8_t *ptr = (grub_uint8_t *) (0xa0000000 | addr); + grub_uint8_t c = *ptr; + *ptr = 0xAA; + if (*ptr != 0xAA) + return 0; + *ptr = 0x55; + if (*ptr != 0x55) + return 0; + *ptr = c; + return 1; +} + +void +grub_machine_init (void) +{ + grub_addr_t modend; + + if (grub_arch_memsize == 0) + { + int i; + + for (i = 27; i >= 0; i--) + if (probe_mem (grub_arch_memsize | (1 << i))) + grub_arch_memsize |= (1 << i); + grub_arch_memsize++; + } + + /* FIXME: measure this. */ + grub_arch_cpuclock = 64000000; + + modend = grub_modules_get_end (); + grub_mm_init_region ((void *) modend, grub_arch_memsize + - (modend - GRUB_ARCH_LOWMEMVSTART)); + + grub_install_get_time_ms (grub_rtc_get_time_ms); + + grub_video_init (); + grub_bitmap_init (); + grub_font_init (); + + grub_keylayouts_init (); + grub_at_keyboard_init (); + + grub_qemu_init_cirrus (); + grub_vga_text_init (); + + grub_terminfo_init (); + grub_serial_init (); + + grub_boot_init (); + + grub_gfxterm_init (); +} + +void +grub_machine_fini (void) +{ +} + +void +grub_exit (void) +{ + while (1); +} + +void +grub_halt (void) +{ + while (1); +} + +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook) +{ + hook (0, grub_arch_memsize, GRUB_MEMORY_AVAILABLE); + return GRUB_ERR_NONE; +} + +extern char _end[]; +grub_addr_t grub_modbase = (grub_addr_t) _end; + diff --git a/grub-core/kern/mips/startup.S b/grub-core/kern/mips/startup.S index ae0e0b187..2476038bc 100644 --- a/grub-core/kern/mips/startup.S +++ b/grub-core/kern/mips/startup.S @@ -20,6 +20,7 @@ #include #include #include +#include #include #define BASE_ADDR 8 @@ -35,22 +36,10 @@ start: bal cont nop - . = _start + GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE -total_module_size: + . = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE +VARIABLE(grub_total_modules_size) .long 0 - . = _start + GRUB_KERNEL_MACHINE_PREFIX - -VARIABLE(grub_prefix) - - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END -#ifdef GRUB_MACHINE_MIPS_YEELOONG VARIABLE (grub_arch_busclock) .long 0 VARIABLE (grub_arch_cpuclock) @@ -59,21 +48,32 @@ VARIABLE (grub_arch_memsize) .long 0 VARIABLE (grub_arch_highmemsize) .long 0 +#ifdef GRUB_MACHINE_MIPS_LOONGSON +VARIABLE (grub_arch_machine) + .long GRUB_ARCH_MACHINE_FULOONG2F #endif cont: /* Save our base. */ move $s0, $ra -#ifdef GRUB_MACHINE_MIPS_YEELOONG +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + lui $t1, %hi(grub_arch_busclock) + addiu $t1, %lo(grub_arch_busclock) + sw $s4, 8($t1) +#endif + +#ifdef GRUB_MACHINE_MIPS_LOONGSON lui $t1, %hi(grub_arch_busclock) addiu $t1, %lo(grub_arch_busclock) sw $s2, 0($t1) sw $s3, 4($t1) sw $s4, 8($t1) sw $s5, 12($t1) + sw $s7, 16($t1) #endif /* Move the modules out of BSS. */ +#ifndef GRUB_MACHINE_ARC lui $t2, %hi(__bss_start) addiu $t2, %lo(__bss_start) @@ -103,6 +103,7 @@ modulesmovcont: b modulesmovcont addiu $t3, $t3, -1 modulesmovdone: +#endif /* Clean BSS. */ diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c index 37ce8decd..0d2ae4bd6 100644 --- a/grub-core/kern/misc.c +++ b/grub-core/kern/misc.c @@ -210,11 +210,14 @@ grub_vprintf (const char *fmt, va_list args) buf[PREALLOC_SIZE - 2] = '.'; buf[PREALLOC_SIZE - 1] = '.'; buf[PREALLOC_SIZE] = 0; + curbuf = buf; } else s = grub_vsnprintf_real (curbuf, s, fmt, ap2); } + va_end (ap2); + grub_xputs (curbuf); if (curbuf != buf) @@ -311,52 +314,6 @@ grub_strrchr (const char *s, int c) return p; } -/* Copied from gnulib. - Written by Bruno Haible , 2005. */ -char * -grub_strstr (const char *haystack, const char *needle) -{ - /* Be careful not to look at the entire extent of haystack or needle - until needed. This is useful because of these two cases: - - haystack may be very long, and a match of needle found early, - - needle may be very long, and not even a short initial segment of - needle may be found in haystack. */ - if (*needle != '\0') - { - /* Speed up the following searches of needle by caching its first - character. */ - char b = *needle++; - - for (;; haystack++) - { - if (*haystack == '\0') - /* No match. */ - return NULL; - if (*haystack == b) - /* The first character matches. */ - { - const char *rhaystack = haystack + 1; - const char *rneedle = needle; - - for (;; rhaystack++, rneedle++) - { - if (*rneedle == '\0') - /* Found a match. */ - return (char *) haystack; - if (*rhaystack == '\0') - /* No match. */ - return NULL; - if (*rhaystack != *rneedle) - /* Nothing in this round. */ - break; - } - } - } - } - else - return (char *) haystack; -} - int grub_strword (const char *haystack, const char *needle) { @@ -597,23 +554,23 @@ grub_reverse (char *str) /* Divide N by D, return the quotient, and store the remainder in *R. */ grub_uint64_t -grub_divmod64 (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r) +grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) { /* This algorithm is typically implemented by hardware. The idea is to get the highest bit in N, 64 times, by keeping - upper(N * 2^i) = upper((Q * 10 + M) * 2^i), where upper + upper(N * 2^i) = (Q * D + M), where upper represents the high 64 bits in 128-bits space. */ unsigned bits = 64; - unsigned long long q = 0; - unsigned m = 0; + grub_uint64_t q = 0; + grub_uint64_t m = 0; /* Skip the slow computation if 32-bit arithmetic is possible. */ - if (n < 0xffffffff) + if (n < 0xffffffff && d < 0xffffffff) { if (r) - *r = ((grub_uint32_t) n) % d; + *r = ((grub_uint32_t) n) % (grub_uint32_t) d; - return ((grub_uint32_t) n) / d; + return ((grub_uint32_t) n) / (grub_uint32_t) d; } while (bits--) @@ -666,7 +623,7 @@ grub_lltoa (char *str, int c, unsigned long long n) /* BASE == 10 */ do { - unsigned m; + grub_uint64_t m; n = grub_divmod64 (n, 10, &m); *p++ = m + '0'; @@ -680,10 +637,13 @@ grub_lltoa (char *str, int c, unsigned long long n) } static int -grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list args) +grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, va_list args_in) { char c; + grub_size_t n = 0; grub_size_t count = 0; + grub_size_t count_args = 0; + const char *fmt; auto void write_char (unsigned char ch); auto void write_str (const char *s); auto void write_fill (const char ch, int n); @@ -702,209 +662,368 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt, va_list ar write_char (*s++); } - void write_fill (const char ch, int n) + void write_fill (const char ch, int count_fill) { int i; - for (i = 0; i < n; i++) + for (i = 0; i < count_fill; i++) write_char (ch); } + fmt = fmt0; while ((c = *fmt++) != 0) { if (c != '%') - write_char (c); - else + continue; + + if (*fmt && *fmt =='-') + fmt++; + + while (*fmt && grub_isdigit (*fmt)) + fmt++; + + if (*fmt && *fmt == '$') + fmt++; + + if (*fmt && *fmt =='-') + fmt++; + + while (*fmt && grub_isdigit (*fmt)) + fmt++; + + if (*fmt && *fmt =='.') + fmt++; + + while (*fmt && grub_isdigit (*fmt)) + fmt++; + + c = *fmt++; + if (c == 'l') { - char tmp[32]; - char *p; - unsigned int format1 = 0; - unsigned int format2 = ~ 0U; - char zerofill = ' '; - int rightfill = 0; - int n; - int longfmt = 0; - int longlongfmt = 0; - int unsig = 0; + c = *fmt++; + if (c == 'l') + c = *fmt++; + } + switch (c) + { + case 'p': + case 'x': + case 'u': + case 'd': + case 'c': + case 'C': + case 's': + count_args++; + break; + } + } - if (*fmt && *fmt =='-') + enum { INT, WCHAR, LONG, LONGLONG, POINTER } types[count_args]; + union + { + int i; + grub_uint32_t w; + long l; + long long ll; + void *p; + } args[count_args]; + + grub_memset (types, 0, sizeof (types)); + + fmt = fmt0; + n = 0; + while ((c = *fmt++) != 0) + { + int longfmt = 0; + int longlongfmt = 0; + grub_size_t curn; + const char *p; + + if (c != '%') + continue; + + curn = n++; + + if (*fmt && *fmt =='-') + fmt++; + + while (*fmt && grub_isdigit (*fmt)) + fmt++; + + if (*fmt && *fmt =='.') + fmt++; + + while (*fmt && grub_isdigit (*fmt)) + fmt++; + + p = fmt; + + if (*fmt && *fmt == '$') + { + curn = grub_strtoull (p, 0, 10) - 1; + fmt++; + } + + while (*fmt && grub_isdigit (*fmt)) + fmt++; + + c = *fmt++; + if (c == 'l') + { + c = *fmt++; + longfmt = 1; + if (c == 'l') { - rightfill = 1; - fmt++; + c = *fmt++; + longlongfmt = 1; } + } + if (curn >= count_args) + continue; + switch (c) + { + case 'x': + case 'u': + case 'd': + if (longlongfmt) + types[curn] = LONGLONG; + else if (longfmt) + types[curn] = LONG; + else + types[curn] = INT; + break; + case 'p': + case 's': + types[curn] = POINTER; + break; + case 'c': + types[curn] = INT; + break; + case 'C': + types[curn] = WCHAR; + break; + } + } - p = (char *) fmt; - /* Read formatting parameters. */ + for (n = 0; n < count_args; n++) + switch (types[n]) + { + case WCHAR: + args[n].w = va_arg (args_in, grub_uint32_t); + break; + case POINTER: + args[n].p = va_arg (args_in, void *); + break; + case INT: + args[n].i = va_arg (args_in, int); + break; + case LONG: + args[n].l = va_arg (args_in, long); + break; + case LONGLONG: + args[n].ll = va_arg (args_in, long long); + break; + } + + fmt = fmt0; + + n = 0; + while ((c = *fmt++) != 0) + { + char tmp[32]; + char *p; + unsigned int format1 = 0; + unsigned int format2 = ~ 0U; + char zerofill = ' '; + int rightfill = 0; + int longfmt = 0; + int longlongfmt = 0; + int unsig = 0; + grub_size_t curn; + + if (c != '%') + { + write_char (c); + continue; + } + + curn = n++; + + rescan:; + + if (*fmt && *fmt =='-') + { + rightfill = 1; + fmt++; + } + + p = (char *) fmt; + /* Read formatting parameters. */ + while (*p && grub_isdigit (*p)) + p++; + + if (p > fmt) + { + char s[p - fmt + 1]; + grub_strncpy (s, fmt, p - fmt); + s[p - fmt] = 0; + if (s[0] == '0') + zerofill = '0'; + format1 = grub_strtoul (s, 0, 10); + fmt = p; + } + + if (*p && *p == '.') + { + p++; + fmt++; while (*p && grub_isdigit (*p)) p++; if (p > fmt) { - char s[p - fmt + 1]; - grub_strncpy (s, fmt, p - fmt); - s[p - fmt] = 0; - if (s[0] == '0') - zerofill = '0'; - format1 = grub_strtoul (s, 0, 10); + char fstr[p - fmt + 1]; + grub_strncpy (fstr, fmt, p - fmt); + fstr[p - fmt] = 0; + format2 = grub_strtoul (fstr, 0, 10); fmt = p; } + } + if (*fmt == '$') + { + curn = format1 - 1; + fmt++; + format1 = 0; + format2 = ~ 0U; + zerofill = ' '; + rightfill = 0; - if (*p && *p == '.') - { - p++; - fmt++; - while (*p && grub_isdigit (*p)) - p++; - - if (p > fmt) - { - char fstr[p - fmt + 1]; - grub_strncpy (fstr, fmt, p - fmt); - fstr[p - fmt] = 0; - format2 = grub_strtoul (fstr, 0, 10); - fmt = p; - } - } + goto rescan; + } + c = *fmt++; + if (c == 'l') + { + longfmt = 1; c = *fmt++; if (c == 'l') { - longfmt = 1; + longlongfmt = 1; c = *fmt++; - if (c == 'l') - { - longlongfmt = 1; - c = *fmt++; - } } + } - switch (c) - { - case 'p': - write_str ("0x"); - c = 'x'; - longlongfmt |= (sizeof (void *) == sizeof (long long)); - /* Fall through. */ - case 'x': - case 'u': - unsig = 1; - /* Fall through. */ - case 'd': - if (longlongfmt) - { - long long ll; + if (curn >= count_args) + continue; - ll = va_arg (args, long long); - grub_lltoa (tmp, c, ll); - } - else if (longfmt && unsig) - { - unsigned long l = va_arg (args, unsigned long); - grub_lltoa (tmp, c, l); - } - else if (longfmt) - { - long l = va_arg (args, long); - grub_lltoa (tmp, c, l); - } - else if (unsig) - { - unsigned u = va_arg (args, unsigned); - grub_lltoa (tmp, c, u); - } - else - { - n = va_arg (args, int); - grub_lltoa (tmp, c, n); - } - if (! rightfill && grub_strlen (tmp) < format1) - write_fill (zerofill, format1 - grub_strlen (tmp)); - write_str (tmp); - if (rightfill && grub_strlen (tmp) < format1) - write_fill (zerofill, format1 - grub_strlen (tmp)); - break; + switch (c) + { + case 'p': + write_str ("0x"); + c = 'x'; + longlongfmt |= (sizeof (void *) == sizeof (long long)); + /* Fall through. */ + case 'x': + case 'u': + unsig = 1; + /* Fall through. */ + case 'd': + if (longlongfmt) + grub_lltoa (tmp, c, args[curn].ll); + else if (longfmt && unsig) + grub_lltoa (tmp, c, (unsigned long) args[curn].l); + else if (longfmt) + grub_lltoa (tmp, c, args[curn].l); + else if (unsig) + grub_lltoa (tmp, c, (unsigned) args[curn].i); + else + grub_lltoa (tmp, c, args[curn].i); + if (! rightfill && grub_strlen (tmp) < format1) + write_fill (zerofill, format1 - grub_strlen (tmp)); + write_str (tmp); + if (rightfill && grub_strlen (tmp) < format1) + write_fill (zerofill, format1 - grub_strlen (tmp)); + break; - case 'c': - n = va_arg (args, int); - write_char (n & 0xff); - break; + case 'c': + write_char (args[curn].i & 0xff); + break; - case 'C': + case 'C': + { + grub_uint32_t code = args[curn].w; + int shift; + unsigned mask; + + if (code <= 0x7f) { - grub_uint32_t code = va_arg (args, grub_uint32_t); - int shift; - unsigned mask; - - if (code <= 0x7f) - { - shift = 0; - mask = 0; - } - else if (code <= 0x7ff) - { - shift = 6; - mask = 0xc0; - } - else if (code <= 0xffff) - { - shift = 12; - mask = 0xe0; - } - else if (code <= 0x1fffff) - { - shift = 18; - mask = 0xf0; - } - else if (code <= 0x3ffffff) - { - shift = 24; - mask = 0xf8; - } - else if (code <= 0x7fffffff) - { - shift = 30; - mask = 0xfc; - } - else - { - code = '?'; - shift = 0; - mask = 0; - } - - write_char (mask | (code >> shift)); - - for (shift -= 6; shift >= 0; shift -= 6) - write_char (0x80 | (0x3f & (code >> shift))); + shift = 0; + mask = 0; + } + else if (code <= 0x7ff) + { + shift = 6; + mask = 0xc0; + } + else if (code <= 0xffff) + { + shift = 12; + mask = 0xe0; + } + else if (code <= 0x1fffff) + { + shift = 18; + mask = 0xf0; + } + else if (code <= 0x3ffffff) + { + shift = 24; + mask = 0xf8; + } + else if (code <= 0x7fffffff) + { + shift = 30; + mask = 0xfc; + } + else + { + code = '?'; + shift = 0; + mask = 0; } - break; - case 's': - p = va_arg (args, char *); - if (p) - { - grub_size_t len = 0; - while (len < format2 && p[len]) - len++; + write_char (mask | (code >> shift)); - if (!rightfill && len < format1) - write_fill (zerofill, format1 - len); + for (shift -= 6; shift >= 0; shift -= 6) + write_char (0x80 | (0x3f & (code >> shift))); + } + break; - grub_size_t i; - for (i = 0; i < len; i++) - write_char (*p++); + case 's': + p = args[curn].p; + if (p) + { + grub_size_t len = 0; + while (len < format2 && p[len]) + len++; - if (rightfill && len < format1) - write_fill (zerofill, format1 - len); - } - else - write_str ("(null)"); + if (!rightfill && len < format1) + write_fill (zerofill, format1 - len); - break; + grub_size_t i; + for (i = 0; i < len; i++) + write_char (*p++); - default: - write_char (c); - break; + if (rightfill && len < format1) + write_fill (zerofill, format1 - len); } + else + write_str ("(null)"); + + break; + + default: + write_char (c); + break; } } @@ -956,6 +1075,9 @@ grub_xvasprintf (const char *fmt, va_list ap) return NULL; s = grub_vsnprintf_real (ret, as, fmt, ap2); + + va_end (ap2); + if (s <= as) return ret; diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 8d9b5db78..ee4d58d81 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -311,11 +311,13 @@ grub_memalign (grub_size_t align, grub_size_t size) count++; goto again; +#if 0 case 1: /* Unload unneeded modules. */ grub_dl_unload_unneeded (); count++; goto again; +#endif default: break; @@ -513,7 +515,7 @@ grub_debug_malloc (const char *file, int line, grub_size_t size) void *ptr; if (grub_mm_debug) - grub_printf ("%s:%d: malloc (0x%zx) = ", file, line, size); + grub_printf ("%s:%d: malloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size); ptr = grub_malloc (size); if (grub_mm_debug) grub_printf ("%p\n", ptr); @@ -526,7 +528,7 @@ grub_debug_zalloc (const char *file, int line, grub_size_t size) void *ptr; if (grub_mm_debug) - grub_printf ("%s:%d: zalloc (0x%zx) = ", file, line, size); + grub_printf ("%s:%d: zalloc (0x%" PRIxGRUB_SIZE ") = ", file, line, size); ptr = grub_zalloc (size); if (grub_mm_debug) grub_printf ("%p\n", ptr); @@ -545,7 +547,7 @@ void * grub_debug_realloc (const char *file, int line, void *ptr, grub_size_t size) { if (grub_mm_debug) - grub_printf ("%s:%d: realloc (%p, 0x%zx) = ", file, line, ptr, size); + grub_printf ("%s:%d: realloc (%p, 0x%" PRIxGRUB_SIZE ") = ", file, line, ptr, size); ptr = grub_realloc (ptr, size); if (grub_mm_debug) grub_printf ("%p\n", ptr); @@ -559,8 +561,8 @@ grub_debug_memalign (const char *file, int line, grub_size_t align, void *ptr; if (grub_mm_debug) - grub_printf ("%s:%d: memalign (0x%zx, 0x%zx) = ", - file, line, align, size); + grub_printf ("%s:%d: memalign (0x%" PRIxGRUB_SIZE ", 0x%" PRIxGRUB_SIZE + ") = ", file, line, align, size); ptr = grub_memalign (align, size); if (grub_mm_debug) grub_printf ("%p\n", ptr); diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c index 6370a7b3a..5b449586c 100644 --- a/grub-core/kern/parser.c +++ b/grub-core/kern/parser.c @@ -123,7 +123,7 @@ grub_parser_split_cmdline (const char *cmdline, grub_reader_getline_t getline, void add_var (grub_parser_state_t newstate) { - char *val; + const char *val; /* Check if a variable was being read in and the end of the name was reached. */ diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c index a2f5dd722..a083f5cbb 100644 --- a/grub-core/kern/partition.c +++ b/grub-core/kern/partition.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include @@ -47,7 +48,7 @@ grub_partition_check_containment (const grub_disk_t disk, grub_dprintf ("partition", "sub-partition %s%d of (%s,%s) ends after parent.\n", part->partmap->name, part->number + 1, disk->name, partname); #ifdef GRUB_UTIL - grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", + grub_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"), disk->name, partname, part->partmap->name, part->number + 1); #endif grub_free (partname); @@ -222,32 +223,23 @@ grub_partition_iterate (struct grub_disk *disk, char * grub_partition_get_name (const grub_partition_t partition) { - char *out = 0; - int curlen = 0; + char *out = 0, *ptr; + grub_size_t needlen = 0; grub_partition_t part; + for (part = partition; part; part = part->parent) + /* Even on 64-bit machines this buffer is enough to hold + longest number. */ + needlen += grub_strlen (part->partmap->name) + 27; + out = grub_malloc (needlen); + if (!out) + return NULL; + + ptr = out; for (part = partition; part; part = part->parent) { - /* Even on 64-bit machines this buffer is enough to hold - longest number. */ - char buf[grub_strlen (part->partmap->name) + 25]; - int strl; - grub_snprintf (buf, sizeof (buf), "%s%d", part->partmap->name, + grub_snprintf (ptr, needlen - (out - ptr), "%s%d", part->partmap->name, part->number + 1); - strl = grub_strlen (buf); - if (curlen) - { - out = grub_realloc (out, curlen + strl + 2); - grub_memcpy (out + strl + 1, out, curlen); - out[curlen + 1 + strl] = 0; - grub_memcpy (out, buf, strl); - out[strl] = ','; - curlen = curlen + 1 + strl; - } - else - { - curlen = strl; - out = grub_strdup (buf); - } + ptr += grub_strlen (ptr); } return out; } diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c index ad19e5600..064bbc61f 100644 --- a/grub-core/kern/powerpc/dl.c +++ b/grub-core/kern/powerpc/dl.c @@ -37,6 +37,62 @@ grub_arch_dl_check_header (void *ehdr) return GRUB_ERR_NONE; } +void +grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got) +{ + const Elf_Ehdr *e = ehdr; + const Elf_Shdr *s; + unsigned i; + + *tramp = 0; + *got = 0; + + /* Find a symbol table. */ + for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + + if (i == e->e_shnum) + return; + + for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize)) + if (s->sh_type == SHT_RELA) + { + const Elf_Rela *rel, *max; + + for (rel = (const Elf_Rela *) ((const char *) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel++) + if (ELF_R_TYPE (rel->r_info) == R_PPC_REL24) + (*tramp)++; + + } + + return; +} + +/* For low-endian reverse lis and addr_high as well as ori and addr_low. */ +struct trampoline +{ + grub_uint32_t lis; + grub_uint32_t ori; + grub_uint32_t mtctr; + grub_uint32_t bctr; +}; + +static const struct trampoline trampoline_template = + { + 0x3c000000, + 0x60000000, + 0x7c0903a6, + 0x4e800420, + }; /* Relocate symbols. */ grub_err_t @@ -46,6 +102,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) Elf_Shdr *s; Elf_Word entsize; unsigned i; + struct trampoline *tptr = mod->tramp; /* Find a symbol table. */ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); @@ -106,7 +163,20 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) Elf_Sword delta = value - (Elf_Word) addr; if (delta << 6 >> 6 != delta) - return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow"); + { + COMPILE_TIME_ASSERT (sizeof (struct trampoline) + == GRUB_ARCH_DL_TRAMP_SIZE); + grub_memcpy (tptr, &trampoline_template, + sizeof (*tptr)); + delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr; + tptr->lis |= (((value) >> 16) & 0xffff); + tptr->ori |= ((value) & 0xffff); + tptr++; + } + + if (delta << 6 >> 6 != delta) + return grub_error (GRUB_ERR_BAD_MODULE, + "relocation overflow"); *addr = (*addr & 0xfc000003) | (delta & 0x3fffffc); break; } diff --git a/grub-core/kern/powerpc/ieee1275/startup.S b/grub-core/kern/powerpc/ieee1275/startup.S index 0b1c23346..b26c47edb 100644 --- a/grub-core/kern/powerpc/ieee1275/startup.S +++ b/grub-core/kern/powerpc/ieee1275/startup.S @@ -28,20 +28,6 @@ .globl start, _start start: _start: - b codestart - - . = _start + GRUB_KERNEL_MACHINE_PREFIX - -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END - -codestart: li 2, 0 li 13, 0 diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c index a81008579..4587b944f 100644 --- a/grub-core/kern/rescue_reader.c +++ b/grub-core/kern/rescue_reader.c @@ -74,7 +74,7 @@ grub_rescue_read_line (char **line, int cont) return 0; } -void +void __attribute__ ((noreturn)) grub_rescue_run (void) { grub_printf ("Entering rescue mode...\n"); diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c index 7b6266cac..e1be5d9ec 100644 --- a/grub-core/kern/sparc64/dl.c +++ b/grub-core/kern/sparc64/dl.c @@ -111,10 +111,13 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (((grub_int32_t) ((value - (Elf_Addr) addr) >> 2)) & 0x3FFFFFFF); break; + case R_SPARC_HH22: /* 9 V-imm22 */ + *addr = (*addr & 0xFFC00000) | ((value >> 42) & 0x3FFFFF); + break; + case R_SPARC_HM10: /* 12 T-simm13 */ + *addr = (*addr & 0xFFFFFC00) | ((value >> 32) & 0x3FF); + break; case R_SPARC_HI22: /* 9 V-imm22 */ - if (((grub_int32_t) value) & 0xFF00000000) - return grub_error (GRUB_ERR_BAD_MODULE, - "high address out of 22 bits range"); *addr = (*addr & 0xFFC00000) | ((value >> 10) & 0x3FFFFF); break; case R_SPARC_LO10: /* 12 T-simm13 */ diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S index cebdca2b6..9d91fba48 100644 --- a/grub-core/kern/sparc64/ieee1275/crt0.S +++ b/grub-core/kern/sparc64/ieee1275/crt0.S @@ -31,18 +31,6 @@ _start: VARIABLE(grub_total_module_size) .word 0 -VARIABLE(grub_kernel_image_size) - .word 0 -VARIABLE(grub_compressed_size) - .word 0 -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = EXT_C(_start) + GRUB_KERNEL_MACHINE_PREFIX_END codestart: /* Copy the modules past the end of the kernel image. diff --git a/grub-core/kern/sparc64/ieee1275/init.c b/grub-core/kern/sparc64/ieee1275/init.c deleted file mode 100644 index 72ee1f136..000000000 --- a/grub-core/kern/sparc64/ieee1275/init.c +++ /dev/null @@ -1,174 +0,0 @@ -/* init.c -- Initialize GRUB on SPARC64. */ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -grub_addr_t grub_ieee1275_original_stack; - -void -grub_exit (void) -{ - grub_ieee1275_exit (); -} - -static grub_uint64_t -ieee1275_get_time_ms (void) -{ - grub_uint32_t msecs = 0; - - grub_ieee1275_milliseconds (&msecs); - - return msecs; -} - -grub_uint32_t -grub_get_rtc (void) -{ - return ieee1275_get_time_ms (); -} - -grub_addr_t -grub_arch_modules_addr (void) -{ - extern char _end[]; - return (grub_addr_t) _end; -} - -void -grub_machine_set_prefix (void) -{ - if (grub_prefix[0] != '(') - { - char bootpath[IEEE1275_MAX_PATH_LEN]; - char *prefix, *path, *colon; - grub_ssize_t actual; - - if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", - &bootpath, sizeof (bootpath), &actual)) - { - /* Should never happen. */ - grub_printf ("/chosen/bootpath property missing!\n"); - grub_env_set ("prefix", ""); - return; - } - - /* Transform an OF device path to a GRUB path. */ - colon = grub_strchr (bootpath, ':'); - if (colon) - { - char *part = colon + 1; - - /* Consistently provide numbered partitions to GRUB. - OpenBOOT traditionally uses alphabetical partition - specifiers. */ - if (part[0] >= 'a' && part[0] <= 'z') - part[0] = '1' + (part[0] - 'a'); - } - prefix = grub_ieee1275_encode_devname (bootpath); - - path = grub_xasprintf("%s%s", prefix, grub_prefix); - - grub_strcpy (grub_prefix, path); - - grub_free (path); - grub_free (prefix); - } - - grub_env_set ("prefix", grub_prefix); -} - -static void -grub_heap_init (void) -{ - grub_mm_init_region ((void *) (grub_modules_get_end () - + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); -} - -static void -grub_parse_cmdline (void) -{ - grub_ssize_t actual; - char args[256]; - - if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args, - sizeof args, &actual) == 0 - && actual > 1) - { - int i = 0; - - while (i < actual) - { - char *command = &args[i]; - char *end; - char *val; - - end = grub_strchr (command, ';'); - if (end == 0) - i = actual; /* No more commands after this one. */ - else - { - *end = '\0'; - i += end - command + 1; - while (grub_isspace(args[i])) - i++; - } - - /* Process command. */ - val = grub_strchr (command, '='); - if (val) - { - *val = '\0'; - grub_env_set (command, val + 1); - } - } - } -} - -void -grub_machine_init (void) -{ - grub_ieee1275_init (); - grub_console_init_early (); - grub_heap_init (); - grub_console_init_lately (); - - grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0); - grub_ofdisk_init (); - - grub_parse_cmdline (); - grub_install_get_time_ms (ieee1275_get_time_ms); -} - -void -grub_machine_fini (void) -{ - grub_ofdisk_fini (); - grub_console_fini (); -} diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c index 7b3593161..d7c65dd82 100644 --- a/grub-core/kern/term.c +++ b/grub-core/kern/term.c @@ -29,6 +29,7 @@ struct grub_term_output *grub_term_outputs; struct grub_term_input *grub_term_inputs; void (*grub_term_poll_usb) (void) = NULL; +void (*grub_net_poll_cards_idle) (void) = NULL; /* Put a Unicode character. */ static void @@ -91,6 +92,9 @@ grub_checkkey (void) if (grub_term_poll_usb) grub_term_poll_usb (); + if (grub_net_poll_cards_idle) + grub_net_poll_cards_idle (); + FOR_ACTIVE_TERM_INPUTS(term) { pending_key = term->getkey (term); diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/vga_init.c similarity index 90% rename from grub-core/kern/i386/qemu/init.c rename to grub-core/kern/vga_init.c index 054dfa86b..889d0128e 100644 --- a/grub-core/kern/i386/qemu/init.c +++ b/grub-core/kern/vga_init.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2010 Free Software Foundation, Inc. + * Copyright (C) 2010,2011 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 +16,9 @@ * along with GRUB. If not, see . */ +#ifndef __mips__ #include +#endif #include #include #include @@ -43,7 +45,17 @@ static struct {grub_uint8_t r, g, b, a; } colors[] = {0xFE, 0xFE, 0xFE, 0xFF} // 15 = white }; +#ifdef __mips__ +extern unsigned char ascii_bitmaps[]; +#else #include +#endif + +#ifdef __mips__ +#define VGA_ADDR 0xb00a0000 +#else +#define VGA_ADDR 0xa0000 +#endif static void load_font (void) @@ -61,7 +73,7 @@ load_font (void) grub_vga_gr_write (0xff, GRUB_VGA_GR_BITMASK); for (i = 0; i < 128; i++) - grub_memcpy ((void *) (0xa0000 + 32 * i), ascii_bitmaps + 16 * i, 16); + grub_memcpy ((void *) (VGA_ADDR + 32 * i), ascii_bitmaps + 16 * i, 16); } static void @@ -78,6 +90,7 @@ load_palette (void) void grub_qemu_init_cirrus (void) { +#ifndef __mips__ auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid); int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))) { @@ -106,8 +119,10 @@ grub_qemu_init_cirrus (void) } grub_pci_iterate (find_card); +#endif - grub_outb (GRUB_VGA_IO_MISC_COLOR, GRUB_VGA_IO_MISC_WRITE); + grub_outb (GRUB_VGA_IO_MISC_COLOR, + GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_MISC_WRITE); load_font (); @@ -143,5 +158,5 @@ grub_qemu_init_cirrus (void) grub_vga_cr_write (14, GRUB_VGA_CR_CURSOR_START); grub_vga_cr_write (15, GRUB_VGA_CR_CURSOR_END); - grub_outb (0x20, 0x3c0); + grub_outb (0x20, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); } diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c index 090ad78b8..9b63b30f8 100644 --- a/grub-core/kern/x86_64/dl.c +++ b/grub-core/kern/x86_64/dl.c @@ -109,7 +109,9 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) break; default: - grub_fatal ("Unrecognized relocation: %d\n", ELF_R_TYPE (rel->r_info)); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "this relocation (%d) is not implemented yet", + ELF_R_TYPE (rel->r_info)); } } } diff --git a/grub-core/kern/x86_64/efi/callwrap.S b/grub-core/kern/x86_64/efi/callwrap.S index 1946732ae..2df95dda1 100644 --- a/grub-core/kern/x86_64/efi/callwrap.S +++ b/grub-core/kern/x86_64/efi/callwrap.S @@ -19,14 +19,13 @@ #include #include -#include /* * x86_64 uses registry to pass parameters. Unfortunately, gcc and efi use * different call conversion, so we need to do some conversion. * * gcc: - * %rdi, %esi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ... + * %rdi, %rsi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ... * * efi: * %rcx, %rdx, %r8, %r9, 32(%rsp), 40(%rsp), 48(%rsp), ... @@ -37,80 +36,94 @@ .text FUNCTION(efi_wrap_0) - subq $40, %rsp + subq $48, %rsp call *%rdi - addq $40, %rsp + addq $48, %rsp ret FUNCTION(efi_wrap_1) - subq $40, %rsp + subq $48, %rsp mov %rsi, %rcx call *%rdi - addq $40, %rsp + addq $48, %rsp ret FUNCTION(efi_wrap_2) - subq $40, %rsp + subq $48, %rsp mov %rsi, %rcx call *%rdi - addq $40, %rsp + addq $48, %rsp ret FUNCTION(efi_wrap_3) - subq $40, %rsp + subq $48, %rsp mov %rcx, %r8 mov %rsi, %rcx call *%rdi - addq $40, %rsp + addq $48, %rsp ret FUNCTION(efi_wrap_4) - subq $40, %rsp + subq $48, %rsp mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx call *%rdi - addq $40, %rsp + addq $48, %rsp ret FUNCTION(efi_wrap_5) - subq $40, %rsp + subq $48, %rsp mov %r9, 32(%rsp) mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx call *%rdi - addq $40, %rsp + addq $48, %rsp ret FUNCTION(efi_wrap_6) - subq $56, %rsp - mov 56+8(%rsp), %rax + subq $64, %rsp + mov 64+8(%rsp), %rax mov %rax, 40(%rsp) mov %r9, 32(%rsp) mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx call *%rdi - addq $56, %rsp + addq $64, %rsp + ret + +FUNCTION(efi_wrap_7) + subq $96, %rsp + mov 96+16(%rsp), %rax + mov %rax, 48(%rsp) + mov 96+8(%rsp), %rax + mov %rax, 40(%rsp) + mov %r9, 32(%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $96, %rsp ret FUNCTION(efi_wrap_10) - subq $88, %rsp - mov 88+40(%rsp), %rax + subq $96, %rsp + mov 96+40(%rsp), %rax mov %rax, 72(%rsp) - mov 88+32(%rsp), %rax + mov 96+32(%rsp), %rax mov %rax, 64(%rsp) - mov 88+24(%rsp), %rax + mov 96+24(%rsp), %rax mov %rax, 56(%rsp) - mov 88+16(%rsp), %rax + mov 96+16(%rsp), %rax mov %rax, 48(%rsp) - mov 88+8(%rsp), %rax + mov 96+8(%rsp), %rax mov %rax, 40(%rsp) mov %r9, 32(%rsp) mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx call *%rdi - addq $88, %rsp + addq $96, %rsp ret diff --git a/grub-core/kern/x86_64/efi/startup.S b/grub-core/kern/x86_64/efi/startup.S index fb4fc7b64..f86f01969 100644 --- a/grub-core/kern/x86_64/efi/startup.S +++ b/grub-core/kern/x86_64/efi/startup.S @@ -19,7 +19,6 @@ #include #include -#include .file "startup.S" .text @@ -28,33 +27,6 @@ start: _start: - jmp codestart - - /* - * Compatibility version number - * - * These MUST be at byte offset 6 and 7 of the executable - * DO NOT MOVE !!! - */ - . = _start + 0x6 - .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR - - /* - * This is a special data area 8 bytes from the beginning. - */ - - . = _start + 0x8 - -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + 0x50 - -codestart: movq %rcx, EXT_C(grub_efi_image_handle)(%rip) movq %rdx, EXT_C(grub_efi_system_table)(%rip) diff --git a/grub-core/lib/LzmaEnc.c b/grub-core/lib/LzmaEnc.c index 01ffa91f9..258ed9c91 100644 --- a/grub-core/lib/LzmaEnc.c +++ b/grub-core/lib/LzmaEnc.c @@ -1994,13 +1994,15 @@ static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 beforeSize = kNumOpts; +#ifdef COMPRESS_MF_MT Bool btMode; +#endif if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; +#ifdef COMPRESS_MF_MT btMode = (p->matchFinderBase.btMode != 0); - #ifdef COMPRESS_MF_MT p->mtMode = (p->multiThread && !p->fastMode && btMode); - #endif +#endif { unsigned lclp = p->lc + p->lp; diff --git a/grub-core/lib/adler32.c b/grub-core/lib/adler32.c new file mode 100644 index 000000000..2a2464db3 --- /dev/null +++ b/grub-core/lib/adler32.c @@ -0,0 +1,153 @@ +/* adler32.c - adler32 check. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Based on adler32() from adler32.c of zlib-1.2.5 library. */ + +#define BASE 65521UL +#define NMAX 5552 + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +static grub_uint32_t +update_adler32 (grub_uint32_t adler, const grub_uint8_t *buf, grub_size_t len) +{ + unsigned long sum2; + unsigned int n; + + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + if (len == 1) + { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + if (len < 16) + { + while (len--) + { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + sum2 %= BASE; + return adler | (sum2 << 16); + } + + while (len >= NMAX) + { + len -= NMAX; + n = NMAX / 16; + do + { + DO16 (buf); + buf += 16; + } + while (--n); + adler %= BASE; + sum2 %= BASE; + } + + if (len) + { + while (len >= 16) + { + len -= 16; + DO16 (buf); + buf += 16; + } + while (len--) + { + adler += *buf++; + sum2 += adler; + } + adler %= BASE; + sum2 %= BASE; + } + + return adler | (sum2 << 16); +} + +typedef struct +{ + grub_uint32_t adler; +} +adler32_context; + +static void +adler32_init (void *context) +{ + adler32_context *ctx = (adler32_context *) context; + ctx->adler = 1; +} + +static void +adler32_write (void *context, const void *inbuf, grub_size_t inlen) +{ + adler32_context *ctx = (adler32_context *) context; + if (!inbuf) + return; + ctx->adler = update_adler32 (ctx->adler, inbuf, inlen); +} + +static grub_uint8_t * +adler32_read (void *context) +{ + adler32_context *ctx = (adler32_context *) context; + return (grub_uint8_t *) &ctx->adler; +} + +static void +adler32_final (void *context __attribute__ ((unused))) +{ +} + +gcry_md_spec_t _gcry_digest_spec_adler32 = { + "ADLER32",0 , 0, 0 , 4, + adler32_init, adler32_write, adler32_final, adler32_read, + sizeof (adler32_context), + .blocksize = 64 +}; + +GRUB_MOD_INIT(adler32) +{ + grub_md_register (&_gcry_digest_spec_adler32); +} + +GRUB_MOD_FINI(adler32) +{ + grub_md_unregister (&_gcry_digest_spec_adler32); +} diff --git a/grub-core/lib/arc/datetime.c b/grub-core/lib/arc/datetime.c new file mode 100644 index 000000000..b8d910e5f --- /dev/null +++ b/grub-core/lib/arc/datetime.c @@ -0,0 +1,48 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +grub_err_t +grub_get_datetime (struct grub_datetime *datetime) +{ + struct grub_arc_timeinfo *dt; + grub_memset (datetime, 0, sizeof (*datetime)); + + dt = GRUB_ARC_FIRMWARE_VECTOR->gettime (); + + datetime->year = dt->y; + datetime->month = dt->m; + datetime->day = dt->d; + datetime->hour = dt->h; + datetime->minute = dt->min; + datetime->second = dt->s; + + return 0; +} + +grub_err_t +grub_set_datetime (struct grub_datetime *datetime __attribute__ ((unused))) +{ + return grub_error (GRUB_ERR_IO, "setting time isn't supported"); +} diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c index 1c765f12a..e6e88c461 100644 --- a/grub-core/lib/arg.c +++ b/grub-core/lib/arg.c @@ -25,14 +25,11 @@ #include /* Built-in parser for default options. */ -#define SHORT_ARG_HELP -100 -#define SHORT_ARG_USAGE -101 - static const struct grub_arg_option help_options[] = { - {"help", SHORT_ARG_HELP, 0, + {"help", 0, 0, N_("Display this help and exit."), 0, ARG_TYPE_NONE}, - {"usage", SHORT_ARG_USAGE, 0, + {"usage", 0, 0, N_("Display the usage of this command and exit."), 0, ARG_TYPE_NONE}, {0, 0, 0, 0, 0, 0} }; @@ -125,9 +122,9 @@ grub_arg_show_help (grub_extcmd_t cmd) if (opt->shortarg && grub_isgraph (opt->shortarg)) grub_printf ("-%c%c ", opt->shortarg, opt->longarg ? ',':' '); - else if (opt->shortarg == SHORT_ARG_HELP && ! h_is_used) + else if (opt == help_options && ! h_is_used) grub_printf ("-h, "); - else if (opt->shortarg == SHORT_ARG_USAGE && ! u_is_used) + else if (opt == help_options + 1 && ! u_is_used) grub_printf ("-u, "); else grub_printf (" "); @@ -180,50 +177,34 @@ grub_arg_show_help (grub_extcmd_t cmd) static int -parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr) +parse_option (grub_extcmd_t cmd, const struct grub_arg_option *opt, + char *arg, struct grub_arg_list *usr) { - switch (key) + if (opt == help_options) { - case SHORT_ARG_HELP: grub_arg_show_help (cmd); return -1; + } - case SHORT_ARG_USAGE: + if (opt == help_options + 1) + { show_usage (cmd); return -1; - - default: - { - int found = -1; - int i = 0; - const struct grub_arg_option *opt = cmd->options; - - while (opt->doc) - { - if (opt->shortarg && key == opt->shortarg) - { - found = i; - break; - } - opt++; - i++; - } - - if (found == -1) - return -1; - - 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; - } - } } + { + int found = opt - cmd->options; + + 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; + } + } return 0; } @@ -307,7 +288,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, it can have an argument value. */ if (*curshort) { - if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno) + if (parse_option (cmd, opt, 0, usr) || grub_errno) goto fail; } else @@ -340,17 +321,20 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, } option = grub_strchr (arg, '='); - if (option) { - arglen = option - arg - 2; - option++; - } else { + if (option) + { + arglen = option - arg - 2; + option++; + } + 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 (!option && argv[curarg + 1] && argv[curarg + 1][0] != '-' + && opt && opt->type != ARG_TYPE_NONE) + option = argv[++curarg]; + if (!opt && (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH)) { if (add_arg (arg) != 0) @@ -408,7 +392,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, /* XXX: Not implemented. */ break; } - if (parse_option (cmd, opt->shortarg, option, usr) || grub_errno) + if (parse_option (cmd, opt, option, usr) || grub_errno) goto fail; } else @@ -421,7 +405,7 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, goto fail; } - if (parse_option (cmd, opt->shortarg, 0, usr) || grub_errno) + if (parse_option (cmd, opt, 0, usr) || grub_errno) goto fail; } } diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c new file mode 100644 index 000000000..a702e6487 --- /dev/null +++ b/grub-core/lib/cmdline.c @@ -0,0 +1,105 @@ +/* cmdline.c - linux command line handling */ +/* + * 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 + +static unsigned int check_arg (char *c, int *has_space) +{ + int space = 0; + unsigned int size = 0; + + while (*c) + { + if (*c == '\\' || *c == '\'' || *c == '"') + size++; + else if (*c == ' ') + space = 1; + + size++; + c++; + } + + if (space) + size += 2; + + if (has_space) + *has_space = space; + + return size; +} + +unsigned int grub_loader_cmdline_size (int argc, char *argv[]) +{ + int i; + unsigned int size = 0; + + for (i = 0; i < argc; i++) + { + size += check_arg (argv[i], 0); + size++; /* Separator space or NULL. */ + } + + return size; +} + +int grub_create_loader_cmdline (int argc, char *argv[], char *buf, + grub_size_t size) +{ + int i, space; + unsigned int arg_size; + char *c; + + for (i = 0; i < argc; i++) + { + c = argv[i]; + arg_size = check_arg(argv[i], &space); + arg_size++; /* Separator space or NULL. */ + + if (size < arg_size) + break; + + size -= arg_size; + + if (space) + *buf++ = '"'; + + while (*c) + { + if (*c == '\\' || *c == '\'' || *c == '"') + *buf++ = '\\'; + + *buf++ = *c; + c++; + } + + if (space) + *buf++ = '"'; + + *buf++ = ' '; + } + + /* Replace last space with null. */ + if (i) + buf--; + + *buf = 0; + + return i; +} diff --git a/grub-core/lib/cmos_datetime.c b/grub-core/lib/cmos_datetime.c index 8db60b48c..86cd91180 100644 --- a/grub-core/lib/cmos_datetime.c +++ b/grub-core/lib/cmos_datetime.c @@ -19,31 +19,48 @@ #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#if !defined (__powerpc__) && !defined (__sparc__) +#define grub_get_datetime_cmos grub_get_datetime +#define grub_set_datetime_cmos grub_set_datetime +#endif grub_err_t -grub_get_datetime (struct grub_datetime *datetime) +grub_get_datetime_cmos (struct grub_datetime *datetime) { int is_bcd, is_12hour; grub_uint8_t value, flag; + grub_err_t err; - flag = grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B); + err = grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B, &flag); + if (err) + return err; is_bcd = ! (flag & GRUB_CMOS_STATUS_B_BINARY); - value = grub_cmos_read (GRUB_CMOS_INDEX_YEAR); + err = grub_cmos_read (GRUB_CMOS_INDEX_YEAR, &value); + if (err) + return err; if (is_bcd) value = grub_bcd_to_num (value); datetime->year = value; datetime->year += (value < 80) ? 2000 : 1900; - value = grub_cmos_read (GRUB_CMOS_INDEX_MONTH); + err = grub_cmos_read (GRUB_CMOS_INDEX_MONTH, &value); + if (err) + return err; if (is_bcd) value = grub_bcd_to_num (value); datetime->month = value; - value = grub_cmos_read (GRUB_CMOS_INDEX_DAY_OF_MONTH); + err = grub_cmos_read (GRUB_CMOS_INDEX_DAY_OF_MONTH, &value); + if (err) + return err; if (is_bcd) value = grub_bcd_to_num (value); @@ -51,7 +68,9 @@ grub_get_datetime (struct grub_datetime *datetime) is_12hour = ! (flag & GRUB_CMOS_STATUS_B_24HOUR); - value = grub_cmos_read (GRUB_CMOS_INDEX_HOUR); + err = grub_cmos_read (GRUB_CMOS_INDEX_HOUR, &value); + if (err) + return err; if (is_12hour) { is_12hour = (value & 0x80); @@ -68,13 +87,18 @@ grub_get_datetime (struct grub_datetime *datetime) datetime->hour = value; - value = grub_cmos_read (GRUB_CMOS_INDEX_MINUTE); + err = grub_cmos_read (GRUB_CMOS_INDEX_MINUTE, &value); + if (err) + return err; + if (is_bcd) value = grub_bcd_to_num (value); datetime->minute = value; - value = grub_cmos_read (GRUB_CMOS_INDEX_SECOND); + err = grub_cmos_read (GRUB_CMOS_INDEX_SECOND, &value); + if (err) + return err; if (is_bcd) value = grub_bcd_to_num (value); @@ -84,12 +108,15 @@ grub_get_datetime (struct grub_datetime *datetime) } grub_err_t -grub_set_datetime (struct grub_datetime *datetime) +grub_set_datetime_cmos (struct grub_datetime *datetime) { int is_bcd, is_12hour; grub_uint8_t value, flag; + grub_err_t err; - flag = grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B); + err = grub_cmos_read (GRUB_CMOS_INDEX_STATUS_B, &flag); + if (err) + return err; is_bcd = ! (flag & GRUB_CMOS_STATUS_B_BINARY); @@ -99,21 +126,27 @@ grub_set_datetime (struct grub_datetime *datetime) if (is_bcd) value = grub_num_to_bcd (value); - grub_cmos_write (GRUB_CMOS_INDEX_YEAR, value); + err = grub_cmos_write (GRUB_CMOS_INDEX_YEAR, value); + if (err) + return err; value = datetime->month; if (is_bcd) value = grub_num_to_bcd (value); - grub_cmos_write (GRUB_CMOS_INDEX_MONTH, value); + err = grub_cmos_write (GRUB_CMOS_INDEX_MONTH, value); + if (err) + return err; value = datetime->day; if (is_bcd) value = grub_num_to_bcd (value); - grub_cmos_write (GRUB_CMOS_INDEX_DAY_OF_MONTH, value); + err = grub_cmos_write (GRUB_CMOS_INDEX_DAY_OF_MONTH, value); + if (err) + return err; value = datetime->hour; @@ -135,21 +168,27 @@ grub_set_datetime (struct grub_datetime *datetime) if (is_12hour) value |= 0x80; - grub_cmos_write (GRUB_CMOS_INDEX_HOUR, value); + err = grub_cmos_write (GRUB_CMOS_INDEX_HOUR, value); + if (err) + return err; value = datetime->minute; if (is_bcd) value = grub_num_to_bcd (value); - grub_cmos_write (GRUB_CMOS_INDEX_MINUTE, value); + err = grub_cmos_write (GRUB_CMOS_INDEX_MINUTE, value); + if (err) + return err; value = datetime->second; if (is_bcd) value = grub_num_to_bcd (value); - grub_cmos_write (GRUB_CMOS_INDEX_SECOND, value); + err = grub_cmos_write (GRUB_CMOS_INDEX_SECOND, value); + if (err) + return err; return 0; } diff --git a/grub-core/lib/crc.c b/grub-core/lib/crc.c new file mode 100644 index 000000000..ffc3ef3b5 --- /dev/null +++ b/grub-core/lib/crc.c @@ -0,0 +1,75 @@ +/* crc.c - crc function */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +static grub_uint32_t crc32c_table [256]; + +static void +init_crc32c_table (void) +{ + auto grub_uint32_t reflect (grub_uint32_t ref, int len); + grub_uint32_t reflect (grub_uint32_t ref, int len) + { + grub_uint32_t result = 0; + int i; + + for (i = 1; i <= len; i++) + { + if (ref & 1) + result |= 1 << (len - i); + ref >>= 1; + } + + return result; + } + + grub_uint32_t polynomial = 0x1edc6f41; + int i, j; + + for(i = 0; i < 256; i++) + { + crc32c_table[i] = reflect(i, 8) << 24; + for (j = 0; j < 8; j++) + crc32c_table[i] = (crc32c_table[i] << 1) ^ + (crc32c_table[i] & (1 << 31) ? polynomial : 0); + crc32c_table[i] = reflect(crc32c_table[i], 32); + } +} + +grub_uint32_t +grub_getcrc32c (grub_uint32_t crc, const void *buf, int size) +{ + int i; + const grub_uint8_t *data = buf; + + if (! crc32c_table[1]) + init_crc32c_table (); + + crc^= 0xffffffff; + + for (i = 0; i < size; i++) + { + crc = (crc >> 8) ^ crc32c_table[(crc & 0xFF) ^ *data]; + data++; + } + + return crc ^ 0xffffffff; +} diff --git a/grub-core/lib/crc64.c b/grub-core/lib/crc64.c new file mode 100644 index 000000000..4b1c92cf0 --- /dev/null +++ b/grub-core/lib/crc64.c @@ -0,0 +1,113 @@ +/* crc64.c - crc64 function */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_uint64_t crc64_table [256]; + +static void +init_crc64_table (void) +{ + auto grub_uint64_t reflect (grub_uint64_t ref, int len); + grub_uint64_t reflect (grub_uint64_t ref, int len) + { + grub_uint64_t result = 0; + int i; + + for (i = 1; i <= len; i++) + { + if (ref & 1) + result |= 1ULL << (len - i); + ref >>= 1; + } + + return result; + } + + grub_uint64_t polynomial = 0x42f0e1eba9ea3693ULL; + int i, j; + + for(i = 0; i < 256; i++) + { + crc64_table[i] = reflect(i, 8) << 56; + for (j = 0; j < 8; j++) + { + crc64_table[i] = (crc64_table[i] << 1) ^ + (crc64_table[i] & (1ULL << 63) ? polynomial : 0); + } + crc64_table[i] = reflect(crc64_table[i], 64); + } +} + +static void +crc64_init (void *context) +{ + if (! crc64_table[1]) + init_crc64_table (); + *(grub_uint64_t *) context = 0; +} + +static void +crc64_write (void *context, const void *buf, grub_size_t size) +{ + unsigned i; + const grub_uint8_t *data = buf; + grub_uint64_t crc = ~grub_le_to_cpu64 (*(grub_uint64_t *) context); + + for (i = 0; i < size; i++) + { + crc = (crc >> 8) ^ crc64_table[(crc & 0xFF) ^ *data]; + data++; + } + + *(grub_uint64_t *) context = grub_cpu_to_le64 (~crc); +} + +static grub_uint8_t * +crc64_read (void *context) +{ + return context; +} + +static void +crc64_final (void *context __attribute__ ((unused))) +{ +} + +gcry_md_spec_t _gcry_digest_spec_crc64 = + { + "CRC64", 0, 0, 0, 8, + crc64_init, crc64_write, crc64_final, crc64_read, + sizeof (grub_uint64_t), + .blocksize = 64 + }; + +GRUB_MOD_INIT(crc64) +{ + grub_md_register (&_gcry_digest_spec_crc64); +} + +GRUB_MOD_FINI(crc64) +{ + grub_md_unregister (&_gcry_digest_spec_crc64); +} diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c index f5768b8b5..48d860335 100644 --- a/grub-core/lib/crypto.c +++ b/grub-core/lib/crypto.c @@ -21,6 +21,16 @@ #include #include #include +#include + +#ifdef GRUB_UTIL +#include +#include +#include +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); struct grub_crypto_hmac_handle { @@ -159,33 +169,12 @@ grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, return cipher->cipher->setkey (cipher->ctx, key, keylen); } - -void -grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) -{ - grub_free (cipher); -} - - -void -grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) -{ - const grub_uint8_t *in1ptr = in1, *in2ptr = in2; - grub_uint8_t *outptr = out; - while (size--) - { - *outptr = *in1ptr ^ *in2ptr; - in1ptr++; - in2ptr++; - outptr++; - } -} - gcry_err_code_t grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size) + void *out, const void *in, grub_size_t size) { - grub_uint8_t *inptr, *outptr, *end; + const grub_uint8_t *inptr; + grub_uint8_t *outptr, *end; if (!cipher->cipher->decrypt) return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) @@ -199,9 +188,10 @@ grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, gcry_err_code_t grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size) + void *out, const void *in, grub_size_t size) { - grub_uint8_t *inptr, *outptr, *end; + const grub_uint8_t *inptr; + grub_uint8_t *outptr, *end; if (!cipher->cipher->encrypt) return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) @@ -239,10 +229,11 @@ grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, gcry_err_code_t grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size, + void *out, const void *in, grub_size_t size, void *iv) { - grub_uint8_t *inptr, *outptr, *end; + const grub_uint8_t *inptr; + grub_uint8_t *outptr, *end; grub_uint8_t ivt[cipher->cipher->blocksize]; if (!cipher->cipher->decrypt) return GPG_ERR_NOT_SUPPORTED; @@ -333,7 +324,8 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md, } void -grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, + const void *data, grub_size_t datalen) { hnd->md->write (hnd->ctx, data, datalen); @@ -375,7 +367,7 @@ grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out) gcry_err_code_t grub_crypto_hmac_buffer (const struct gcry_md_spec *md, const void *key, grub_size_t keylen, - void *data, grub_size_t datalen, void *out) + const void *data, grub_size_t datalen, void *out) { struct grub_crypto_hmac_handle *hnd; @@ -411,10 +403,43 @@ grub_crypto_memcmp (const void *a, const void *b, grub_size_t n) return !!counter; } -#ifndef GRUB_MKPASSWD int grub_password_get (char buf[], unsigned buf_size) { +#ifdef GRUB_UTIL + FILE *in; + struct termios s, t; + int tty_changed = 0; + char *ptr; + + /* Disable echoing. Based on glibc. */ + in = fopen ("/dev/tty", "w+c"); + if (in == NULL) + in = stdin; + + if (tcgetattr (fileno (in), &t) == 0) + { + /* Save the old one. */ + s = t; + /* Tricky, tricky. */ + t.c_lflag &= ~(ECHO|ISIG); + tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0); + } + else + tty_changed = 0; + fgets (buf, buf_size, stdin); + ptr = buf + strlen (buf) - 1; + while (buf <= ptr && (*ptr == '\n' || *ptr == '\r')) + *ptr-- = 0; + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + + grub_xputs ("\n"); + grub_refresh (); + + return 1; +#else unsigned cur_len = 0; int key; @@ -449,5 +474,5 @@ grub_password_get (char buf[], unsigned buf_size) grub_refresh (); return (key != '\e'); -} #endif +} diff --git a/grub-core/lib/efi/datetime.c b/grub-core/lib/efi/datetime.c index 0a91c345a..0fd1b5fbd 100644 --- a/grub-core/lib/efi/datetime.c +++ b/grub-core/lib/efi/datetime.c @@ -22,6 +22,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); grub_err_t grub_get_datetime (struct grub_datetime *datetime) diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c index c19536897..5ebf2cd1d 100644 --- a/grub-core/lib/efi/halt.c +++ b/grub-core/lib/efi/halt.c @@ -28,7 +28,9 @@ void grub_halt (void) { grub_machine_fini (); +#ifndef __ia64__ grub_acpi_halt (); +#endif efi_call_4 (grub_efi_system_table->runtime_services->reset_system, GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); diff --git a/include/grub/i386/pc/loader.h b/grub-core/lib/efi/reboot.c similarity index 64% rename from include/grub/i386/pc/loader.h rename to grub-core/lib/efi/reboot.c index bfbcaac5a..9382370f7 100644 --- a/include/grub/i386/pc/loader.h +++ b/grub-core/lib/efi/reboot.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2007 Free Software Foundation, Inc. + * Copyright (C) 2011 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,12 +16,17 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 +#include +#include +#include +#include +#include -#include - -/* This is an asm part of the chainloader. */ -void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); - -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +void +grub_reboot (void) +{ + grub_machine_fini (); + efi_call_4 (grub_efi_system_table->runtime_services->reset_system, + GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); + for (;;) ; +} diff --git a/grub-core/lib/efi/relocator.c b/grub-core/lib/efi/relocator.c index fc4de834b..0d346bea3 100644 --- a/grub-core/lib/efi/relocator.c +++ b/grub-core/lib/efi/relocator.c @@ -62,13 +62,25 @@ grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) (char *) desc < ((char *) descs + mmapsize); desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { + grub_uint64_t start = desc->physical_start; + grub_uint64_t end = desc->physical_start + (desc->num_pages << 12); + + /* post-4G addresses are never supported on 32-bit EFI. + Moreover it has been reported that some 64-bit EFI contrary to the + spec don't map post-4G pages. So if you enable post-4G allocations, + map pages manually or check that they are mapped. + */ + if (end >= 0x100000000ULL) + end = 0x100000000ULL; + if (end <= start) + continue; if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) continue; events[counter].type = REG_FIRMWARE_START; - events[counter].pos = desc->physical_start; + events[counter].pos = start; counter++; events[counter].type = REG_FIRMWARE_END; - events[counter].pos = desc->physical_start + (desc->num_pages << 12); + events[counter].pos = end; counter++; } @@ -85,6 +97,9 @@ grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size) if (grub_efi_is_finished) return 1; + grub_dprintf ("relocator", "EFI alloc: %llx, %llx\n", + (unsigned long long) start, (unsigned long long) size); + 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); diff --git a/grub-core/lib/i386/halt.c b/grub-core/lib/i386/halt.c index 15c4ba0d6..bd878c9bf 100644 --- a/grub-core/lib/i386/halt.c +++ b/grub-core/lib/i386/halt.c @@ -19,6 +19,7 @@ #include #include #include +#include const char bochs_shutdown[] = "Shutdown"; @@ -52,7 +53,7 @@ grub_halt (void) for (i = 0; i < sizeof (bochs_shutdown) - 1; i++) grub_outb (bochs_shutdown[i], 0x8900); - grub_printf ("GRUB doesn't know how to halt this machine yet!\n"); + grub_puts_ (N_("GRUB doesn't know how to halt this machine yet!")); /* 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 ... */ diff --git a/grub-core/lib/i386/pc/biosnum.c b/grub-core/lib/i386/pc/biosnum.c index 058c9d331..0f0e743c4 100644 --- a/grub-core/lib/i386/pc/biosnum.c +++ b/grub-core/lib/i386/pc/biosnum.c @@ -19,11 +19,12 @@ #include #include #include +#include static int grub_get_root_biosnumber_default (void) { - char *biosnum; + const char *biosnum; int ret = -1; grub_device_t dev; diff --git a/grub-core/lib/i386/reboot.c b/grub-core/lib/i386/reboot.c new file mode 100644 index 000000000..45a2259cf --- /dev/null +++ b/grub-core/lib/i386/reboot.c @@ -0,0 +1,60 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +void +grub_reboot (void) +{ + struct grub_relocator *relocator = NULL; + grub_relocator_chunk_t ch; + grub_err_t err; + void *buf; + struct grub_relocator16_state state; + grub_uint16_t segment; + + relocator = grub_relocator_new (); + if (!relocator) + while (1); + err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000, 0x1000, + grub_reboot_end - grub_reboot_start, + 16, GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + while (1); + buf = get_virtual_current_address (ch); + grub_memcpy (buf, grub_reboot_start, grub_reboot_end - grub_reboot_start); + + segment = ((grub_addr_t) get_physical_target_address (ch)) >> 4; + state.gs = state.fs = state.es = state.ds = state.ss = segment; + state.sp = 0; + state.cs = segment; + state.ip = 0; + state.a20 = 0; + + grub_stop_floppy (); + + err = grub_relocator16_boot (relocator, state); + + while (1); +} + diff --git a/include/grub/i386/pc/vga.h b/grub-core/lib/i386/reboot_trampoline.S similarity index 69% rename from include/grub/i386/pc/vga.h rename to grub-core/lib/i386/reboot_trampoline.S index ecc169022..c088cd081 100644 --- a/include/grub/i386/pc/vga.h +++ b/grub-core/lib/i386/reboot_trampoline.S @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2011 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,19 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_VGA_MACHINE_HEADER -#define GRUB_VGA_MACHINE_HEADER 1 - #include -#include +#include -/* The VGA (at the beginning of upper memory). */ -#define GRUB_MEMORY_MACHINE_VGA_ADDR GRUB_MEMORY_MACHINE_UPPER + .p2align 4 -#endif /* ! GRUB_VGA_MACHINE_HEADER */ +VARIABLE(grub_reboot_start) + .code16 + + /* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */ + movw $0x0472, %di + xorw %ax, %ax + movw %ax, (%di) + ljmp $0xf000, $0xfff0 + + .code32 +VARIABLE(grub_reboot_end) diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c index 1bc4240c3..1f0aa0dd1 100644 --- a/grub-core/lib/i386/relocator.c +++ b/grub-core/lib/i386/relocator.c @@ -50,6 +50,10 @@ 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_relocator16_ebx; +extern grub_uint32_t grub_relocator16_esi; + +extern grub_uint16_t grub_relocator16_keep_a20_enabled; extern grub_uint8_t grub_relocator32_start; extern grub_uint8_t grub_relocator32_end; @@ -194,7 +198,8 @@ grub_relocator16_boot (struct grub_relocator *rel, void *relst; grub_relocator_chunk_t ch; - err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + /* Put it higher than the byte it checks for A20 check. */ + err = grub_relocator_alloc_chunk_align (rel, &ch, 0x8010, 0xa0000 - RELOCATOR_SIZEOF (16), RELOCATOR_SIZEOF (16), 16, GRUB_RELOCATOR_PREFERENCE_NONE); @@ -212,7 +217,11 @@ grub_relocator16_boot (struct grub_relocator *rel, grub_relocator16_ss = state.ss; grub_relocator16_sp = state.sp; + grub_relocator16_ebx = state.ebx; grub_relocator16_edx = state.edx; + grub_relocator16_esi = state.esi; + + grub_relocator16_keep_a20_enabled = state.a20; grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start, RELOCATOR_SIZEOF (16)); diff --git a/grub-core/lib/i386/relocator16.S b/grub-core/lib/i386/relocator16.S index c3768f4eb..babe69e1d 100644 --- a/grub-core/lib/i386/relocator16.S +++ b/grub-core/lib/i386/relocator16.S @@ -93,6 +93,85 @@ LOCAL(segment): .word 0 LOCAL(cont3): + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_keep_a20_enabled) + .word 0 + test %ax, %ax + jnz LOCAL(gate_a20_done) + + /* first of all, test if already in a good state */ + call LOCAL(gate_a20_check_state) + testb %al, %al + jz LOCAL(gate_a20_done) + + /* second, try a BIOS call */ + movw $0x2400, %ax + int $0x15 + + call LOCAL(gate_a20_check_state) + testb %al, %al + jz LOCAL(gate_a20_done) + + /* + * In macbook, the keyboard test would hang the machine, so we move + * this forward. + */ + /* fourth, try the system control port A */ + inb $0x92 + andb $(~0x03), %al + outb $0x92 + + /* When turning off Gate A20, do not check the state strictly, + because a failure is not fatal usually, and Gate A20 is always + on some modern machines. */ + jmp LOCAL(gate_a20_done) + +LOCAL(gate_a20_check_state): + /* iterate the checking for a while */ + movw $100, %cx +1: + call 3f + testb %al, %al + jz 2f + loop 1b +2: + ret + +3: + xorw %ax, %ax + movw %ax, %ds + decw %ax + movw %ax, %es + xorw %ax, %ax + + movw $0x8000, %ax + /* compare the byte at ADDR with that at 0x100000 + ADDR */ + movw %ax, %si + addw $0x10, %ax + movw %ax, %di + + /* save the original byte in DL */ + movb %ds:(%si), %dl + movb %es:(%di), %al + /* try to set one less value at ADDR */ + movb %al, %dh + decb %dh + movb %dh, %ds:(%si) + /* serialize */ + outb %al, $0x80 + outb %al, $0x80 + /* obtain the value at 0x100000 + ADDR in CH */ + movb %es:(%di), %dh + /* this result is 1 if A20 is on or 0 if it is off */ + subb %dh, %al + xorb $1, %al + /* restore the original */ + movb %dl, %es:(%di) + ret + +LOCAL(gate_a20_done): /* we are in real mode now * set up the real mode segment registers : DS, SS, ES */ @@ -130,13 +209,24 @@ VARIABLE(grub_relocator16_ss) .byte 0xb8 VARIABLE(grub_relocator16_sp) .word 0 - movw %ax, %ss + movzwl %ax, %esp + + /* movw imm32, %eax. */ + .byte 0x66, 0xb8 +VARIABLE(grub_relocator16_esi) + .long 0 + movl %eax, %esi /* movw imm32, %edx. */ .byte 0x66, 0xba VARIABLE(grub_relocator16_edx) .long 0 - + + /* movw imm32, %ebx. */ + .byte 0x66, 0xbb +VARIABLE(grub_relocator16_ebx) + .long 0 + /* Cleared direction flag is of no problem with any current payload and makes this implementation easier. */ cld diff --git a/grub-core/lib/i386/setjmp.S b/grub-core/lib/i386/setjmp.S index a2002ae3d..5b7aa158b 100644 --- a/grub-core/lib/i386/setjmp.S +++ b/grub-core/lib/i386/setjmp.S @@ -17,9 +17,12 @@ */ #include +#include .file "setjmp.S" +GRUB_MOD_LICENSE ("GPLv3+") + .text /* diff --git a/grub-core/lib/ia64/longjmp.S b/grub-core/lib/ia64/longjmp.S new file mode 100644 index 000000000..729bdc76e --- /dev/null +++ b/grub-core/lib/ia64/longjmp.S @@ -0,0 +1,162 @@ +/* Copyright (C) 1999, 2000, 2001, 2002, 2008 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + Note that __sigsetjmp() did NOT flush the register stack. Instead, + we do it here since __longjmp() is usually much less frequently + invoked than __sigsetjmp(). The only difficulty is that __sigsetjmp() + didn't (and wouldn't be able to) save ar.rnat either. This is a problem + because if we're not careful, we could end up loading random NaT bits. + There are two cases: + + (i) ar.bsp < ia64_rse_rnat_addr(jmpbuf.ar_bsp) + ar.rnat contains the desired bits---preserve ar.rnat + across loadrs and write to ar.bspstore + + (ii) ar.bsp >= ia64_rse_rnat_addr(jmpbuf.ar_bsp) + The desired ar.rnat is stored in + ia64_rse_rnat_addr(jmpbuf.ar_bsp). Load those + bits into ar.rnat after setting ar.bspstore. */ + + + +# define pPos p6 /* is rotate count positive? */ +# define pNeg p7 /* is rotate count negative? */ + + + /* __longjmp(__jmp_buf buf, int val) */ + + .text + .global longjmp + .proc longjmp +longjmp: + alloc r8=ar.pfs,2,1,0,0 + mov r27=ar.rsc + add r2=0x98,in0 // r2 <- &jmpbuf.orig_jmp_buf_addr + ;; + ld8 r8=[r2],-16 // r8 <- orig_jmp_buf_addr + mov r10=ar.bsp + and r11=~0x3,r27 // clear ar.rsc.mode + ;; + flushrs // flush dirty regs to backing store (must be first in insn grp) + ld8 r23=[r2],8 // r23 <- jmpbuf.ar_bsp + sub r8=r8,in0 // r8 <- &orig_jmpbuf - &jmpbuf + ;; + ld8 r25=[r2] // r25 <- jmpbuf.ar_unat + extr.u r8=r8,3,6 // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f + ;; + cmp.lt pNeg,pPos=r8,r0 + mov r2=in0 + ;; +(pPos) mov r16=r8 +(pNeg) add r16=64,r8 +(pPos) sub r17=64,r8 +(pNeg) sub r17=r0,r8 + ;; + mov ar.rsc=r11 // put RSE in enforced lazy mode + shr.u r8=r25,r16 + add r3=8,in0 // r3 <- &jmpbuf.r1 + shl r9=r25,r17 + ;; + or r25=r8,r9 + ;; + mov r26=ar.rnat + mov ar.unat=r25 // setup ar.unat (NaT bits for r1, r4-r7, and r12) + ;; + ld8.fill.nta sp=[r2],16 // r12 (sp) + ld8.fill.nta gp=[r3],16 // r1 (gp) + dep r11=-1,r23,3,6 // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp) + ;; + ld8.nta r16=[r2],16 // caller's unat + ld8.nta r17=[r3],16 // fpsr + ;; + ld8.fill.nta r4=[r2],16 // r4 + ld8.fill.nta r5=[r3],16 // r5 (gp) + cmp.geu p8,p0=r10,r11 // p8 <- (ar.bsp >= jmpbuf.ar_bsp) + ;; + ld8.fill.nta r6=[r2],16 // r6 + ld8.fill.nta r7=[r3],16 // r7 + ;; + mov ar.unat=r16 // restore caller's unat + mov ar.fpsr=r17 // restore fpsr + ;; + ld8.nta r16=[r2],16 // b0 + ld8.nta r17=[r3],16 // b1 + ;; +(p8) ld8 r26=[r11] // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp) + mov ar.bspstore=r23 // restore ar.bspstore + ;; + ld8.nta r18=[r2],16 // b2 + ld8.nta r19=[r3],16 // b3 + ;; + ld8.nta r20=[r2],16 // b4 + ld8.nta r21=[r3],16 // b5 + ;; + ld8.nta r11=[r2],16 // ar.pfs + ld8.nta r22=[r3],56 // ar.lc + ;; + ld8.nta r24=[r2],32 // pr + mov b0=r16 + ;; + ldf.fill.nta f2=[r2],32 + ldf.fill.nta f3=[r3],32 + mov b1=r17 + ;; + ldf.fill.nta f4=[r2],32 + ldf.fill.nta f5=[r3],32 + mov b2=r18 + ;; + ldf.fill.nta f16=[r2],32 + ldf.fill.nta f17=[r3],32 + mov b3=r19 + ;; + ldf.fill.nta f18=[r2],32 + ldf.fill.nta f19=[r3],32 + mov b4=r20 + ;; + ldf.fill.nta f20=[r2],32 + ldf.fill.nta f21=[r3],32 + mov b5=r21 + ;; + ldf.fill.nta f22=[r2],32 + ldf.fill.nta f23=[r3],32 + mov ar.lc=r22 + ;; + ldf.fill.nta f24=[r2],32 + ldf.fill.nta f25=[r3],32 + cmp.eq p8,p9=0,in1 + ;; + ldf.fill.nta f26=[r2],32 + ldf.fill.nta f27=[r3],32 + mov ar.pfs=r11 + ;; + ldf.fill.nta f28=[r2],32 + ldf.fill.nta f29=[r3],32 + ;; + ldf.fill.nta f30=[r2] + ldf.fill.nta f31=[r3] +(p8) mov r8=1 + + mov ar.rnat=r26 // restore ar.rnat + ;; + mov ar.rsc=r27 // restore ar.rsc +(p9) mov r8=in1 + + invala // virt. -> phys. regnum mapping may change + mov pr=r24,-1 + br.ret.dptk.few rp + .endp longjmp diff --git a/grub-core/lib/ia64/setjmp.S b/grub-core/lib/ia64/setjmp.S new file mode 100644 index 000000000..190623d35 --- /dev/null +++ b/grub-core/lib/ia64/setjmp.S @@ -0,0 +1,177 @@ +/* Copyright (C) 1999, 2000, 2001, 2002, 2008 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. + + The layout of the jmp_buf is as follows. This is subject to change + and user-code should never depend on the particular layout of + jmp_buf! + + + offset: description: + ------- ------------ + 0x000 stack pointer (r12) ; unchangeable (see _JMPBUF_UNWINDS) + 0x008 r1 (gp) + 0x010 caller's unat + 0x018 fpsr + 0x020 r4 + 0x028 r5 + 0x030 r6 + 0x038 r7 + 0x040 rp (b0) + 0x048 b1 + 0x050 b2 + 0x058 b3 + 0x060 b4 + 0x068 b5 + 0x070 ar.pfs + 0x078 ar.lc + 0x080 pr + 0x088 ar.bsp ; unchangeable (see __longjmp.S) + 0x090 ar.unat + 0x098 &__jmp_buf ; address of the jmpbuf (needed to locate NaT bits in unat) + 0x0a0 f2 + 0x0b0 f3 + 0x0c0 f4 + 0x0d0 f5 + 0x0e0 f16 + 0x0f0 f17 + 0x100 f18 + 0x110 f19 + 0x120 f20 + 0x130 f21 + 0x130 f22 + 0x140 f23 + 0x150 f24 + 0x160 f25 + 0x170 f26 + 0x180 f27 + 0x190 f28 + 0x1a0 f29 + 0x1b0 f30 + 0x1c0 f31 */ + +#include +#include + + .file "setjmp.S" + +GRUB_MOD_LICENSE ("GPLv2+") + + /* The following two entry points are the traditional entry points: */ + + .text + .global setjmp + .proc setjmp +setjmp: + alloc r8=ar.pfs,2,0,0,0 + mov in1=1 + br.cond.sptk.many __sigsetjmp + .endp setjmp + + /* __sigsetjmp(__jmp_buf buf, int savemask) */ + + .proc __sigsetjmp +__sigsetjmp: + //.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc loc1=ar.pfs,2,2,2,0 + mov r16=ar.unat + ;; + mov r17=ar.fpsr + mov r2=in0 + add r3=8,in0 + ;; + st8.spill.nta [r2]=sp,16 // r12 (sp) + st8.spill.nta [r3]=gp,16 // r1 (gp) + ;; + st8.nta [r2]=r16,16 // save caller's unat + st8.nta [r3]=r17,16 // save fpsr + add r8=0xa0,in0 + ;; + st8.spill.nta [r2]=r4,16 // r4 + st8.spill.nta [r3]=r5,16 // r5 + add r9=0xb0,in0 + ;; + stf.spill.nta [r8]=f2,32 + stf.spill.nta [r9]=f3,32 + mov loc0=rp + .body + ;; + stf.spill.nta [r8]=f4,32 + stf.spill.nta [r9]=f5,32 + mov r17=b1 + ;; + stf.spill.nta [r8]=f16,32 + stf.spill.nta [r9]=f17,32 + mov r18=b2 + ;; + stf.spill.nta [r8]=f18,32 + stf.spill.nta [r9]=f19,32 + mov r19=b3 + ;; + stf.spill.nta [r8]=f20,32 + stf.spill.nta [r9]=f21,32 + mov r20=b4 + ;; + stf.spill.nta [r8]=f22,32 + stf.spill.nta [r9]=f23,32 + mov r21=b5 + ;; + stf.spill.nta [r8]=f24,32 + stf.spill.nta [r9]=f25,32 + mov r22=ar.lc + ;; + stf.spill.nta [r8]=f26,32 + stf.spill.nta [r9]=f27,32 + mov r24=pr + ;; + stf.spill.nta [r8]=f28,32 + stf.spill.nta [r9]=f29,32 + ;; + stf.spill.nta [r8]=f30 + stf.spill.nta [r9]=f31 + + st8.spill.nta [r2]=r6,16 // r6 + st8.spill.nta [r3]=r7,16 // r7 + ;; + mov r23=ar.bsp + mov r25=ar.unat + mov out0=in0 + + st8.nta [r2]=loc0,16 // b0 + st8.nta [r3]=r17,16 // b1 + mov out1=in1 + ;; + st8.nta [r2]=r18,16 // b2 + st8.nta [r3]=r19,16 // b3 + ;; + st8.nta [r2]=r20,16 // b4 + st8.nta [r3]=r21,16 // b5 + ;; + st8.nta [r2]=loc1,16 // ar.pfs + st8.nta [r3]=r22,16 // ar.lc + ;; + st8.nta [r2]=r24,16 // pr + st8.nta [r3]=r23,16 // ar.bsp + ;; + st8.nta [r2]=r25 // ar.unat + st8.nta [r3]=in0 // &__jmp_buf + mov r8=0 + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp + + .endp __sigsetjmp diff --git a/grub-core/lib/ieee1275/cmos.c b/grub-core/lib/ieee1275/cmos.c new file mode 100644 index 000000000..fa57db9e7 --- /dev/null +++ b/grub-core/lib/ieee1275/cmos.c @@ -0,0 +1,75 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +volatile grub_uint8_t *grub_cmos_port = 0; +grub_err_t +grub_cmos_find_port (void) +{ + auto int hook (struct grub_ieee1275_devalias *alias); + int hook (struct grub_ieee1275_devalias *alias) + { + grub_ieee1275_phandle_t dev; + grub_uint32_t addr[2]; + grub_ssize_t actual; + /* Enough to check if it's "m5819" */ + char compat[100]; + if (grub_ieee1275_finddevice (alias->path, &dev)) + return 0; + if (grub_ieee1275_get_property (dev, "compatible", compat, sizeof (compat), + 0)) + return 0; + if (grub_strcmp (compat, "m5819") != 0) + return 0; + if (grub_ieee1275_get_integer_property (dev, "address", + addr, sizeof (addr), &actual)) + return 0; + if (actual == 4) + { + grub_cmos_port = (volatile grub_uint8_t *) (grub_addr_t) addr[0]; + return 1; + } + +#if GRUB_CPU_SIZEOF_VOID_P == 8 + if (actual == 8) + { + grub_cmos_port = (volatile grub_uint8_t *) + ((((grub_addr_t) addr[0]) << 32) | addr[1]); + return 1; + } +#else + if (actual == 8 && addr[0] == 0) + { + grub_cmos_port = (volatile grub_uint8_t *) addr[1]; + return 1; + } +#endif + return 0; + } + + grub_ieee1275_devices_iterate (hook); + if (!grub_cmos_port) + return grub_error (GRUB_ERR_IO, "no cmos found"); + + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/ieee1275/datetime.c b/grub-core/lib/ieee1275/datetime.c index 7e6f8d1f1..1947135fe 100644 --- a/grub-core/lib/ieee1275/datetime.c +++ b/grub-core/lib/ieee1275/datetime.c @@ -20,8 +20,15 @@ #include #include #include +#include +#if defined (__powerpc__) || defined (__sparc__) +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); static char *rtc = 0; +static int no_ieee1275_rtc = 0; static void find_rtc (void) @@ -39,6 +46,8 @@ find_rtc (void) } grub_ieee1275_devices_iterate (hook); + if (!rtc) + no_ieee1275_rtc = 1; } grub_err_t @@ -61,10 +70,12 @@ grub_get_datetime (struct grub_datetime *datetime) int status; grub_ieee1275_ihandle_t ihandle; + if (no_ieee1275_rtc) + return grub_get_datetime_cmos (datetime); if (!rtc) find_rtc (); if (!rtc) - return grub_error (GRUB_ERR_IO, "no RTC found"); + return grub_get_datetime_cmos (datetime); status = grub_ieee1275_open (rtc, &ihandle); if (status == -1) @@ -111,10 +122,12 @@ grub_set_datetime (struct grub_datetime *datetime) int status; grub_ieee1275_ihandle_t ihandle; + if (no_ieee1275_rtc) + return grub_set_datetime_cmos (datetime); if (!rtc) find_rtc (); if (!rtc) - return grub_error (GRUB_ERR_IO, "no RTC found"); + return grub_set_datetime_cmos (datetime); status = grub_ieee1275_open (rtc, &ihandle); if (status == -1) diff --git a/grub-core/lib/ieee1275/reboot.c b/grub-core/lib/ieee1275/reboot.c new file mode 100644 index 000000000..91c8779f2 --- /dev/null +++ b/grub-core/lib/ieee1275/reboot.c @@ -0,0 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +void +grub_reboot (void) +{ + grub_ieee1275_interpret ("reset-all", 0); + for (;;) ; +} diff --git a/grub-core/lib/legacy_parse.c b/grub-core/lib/legacy_parse.c index ae27048a2..2d9221bda 100644 --- a/grub-core/lib/legacy_parse.c +++ b/grub-core/lib/legacy_parse.c @@ -42,7 +42,8 @@ struct legacy_command TYPE_BOOL, TYPE_INT, TYPE_REST_VERBATIM, - TYPE_VBE_MODE + TYPE_VBE_MODE, + TYPE_WITH_CONFIGFILE_OPTION } argt[4]; enum { FLAG_IGNORE_REST = 0x001, @@ -58,13 +59,22 @@ struct legacy_command const char *longdesc; }; -struct legacy_command legacy_commands[] = +/* Help texts are kept here mostly for reference. They are never shown. So + no need to gettextize. + */ +static struct legacy_command legacy_commands[] = { {"blocklist", "blocklist '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE", "Print the blocklist notation of the file FILE."}, {"boot", "boot\n", NULL, 0, 0, {}, 0, 0, "Boot the OS/chain-loader which has been loaded."}, - /* FIXME: bootp unsupported. */ + {"bootp", "net_bootp; net_ls_addr; if [ x%s = x--with-configfile ]; then " + "if net_get_dhcp_option configfile_name pxe 150 string; then " + "configfile $configfile_name; fi; fi\n", NULL, 0, 1, + {TYPE_WITH_CONFIGFILE_OPTION}, FLAG_IGNORE_REST, "[--with-configfile]", + "Initialize a network device via BOOTP. If the option `--with-configfile'" + " is given, try to load a configuration file specified by the 150 vendor" + " tag."}, {"cat", "cat '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE", "Print the contents of the file FILE."}, {"chainloader", "chainloader %s '%s'\n", NULL, 0, @@ -102,7 +112,13 @@ struct legacy_command legacy_commands[] = "[NUM | `saved']", "Set the default entry to entry number NUM (if not specified, it is" " 0, the first entry) or the entry number saved by savedefault."}, - /* FIXME: dhcp unsupported. */ + {"dhcp", "net_bootp; net_ls_addr; if [ x%s = x--with-configfile ]; then " + "if net_get_dhcp_option configfile_name pxe 150 string; then " + "configfile $configfile_name; fi; fi\n", NULL, 0, 1, + {TYPE_WITH_CONFIGFILE_OPTION}, FLAG_IGNORE_REST, "[--with-configfile]", + "Initialize a network device via BOOTP. If the option `--with-configfile'" + " is given, try to load a configuration file specified by the 150 vendor" + " tag."}, {"displayapm", "lsapm\n", NULL, 0, 0, {}, 0, 0, "Display APM BIOS information."}, {"displaymem", "lsmmap\n", NULL, 0, 0, {}, 0, 0, @@ -116,7 +132,7 @@ struct legacy_command legacy_commands[] = " immediately starts over using the NUM entry (same numbering as the" " `default' command). This obviously won't help if the machine" " was rebooted by a kernel that GRUB loaded."}, - {"find", "search -sf '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILENAME", + {"find", "search -f '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILENAME", "Search for the filename FILENAME in all of partitions and print the list of" " the devices which contain the file."}, /* FIXME: fstest unsupported. */ @@ -322,24 +338,23 @@ struct legacy_command legacy_commands[] = char * grub_legacy_escape (const char *in, grub_size_t len) { - const char *ptr; - char *ret, *outptr; + char *ptr; + char *ret; + char saved; int overhead = 0; - for (ptr = in; ptr < in + len && *ptr; ptr++) - if (*ptr == '\'' || *ptr == '\\') - overhead++; + + for (ptr = (char*)in; ptr < in + len && *ptr; ptr++) + if (*ptr == '\'') + overhead += 3; ret = grub_malloc (ptr - in + overhead + 1); if (!ret) return NULL; - outptr = ret; - for (ptr = in; ptr < in + len && *ptr; ptr++) - { - if (*ptr == '\'' || *ptr == '\\') - *outptr++ = '\\'; - - *outptr++ = *ptr; - } - *outptr++ = 0; + + ptr = (char*)in; + saved = ptr[len]; + ptr[len] = '\0'; + grub_strchrsub (ret, ptr, '\'', "'\\''"); + ptr[len] = saved; return ret; } @@ -400,7 +415,7 @@ adjust_file (const char *in, grub_size_t len) } static int -check_option (const char *a, char *b, grub_size_t len) +check_option (const char *a, const char *b, grub_size_t len) { if (grub_strlen (b) != len) return 0; @@ -412,6 +427,8 @@ is_option (enum arg_type opt, const char *curarg, grub_size_t len) { switch (opt) { + case TYPE_WITH_CONFIGFILE_OPTION: + return check_option (curarg, "--with-configfile", len); case TYPE_NOAPM_OPTION: return check_option (curarg, "--no-apm", len); case TYPE_FORCE_OPTION: @@ -486,8 +503,12 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) if (legacy_commands[cmdnum].flags & FLAG_TERMINAL) { - int dumb = 0, no_echo = 0, no_edit = 0, lines = 24; - int console = 0, serial = 0, hercules = 0; + int dumb = 0, lines = 24; +#ifdef TODO + int no_echo = 0, no_edit = 0; + int hercules = 0; +#endif + int console = 0, serial = 0; /* Big enough for any possible resulting command. */ char outbuf[256] = ""; char *outptr; @@ -497,13 +518,13 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) " [console] [serial] [hercules]"*/ if (grub_memcmp (ptr, "--dumb", sizeof ("--dumb") - 1) == 0) dumb = 1; - +#ifdef TODO if (grub_memcmp (ptr, "--no-echo", sizeof ("--no-echo") - 1) == 0) no_echo = 1; if (grub_memcmp (ptr, "--no-edit", sizeof ("--no-edit") - 1) == 0) no_edit = 1; - +#endif if (grub_memcmp (ptr, "--lines=", sizeof ("--lines=") - 1) == 0) { lines = grub_strtoul (ptr + sizeof ("--lines=") - 1, 0, 0); @@ -519,10 +540,10 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) if (grub_memcmp (ptr, "serial", sizeof ("serial") - 1) == 0) serial = 1; - +#ifdef TODO if (grub_memcmp (ptr, "hercules", sizeof ("hercules") - 1) == 0) hercules = 1; - +#endif while (*ptr && !grub_isspace (*ptr)) ptr++; while (*ptr && grub_isspace (*ptr)) @@ -618,12 +639,13 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) { for (; *ptr && grub_isspace (*ptr); ptr++); for (; *ptr && !grub_isspace (*ptr); ptr++) - if (*ptr == '\\' || *ptr == '\'') - overhead++; + if (*ptr == '\'') + overhead += 3; if (*ptr) ptr++; overhead += 3; } + outptr0 = args[i] = grub_malloc (overhead + (ptr - curarg)); if (!outptr0) return NULL; @@ -637,9 +659,15 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) *outptr++ = '\''; for (; *ptr && !grub_isspace (*ptr); ptr++) { - if (*ptr == '\\' || *ptr == '\'') - *outptr++ = '\\'; - *outptr++ = *ptr; + if (*ptr == '\'') + { + *outptr++ = '\''; + *outptr++ = '\\'; + *outptr++ = '\''; + *outptr++ = '\''; + } + else + *outptr++ = *ptr; } *outptr++ = '\''; if (*ptr) @@ -652,6 +680,7 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) case TYPE_VERBATIM: args[i] = grub_legacy_escape (curarg, curarglen); break; + case TYPE_WITH_CONFIGFILE_OPTION: case TYPE_FORCE_OPTION: case TYPE_NOAPM_OPTION: case TYPE_TYPE_OR_NOMEM_OPTION: @@ -670,7 +699,10 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) int base = 10; brk = curarg; if (brk[0] == '0' && brk[1] == 'x') - base = 16; + { + base = 16; + brk += 2; + } else if (brk[0] == '0') base = 8; for (; *brk && brk < curarg + curarglen; brk++) @@ -743,6 +775,7 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix) case TYPE_FILE: case TYPE_REST_VERBATIM: case TYPE_VERBATIM: + case TYPE_WITH_CONFIGFILE_OPTION: case TYPE_FORCE_OPTION: case TYPE_NOAPM_OPTION: case TYPE_TYPE_OR_NOMEM_OPTION: diff --git a/grub-core/lib/libgcrypt/cipher/md4.c b/grub-core/lib/libgcrypt/cipher/md4.c index 680cf87f5..aa180f0d4 100644 --- a/grub-core/lib/libgcrypt/cipher/md4.c +++ b/grub-core/lib/libgcrypt/cipher/md4.c @@ -101,7 +101,8 @@ transform ( MD4_CONTEXT *ctx, const unsigned char *data ) #ifdef WORDS_BIGENDIAN { int i; - byte *p2, *p1; + byte *p2; + const byte *p1; for(i=0, p1=data, p2=(byte*)in; i < 16; i++, p2 += 4 ) { p2[3] = *p1++; diff --git a/grub-core/lib/libgcrypt/cipher/md5.c b/grub-core/lib/libgcrypt/cipher/md5.c index 899dce89a..3d3046df2 100644 --- a/grub-core/lib/libgcrypt/cipher/md5.c +++ b/grub-core/lib/libgcrypt/cipher/md5.c @@ -92,7 +92,8 @@ transform ( MD5_CONTEXT *ctx, const unsigned char *data ) #ifdef WORDS_BIGENDIAN { int i; - byte *p2, *p1; + byte *p2; + const byte *p1; for(i=0, p1=data, p2=(byte*)correct_words; i < 16; i++, p2 += 4 ) { p2[3] = *p1++; diff --git a/grub-core/lib/libgcrypt/cipher/rmd160.c b/grub-core/lib/libgcrypt/cipher/rmd160.c index 7805bf53b..73d533739 100644 --- a/grub-core/lib/libgcrypt/cipher/rmd160.c +++ b/grub-core/lib/libgcrypt/cipher/rmd160.c @@ -169,7 +169,8 @@ transform ( RMD160_CONTEXT *hd, const unsigned char *data ) u32 x[16]; { int i; - byte *p2, *p1; + byte *p2; + const byte *p1; for (i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) { p2[3] = *p1++; diff --git a/grub-core/lib/libgcrypt/cipher/serpent.c b/grub-core/lib/libgcrypt/cipher/serpent.c index 6b7e655a9..b1026eafc 100644 --- a/grub-core/lib/libgcrypt/cipher/serpent.c +++ b/grub-core/lib/libgcrypt/cipher/serpent.c @@ -585,22 +585,19 @@ serpent_key_prepare (const byte *key, unsigned int key_length, int i; /* Copy key. */ - for (i = 0; i < key_length / 4; i++) - { + memcpy (key_prepared, key, key_length); #ifdef WORDS_BIGENDIAN - key_prepared[i] = byte_swap_32 (((u32 *) key)[i]); -#else - key_prepared[i] = ((u32 *) key)[i]; + for (i = 0; i < key_length / 4; i++) + key_prepared[i] = byte_swap_32 (key_prepared[i]); #endif - } - if (i < 8) + if (key_length < 32) { /* Key must be padded according to the Serpent specification. */ - key_prepared[i] = 0x00000001; + key_prepared[key_length / 4] = 0x00000001; - for (i++; i < 8; i++) + for (i = key_length / 4 + 1; i < 8; i++) key_prepared[i] = 0; } } @@ -707,21 +704,17 @@ serpent_setkey (void *ctx, static void serpent_encrypt_internal (serpent_context_t *context, - const serpent_block_t input, serpent_block_t output) + const byte *input, byte *output) { serpent_block_t b, b_next; int round = 0; + memcpy (b, input, sizeof (b)); #ifdef WORDS_BIGENDIAN - b[0] = byte_swap_32 (input[0]); - b[1] = byte_swap_32 (input[1]); - b[2] = byte_swap_32 (input[2]); - b[3] = byte_swap_32 (input[3]); -#else - b[0] = input[0]; - b[1] = input[1]; - b[2] = input[2]; - b[3] = input[3]; + b[0] = byte_swap_32 (b[0]); + b[1] = byte_swap_32 (b[1]); + b[2] = byte_swap_32 (b[2]); + b[3] = byte_swap_32 (b[3]); #endif ROUND (0, context->keys, b, b_next); @@ -759,35 +752,27 @@ serpent_encrypt_internal (serpent_context_t *context, ROUND_LAST (7, context->keys, b, b_next); #ifdef WORDS_BIGENDIAN - output[0] = byte_swap_32 (b_next[0]); - output[1] = byte_swap_32 (b_next[1]); - output[2] = byte_swap_32 (b_next[2]); - output[3] = byte_swap_32 (b_next[3]); -#else - output[0] = b_next[0]; - output[1] = b_next[1]; - output[2] = b_next[2]; - output[3] = b_next[3]; + b_next[0] = byte_swap_32 (b_next[0]); + b_next[1] = byte_swap_32 (b_next[1]); + b_next[2] = byte_swap_32 (b_next[2]); + b_next[3] = byte_swap_32 (b_next[3]); #endif + memcpy (output, b_next, sizeof (b_next)); } static void serpent_decrypt_internal (serpent_context_t *context, - const serpent_block_t input, serpent_block_t output) + const byte *input, byte *output) { serpent_block_t b, b_next; int round = ROUNDS; + memcpy (b, input, sizeof (b)); #ifdef WORDS_BIGENDIAN - b_next[0] = byte_swap_32 (input[0]); - b_next[1] = byte_swap_32 (input[1]); - b_next[2] = byte_swap_32 (input[2]); - b_next[3] = byte_swap_32 (input[3]); -#else - b_next[0] = input[0]; - b_next[1] = input[1]; - b_next[2] = input[2]; - b_next[3] = input[3]; + b[0] = byte_swap_32 (b[0]); + b[1] = byte_swap_32 (b[1]); + b[2] = byte_swap_32 (b[2]); + b[3] = byte_swap_32 (b[3]); #endif ROUND_FIRST_INVERSE (7, context->keys, b_next, b); @@ -824,18 +809,13 @@ serpent_decrypt_internal (serpent_context_t *context, ROUND_INVERSE (1, context->keys, b, b_next); ROUND_INVERSE (0, context->keys, b, b_next); - #ifdef WORDS_BIGENDIAN - output[0] = byte_swap_32 (b_next[0]); - output[1] = byte_swap_32 (b_next[1]); - output[2] = byte_swap_32 (b_next[2]); - output[3] = byte_swap_32 (b_next[3]); -#else - output[0] = b_next[0]; - output[1] = b_next[1]; - output[2] = b_next[2]; - output[3] = b_next[3]; + b_next[0] = byte_swap_32 (b_next[0]); + b_next[1] = byte_swap_32 (b_next[1]); + b_next[2] = byte_swap_32 (b_next[2]); + b_next[3] = byte_swap_32 (b_next[3]); #endif + memcpy (output, b_next, sizeof (b_next)); } static void @@ -843,8 +823,7 @@ serpent_encrypt (void *ctx, byte *buffer_out, const byte *buffer_in) { serpent_context_t *context = ctx; - serpent_encrypt_internal (context, - (const u32 *) buffer_in, (u32 *) buffer_out); + serpent_encrypt_internal (context, buffer_in, buffer_out); _gcry_burn_stack (2 * sizeof (serpent_block_t)); } @@ -853,9 +832,7 @@ serpent_decrypt (void *ctx, byte *buffer_out, const byte *buffer_in) { serpent_context_t *context = ctx; - serpent_decrypt_internal (context, - (const u32 *) buffer_in, - (u32 *) buffer_out); + serpent_decrypt_internal (context, buffer_in, buffer_out); _gcry_burn_stack (2 * sizeof (serpent_block_t)); } @@ -915,8 +892,8 @@ serpent_test (void) serpent_setkey_internal (&context, test_data[i].key, test_data[i].key_length); serpent_encrypt_internal (&context, - (const u32 *) test_data[i].text_plain, - (u32 *) scratch); + test_data[i].text_plain, + scratch); if (memcmp (scratch, test_data[i].text_cipher, sizeof (serpent_block_t))) switch (test_data[i].key_length) @@ -930,8 +907,8 @@ serpent_test (void) } serpent_decrypt_internal (&context, - (const u32 *) test_data[i].text_cipher, - (u32 *) scratch); + test_data[i].text_cipher, + scratch); if (memcmp (scratch, test_data[i].text_plain, sizeof (serpent_block_t))) switch (test_data[i].key_length) { diff --git a/grub-core/lib/libgcrypt_wrap/cipher_wrap.h b/grub-core/lib/libgcrypt_wrap/cipher_wrap.h index b4530c112..5a64c5736 100644 --- a/grub-core/lib/libgcrypt_wrap/cipher_wrap.h +++ b/grub-core/lib/libgcrypt_wrap/cipher_wrap.h @@ -25,6 +25,12 @@ #include #include +#undef WORDS_BIGENDIAN + +#ifdef GRUB_CPU_WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 1 +#endif + #define __GNU_LIBRARY__ #define DIM ARRAY_SIZE @@ -81,6 +87,25 @@ fips_mode (void) return 0; } -#define memset grub_memset +#ifdef GRUB_UTIL +static inline void * +memcpy (void *dest, const void *src, grub_size_t n) +{ + return grub_memcpy (dest, src, n); +} + +static inline void * +memset (void *s, int c, grub_size_t n) +{ + return grub_memset (s, c, n); +} + +static inline int +memcmp (const void *s1, const void *s2, grub_size_t n) +{ + return grub_memcmp (s1, s2, n); +} +#endif + #endif diff --git a/grub-core/lib/minilzo/lzoconf.h b/grub-core/lib/minilzo/lzoconf.h new file mode 100644 index 000000000..1d0fe14fc --- /dev/null +++ b/grub-core/lib/minilzo/lzoconf.h @@ -0,0 +1,446 @@ +/* lzoconf.h -- configuration of the LZO data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZOCONF_H_INCLUDED +#define __LZOCONF_H_INCLUDED 1 + +#define LZO_VERSION 0x2050 +#define LZO_VERSION_STRING "2.05" +#define LZO_VERSION_DATE "Apr 23 2011" + +/* internal Autoconf configuration file - only used when building LZO */ +#if defined(LZO_HAVE_CONFIG_H) +# include +#endif +#include +#include + + +/*********************************************************************** +// LZO requires a conforming +************************************************************************/ + +#if !defined(CHAR_BIT) || (CHAR_BIT != 8) +# error "invalid CHAR_BIT" +#endif +#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) +# error "check your compiler installation" +#endif +#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) +# error "your limits.h macros are broken" +#endif + +/* get OS and architecture defines */ +#ifndef __LZODEFS_H_INCLUDED +#include "lzodefs.h" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// some core defines +************************************************************************/ + +#if !defined(LZO_UINT32_C) +# if (UINT_MAX < LZO_0xffffffffL) +# define LZO_UINT32_C(c) c ## UL +# else +# define LZO_UINT32_C(c) ((c) + 0U) +# endif +#endif + +/* memory checkers */ +#if !defined(__LZO_CHECKER) +# if defined(__BOUNDS_CHECKING_ON) +# define __LZO_CHECKER 1 +# elif defined(__CHECKER__) +# define __LZO_CHECKER 1 +# elif defined(__INSURE__) +# define __LZO_CHECKER 1 +# elif defined(__PURIFY__) +# define __LZO_CHECKER 1 +# endif +#endif + + +/*********************************************************************** +// integral and pointer types +************************************************************************/ + +/* lzo_uint should match size_t */ +#if !defined(LZO_UINT_MAX) +# if defined(LZO_ABI_LLP64) /* WIN64 */ +# if defined(LZO_OS_WIN64) + typedef unsigned __int64 lzo_uint; + typedef __int64 lzo_int; +# else + typedef unsigned long long lzo_uint; + typedef long long lzo_int; +# endif +# define LZO_UINT_MAX 0xffffffffffffffffull +# define LZO_INT_MAX 9223372036854775807LL +# define LZO_INT_MIN (-1LL - LZO_INT_MAX) +# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */ + typedef unsigned int lzo_uint; + typedef int lzo_int; +# define LZO_UINT_MAX UINT_MAX +# define LZO_INT_MAX INT_MAX +# define LZO_INT_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint; + typedef long lzo_int; +# define LZO_UINT_MAX ULONG_MAX +# define LZO_INT_MAX LONG_MAX +# define LZO_INT_MIN LONG_MIN +# else +# error "lzo_uint" +# endif +#endif + +/* Integral types with 32 bits or more. */ +#if !defined(LZO_UINT32_MAX) +# if (UINT_MAX >= LZO_0xffffffffL) + typedef unsigned int lzo_uint32; + typedef int lzo_int32; +# define LZO_UINT32_MAX UINT_MAX +# define LZO_INT32_MAX INT_MAX +# define LZO_INT32_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint32; + typedef long lzo_int32; +# define LZO_UINT32_MAX ULONG_MAX +# define LZO_INT32_MAX LONG_MAX +# define LZO_INT32_MIN LONG_MIN +# else +# error "lzo_uint32" +# endif +#endif + +/* Integral types with exactly 64 bits. */ +#if !defined(LZO_UINT64_MAX) +# if (LZO_UINT_MAX >= LZO_0xffffffffL) +# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3) +# define lzo_uint64 lzo_uint +# define lzo_int64 lzo_int +# define LZO_UINT64_MAX LZO_UINT_MAX +# define LZO_INT64_MAX LZO_INT_MAX +# define LZO_INT64_MIN LZO_INT_MIN +# endif +# elif (ULONG_MAX >= LZO_0xffffffffL) +# if ((((ULONG_MAX) >> 31) >> 31) == 3) + typedef unsigned long lzo_uint64; + typedef long lzo_int64; +# define LZO_UINT64_MAX ULONG_MAX +# define LZO_INT64_MAX LONG_MAX +# define LZO_INT64_MIN LONG_MIN +# endif +# endif +#endif + +/* The larger type of lzo_uint and lzo_uint32. */ +#if (LZO_UINT_MAX >= LZO_UINT32_MAX) +# define lzo_xint lzo_uint +#else +# define lzo_xint lzo_uint32 +#endif + +/* Memory model that allows to access memory at offsets of lzo_uint. */ +#if !defined(__LZO_MMODEL) +# if (LZO_UINT_MAX <= UINT_MAX) +# define __LZO_MMODEL /*empty*/ +# elif defined(LZO_HAVE_MM_HUGE_PTR) +# define __LZO_MMODEL_HUGE 1 +# define __LZO_MMODEL __huge +# else +# define __LZO_MMODEL /*empty*/ +# endif +#endif + +/* no typedef here because of const-pointer issues */ +#define lzo_bytep unsigned char __LZO_MMODEL * +#define lzo_charp char __LZO_MMODEL * +#define lzo_voidp void __LZO_MMODEL * +#define lzo_shortp short __LZO_MMODEL * +#define lzo_ushortp unsigned short __LZO_MMODEL * +#define lzo_uint32p lzo_uint32 __LZO_MMODEL * +#define lzo_int32p lzo_int32 __LZO_MMODEL * +#if defined(LZO_UINT64_MAX) +#define lzo_uint64p lzo_uint64 __LZO_MMODEL * +#define lzo_int64p lzo_int64 __LZO_MMODEL * +#endif +#define lzo_uintp lzo_uint __LZO_MMODEL * +#define lzo_intp lzo_int __LZO_MMODEL * +#define lzo_xintp lzo_xint __LZO_MMODEL * +#define lzo_voidpp lzo_voidp __LZO_MMODEL * +#define lzo_bytepp lzo_bytep __LZO_MMODEL * +/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */ +#define lzo_byte unsigned char __LZO_MMODEL + +typedef int lzo_bool; + + +/*********************************************************************** +// function types +************************************************************************/ + +/* name mangling */ +#if !defined(__LZO_EXTERN_C) +# ifdef __cplusplus +# define __LZO_EXTERN_C extern "C" +# else +# define __LZO_EXTERN_C extern +# endif +#endif + +/* calling convention */ +#if !defined(__LZO_CDECL) +# define __LZO_CDECL __lzo_cdecl +#endif + +/* DLL export information */ +#if !defined(__LZO_EXPORT1) +# define __LZO_EXPORT1 /*empty*/ +#endif +#if !defined(__LZO_EXPORT2) +# define __LZO_EXPORT2 /*empty*/ +#endif + +/* __cdecl calling convention for public C and assembly functions */ +#if !defined(LZO_PUBLIC) +# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL +#endif +#if !defined(LZO_EXTERN) +# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) +#endif +#if !defined(LZO_PRIVATE) +# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL +#endif + +/* function types */ +typedef int +(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_bytep dict, lzo_uint dict_len ); + +typedef int +(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_bytep dict, lzo_uint dict_len ); + + +/* Callback interface. Currently only the progress indicator ("nprogress") + * is used, but this may change in a future release. */ + +struct lzo_callback_t; +typedef struct lzo_callback_t lzo_callback_t; +#define lzo_callback_p lzo_callback_t __LZO_MMODEL * + +/* malloc & free function types */ +typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t) + (lzo_callback_p self, lzo_uint items, lzo_uint size); +typedef void (__LZO_CDECL *lzo_free_func_t) + (lzo_callback_p self, lzo_voidp ptr); + +/* a progress indicator callback function */ +typedef void (__LZO_CDECL *lzo_progress_func_t) + (lzo_callback_p, lzo_uint, lzo_uint, int); + +struct lzo_callback_t +{ + /* custom allocators (set to 0 to disable) */ + lzo_alloc_func_t nalloc; /* [not used right now] */ + lzo_free_func_t nfree; /* [not used right now] */ + + /* a progress indicator callback function (set to 0 to disable) */ + lzo_progress_func_t nprogress; + + /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress + * callbacks points back to this struct, so you are free to store + * some extra info in the following variables. */ + lzo_voidp user1; + lzo_xint user2; + lzo_xint user3; +}; + + +/*********************************************************************** +// error codes and prototypes +************************************************************************/ + +/* Error codes for the compression/decompression functions. Negative + * values are errors, positive values will be used for special but + * normal events. + */ +#define LZO_E_OK 0 +#define LZO_E_ERROR (-1) +#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */ +#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ +#define LZO_E_INPUT_OVERRUN (-4) +#define LZO_E_OUTPUT_OVERRUN (-5) +#define LZO_E_LOOKBEHIND_OVERRUN (-6) +#define LZO_E_EOF_NOT_FOUND (-7) +#define LZO_E_INPUT_NOT_CONSUMED (-8) +#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ +#define LZO_E_INVALID_ARGUMENT (-10) + + +#ifndef lzo_sizeof_dict_t +# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep)) +#endif + +/* lzo_init() should be the first function you call. + * Check the return code ! + * + * lzo_init() is a macro to allow checking that the library and the + * compiler's view of various types are consistent. + */ +#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ + (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ + (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ + (int)sizeof(lzo_callback_t)) +LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int); + +/* version functions (useful for shared libraries) */ +LZO_EXTERN(unsigned) lzo_version(void); +LZO_EXTERN(const char *) lzo_version_string(void); +LZO_EXTERN(const char *) lzo_version_date(void); +LZO_EXTERN(const lzo_charp) _lzo_version_string(void); +LZO_EXTERN(const lzo_charp) _lzo_version_date(void); + +/* string functions */ +LZO_EXTERN(int) + lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len); +LZO_EXTERN(lzo_voidp) + lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len); +LZO_EXTERN(lzo_voidp) + lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len); +LZO_EXTERN(lzo_voidp) + lzo_memset(lzo_voidp buf, int c, lzo_uint len); + +/* checksum functions */ +LZO_EXTERN(lzo_uint32) + lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); +LZO_EXTERN(lzo_uint32) + lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len); +LZO_EXTERN(const lzo_uint32p) + lzo_get_crc32_table(void); + +/* misc. */ +LZO_EXTERN(int) _lzo_config_check(void); +typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; +typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; +typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t; + +/* align a char pointer on a boundary that is a multiple of 'size' */ +LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size); +#define LZO_PTR_ALIGN_UP(p,size) \ + ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size))) + + +/*********************************************************************** +// deprecated macros - only for backward compatibility with LZO v1.xx +************************************************************************/ + +#if defined(LZO_CFG_COMPAT) + +#define __LZOCONF_H 1 + +#if defined(LZO_ARCH_I086) +# define __LZO_i386 1 +#elif defined(LZO_ARCH_I386) +# define __LZO_i386 1 +#endif + +#if defined(LZO_OS_DOS16) +# define __LZO_DOS 1 +# define __LZO_DOS16 1 +#elif defined(LZO_OS_DOS32) +# define __LZO_DOS 1 +#elif defined(LZO_OS_WIN16) +# define __LZO_WIN 1 +# define __LZO_WIN16 1 +#elif defined(LZO_OS_WIN32) +# define __LZO_WIN 1 +#endif + +#define __LZO_CMODEL /*empty*/ +#define __LZO_DMODEL /*empty*/ +#define __LZO_ENTRY __LZO_CDECL +#define LZO_EXTERN_CDECL LZO_EXTERN +#define LZO_ALIGN LZO_PTR_ALIGN_UP + +#define lzo_compress_asm_t lzo_compress_t +#define lzo_decompress_asm_t lzo_decompress_t + +#endif /* LZO_CFG_COMPAT */ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + + +/* vim:set ts=4 et: */ diff --git a/grub-core/lib/minilzo/lzodefs.h b/grub-core/lib/minilzo/lzodefs.h new file mode 100644 index 000000000..0e40e332a --- /dev/null +++ b/grub-core/lib/minilzo/lzodefs.h @@ -0,0 +1,1852 @@ +/* lzodefs.h -- architecture, OS and compiler specific defines + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if defined(__IBMCPP__) && !defined(__IBMC__) +# define __IBMC__ __IBMCPP__ +#endif +#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if defined(__INTEL_COMPILER) && defined(__linux__) +# pragma warning(disable: 193) +#endif +#if defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif 0 && defined(__C251__) +# pragma warning disable = 322 +#endif +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if (_MSC_VER >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if 0 +#define LZO_0xffffL 0xfffful +#define LZO_0xffffffffL 0xfffffffful +#else +#define LZO_0xffffL 65535ul +#define LZO_0xffffffffL 4294967295ul +#endif +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED 1 +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +#else +# define LZO_EXTERN_C extern +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if (LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif (LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__ppc__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif (defined(__mips__) && defined(__psp__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) || defined(__MACOS__) +# define LZO_OS_POSIX_MACOSX 1 +# define LZO_INFO_OS_POSIX "macosx" +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +#elif defined(__INTEL_COMPILER) +# define LZO_CC_INTELC 1 +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_WIN32) || defined(_WIN64) +# define LZO_CC_SYNTAX_MSC 1 +# else +# define LZO_CC_SYNTAX_GNUC 1 +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) +# else +# define LZO_CC_CLANG_CLANG 0x010000L +# endif +# define LZO_CC_CLANG LZO_CC_CLANG_GNUC +# define LZO_INFO_CC "clang" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) +# define LZO_CC_IBMC 1 +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(_MSC_VER) +# define LZO_CC_MSC 1 +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#elif defined(__MWERKS__) +# define LZO_CC_MWERKS 1 +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if (__ZTC__ == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if (LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_ARCH_IA16 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) +# define LZO_ARCH_ARM 1 +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) +# define LZO_INFO_ARCH "arm" +# else +# define LZO_INFO_ARCH "arm" +# endif +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#endif +#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "this should not happen" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "this should not happen" +# elif (LZO_CC_ZORTECHC) +# else +# error "this should not happen" +# endif +#endif +#ifdef __cplusplus +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#ifdef __cplusplus +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#endif +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#endif +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#endif +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#endif +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#endif +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#endif +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && (LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if (LZO_ARCH_I086) +# define __LZO_WORDSIZE 2 +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "LZO_MM" +# endif +#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) +# define __LZO_WORDSIZE 1 +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__NORMAL_MODE__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 2 +# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 4 +# else +# define __LZO_WORDSIZE 2 +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_M16C) +# define __LZO_WORDSIZE 2 +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define __LZO_WORDSIZE LZO_SIZEOF_LONG +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_ARCH_SPU) +# if 0 +# define __LZO_WORDSIZE 16 +# endif +# define LZO_SIZEOF_VOID_P 4 +#else +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_WORDSIZE) +# if defined(__LZO_WORDSIZE) +# define LZO_WORDSIZE __LZO_WORDSIZE +# else +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +# endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#else +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "LZO_MM" +# endif +#else +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) +# error "this should not happen" +#endif +#if (LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif (LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif (LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if !defined(__LZO_LIBC_OVERRIDE) +#if (LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif (LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif (LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif (LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif (LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uclibc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#else +# define __lzo_gnuc_extension__ /*empty*/ +#endif +#endif +#if !defined(__lzo_ua_volatile) +# define __lzo_ua_volatile volatile +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_alignof(e) __alignof__(e) +#endif +#endif +#if defined(__lzo_alignof) +# define __lzo_HAVE_alignof 1 +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# define __lzo_HAVE_constructor 1 +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# define __lzo_HAVE_destructor 1 +#endif +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) +# error "this should not happen" +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_inline __inline__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define __lzo_inline inline +#endif +#endif +#if defined(__lzo_inline) +# define __lzo_HAVE_inline 1 +#else +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#endif +#endif +#if defined(__lzo_forceinline) +# define __lzo_HAVE_forceinline 1 +#else +# define __lzo_forceinline /*empty*/ +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_noinline __attribute__((__noinline__)) +#endif +#endif +#if defined(__lzo_noinline) +# define __lzo_HAVE_noinline 1 +#else +# define __lzo_noinline /*empty*/ +#endif +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) +# error "this should not happen" +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#endif +#endif +#if defined(__lzo_noreturn) +# define __lzo_HAVE_noreturn 1 +#else +# define __lzo_noreturn /*empty*/ +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# define __lzo_HAVE_nothrow 1 +#else +# define __lzo_nothrow /*empty*/ +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#endif +#endif +#if defined(__lzo_restrict) +# define __lzo_HAVE_restrict 1 +#else +# define __lzo_restrict /*empty*/ +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# define __lzo_HAVE_likely 1 +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_unlikely) +# define __lzo_HAVE_unlikely 1 +#else +# define __lzo_unlikely(e) (e) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if (0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(LZO_UNCONST_CAST) +# if 0 && defined(__cplusplus) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) +# else +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} +# endif +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit /*empty*/ +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl /*empty*/ +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit /*empty*/ +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main /*empty*/ +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort /*empty*/ +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler /*empty*/ +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !(LZO_CFG_NO_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# define LZO_OPT_UNALIGNED64 1 +#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) +#elif (LZO_ARCH_ARM) +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_CRIS) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_I386) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if (LZO_ABI_BIG_ENDIAN) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_S390) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# if (LZO_SIZEOF_SIZE_T == 8) +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if (LZO_CFG_NO_INLINE_ASM) +#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +#elif (LZO_CC_INTELC) +# define __LZO_ASM_CLOBBER "memory" +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +#endif +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER + +#endif /* already included */ + +/* vim:set ts=4 et: */ diff --git a/grub-core/lib/minilzo/minilzo.c b/grub-core/lib/minilzo/minilzo.c new file mode 100644 index 000000000..25a1f68b3 --- /dev/null +++ b/grub-core/lib/minilzo/minilzo.c @@ -0,0 +1,4562 @@ +/* minilzo.c -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + +#define __LZO_IN_MINILZO 1 + +#if defined(LZO_CFG_FREESTANDING) +# undef MINILZO_HAVE_CONFIG_H +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# include +#endif +#include +#include +#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS) + +#ifndef __LZODEFS_H_INCLUDED +#define __LZODEFS_H_INCLUDED 1 + +#if defined(__CYGWIN32__) && !defined(__CYGWIN__) +# define __CYGWIN__ __CYGWIN32__ +#endif +#if defined(__IBMCPP__) && !defined(__IBMC__) +# define __IBMC__ __IBMCPP__ +#endif +#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +#endif +#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) +# define _ALL_SOURCE 1 +#endif +#if defined(__mips__) && defined(__R5900__) +# if !defined(__LONG_MAX__) +# define __LONG_MAX__ 9223372036854775807L +# endif +#endif +#if defined(__INTEL_COMPILER) && defined(__linux__) +# pragma warning(disable: 193) +#endif +#if defined(__KEIL__) && defined(__C166__) +# pragma warning disable = 322 +#elif 0 && defined(__C251__) +# pragma warning disable = 322 +#endif +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) +# if (_MSC_VER >= 1300) +# pragma warning(disable: 4668) +# endif +#endif +#if 0 && defined(__WATCOMC__) +# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) +# pragma warning 203 9 +# endif +#endif +#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) +# pragma option -h +#endif +#if 0 +#define LZO_0xffffL 0xfffful +#define LZO_0xffffffffL 0xfffffffful +#else +#define LZO_0xffffL 65535ul +#define LZO_0xffffffffL 4294967295ul +#endif +#if (LZO_0xffffL == LZO_0xffffffffL) +# error "your preprocessor is broken 1" +#endif +#if (16ul * 16384ul != 262144ul) +# error "your preprocessor is broken 2" +#endif +#if 0 +#if (32767 >= 4294967295ul) +# error "your preprocessor is broken 3" +#endif +#if (65535u >= 4294967295ul) +# error "your preprocessor is broken 4" +#endif +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) +# if !defined(MSDOS) +# define MSDOS 1 +# endif +# if !defined(_MSDOS) +# define _MSDOS 1 +# endif +#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) +# if (__VERSION == 520) && (MB_LEN_MAX == 1) +# if !defined(__AZTEC_C__) +# define __AZTEC_C__ __VERSION +# endif +# if !defined(__DOS__) +# define __DOS__ 1 +# endif +# endif +#endif +#endif +#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) +# define ptrdiff_t long +# define _PTRDIFF_T_DEFINED 1 +#endif +#if (UINT_MAX == LZO_0xffffL) +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +# if defined(__AZTEC_C__) && defined(__DOS__) +# define __LZO_RENAME_A 1 +# elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define __LZO_RENAME_A 1 +# elif (_MSC_VER < 700) +# define __LZO_RENAME_B 1 +# endif +# elif defined(__TSC__) && defined(__OS2__) +# define __LZO_RENAME_A 1 +# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) +# define __LZO_RENAME_A 1 +# elif defined(__PACIFIC__) && defined(DOS) +# if !defined(__far) +# define __far far +# endif +# if !defined(__near) +# define __near near +# endif +# endif +# if defined(__LZO_RENAME_A) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__far) +# define __far far +# endif +# if !defined(__huge) +# define __huge huge +# endif +# if !defined(__near) +# define __near near +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# if !defined(__huge) +# define __huge huge +# endif +# elif defined(__LZO_RENAME_B) +# if !defined(__cdecl) +# define __cdecl _cdecl +# endif +# if !defined(__far) +# define __far _far +# endif +# if !defined(__huge) +# define __huge _huge +# endif +# if !defined(__near) +# define __near _near +# endif +# if !defined(__pascal) +# define __pascal _pascal +# endif +# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# if !defined(__cdecl) +# define __cdecl cdecl +# endif +# if !defined(__pascal) +# define __pascal pascal +# endif +# endif +# undef __LZO_RENAME_A +# undef __LZO_RENAME_B +#endif +#if (UINT_MAX == LZO_0xffffL) +#if defined(__AZTEC_C__) && defined(__DOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +#elif defined(_MSC_VER) && defined(MSDOS) +# if (_MSC_VER < 600) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# endif +# if (_MSC_VER < 700) +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# define LZO_BROKEN_SIZEOF 1 +# endif +#elif defined(__PACIFIC__) && defined(DOS) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#elif defined(__TURBOC__) && defined(__MSDOS__) +# if (__TURBOC__ < 0x0150) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +# define LZO_BROKEN_INTEGRAL_PROMOTION 1 +# endif +# if (__TURBOC__ < 0x0200) +# define LZO_BROKEN_SIZEOF 1 +# endif +# if (__TURBOC__ < 0x0400) && defined(__cplusplus) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# endif +#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) +# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 +# define LZO_BROKEN_SIZEOF 1 +#endif +#endif +#if defined(__WATCOMC__) && (__WATCOMC__ < 900) +# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 +#endif +#if defined(_CRAY) && defined(_CRAY1) +# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1 +#endif +#define LZO_PP_STRINGIZE(x) #x +#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x) +#define LZO_PP_CONCAT2(a,b) a ## b +#define LZO_PP_CONCAT3(a,b,c) a ## b ## c +#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b) +#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c) +#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d) +#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e) +#if 1 +#define LZO_CPP_STRINGIZE(x) #x +#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) +#define LZO_CPP_CONCAT2(a,b) a ## b +#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c +#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d +#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e +#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) +#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) +#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) +#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) +#endif +#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) +#if 1 && defined(__cplusplus) +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS 1 +# endif +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS 1 +# endif +#endif +#if defined(__cplusplus) +# define LZO_EXTERN_C extern "C" +#else +# define LZO_EXTERN_C extern +#endif +#if !defined(__LZO_OS_OVERRIDE) +#if (LZO_OS_FREESTANDING) +# define LZO_INFO_OS "freestanding" +#elif (LZO_OS_EMBEDDED) +# define LZO_INFO_OS "embedded" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_OS_EMBEDDED 1 +# define LZO_INFO_OS "embedded" +#elif defined(__CYGWIN__) && defined(__GNUC__) +# define LZO_OS_CYGWIN 1 +# define LZO_INFO_OS "cygwin" +#elif defined(__EMX__) && defined(__GNUC__) +# define LZO_OS_EMX 1 +# define LZO_INFO_OS "emx" +#elif defined(__BEOS__) +# define LZO_OS_BEOS 1 +# define LZO_INFO_OS "beos" +#elif defined(__Lynx__) +# define LZO_OS_LYNXOS 1 +# define LZO_INFO_OS "lynxos" +#elif defined(__OS400__) +# define LZO_OS_OS400 1 +# define LZO_INFO_OS "os400" +#elif defined(__QNX__) +# define LZO_OS_QNX 1 +# define LZO_INFO_OS "qnx" +#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__BORLANDC__) && defined(__DPMI16__) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +#elif defined(__ZTC__) && defined(DOS386) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +#elif defined(__OS2__) || defined(__OS2V2__) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_OS216 1 +# define LZO_INFO_OS "os216" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_OS2 1 +# define LZO_INFO_OS "os2" +# else +# error "check your limits.h header" +# endif +#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) +# define LZO_OS_WIN64 1 +# define LZO_INFO_OS "win64" +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__MWERKS__) && defined(__INTEL__) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_WIN16 1 +# define LZO_INFO_OS "win16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# else +# error "check your limits.h header" +# endif +#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) +# if (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_OS_DOS32 1 +# define LZO_INFO_OS "dos32" +# else +# error "check your limits.h header" +# endif +#elif defined(__WATCOMC__) +# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) +# define LZO_OS_DOS16 1 +# define LZO_INFO_OS "dos16" +# elif defined(__NT__) && (__WATCOMC__ < 1100) +# define LZO_OS_WIN32 1 +# define LZO_INFO_OS "win32" +# elif defined(__linux__) || defined(__LINUX__) +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +# else +# error "please specify a target using the -bt compiler option" +# endif +#elif defined(__palmos__) +# define LZO_OS_PALMOS 1 +# define LZO_INFO_OS "palmos" +#elif defined(__TOS__) || defined(__atarist__) +# define LZO_OS_TOS 1 +# define LZO_INFO_OS "tos" +#elif defined(macintosh) && !defined(__ppc__) +# define LZO_OS_MACCLASSIC 1 +# define LZO_INFO_OS "macclassic" +#elif defined(__VMS) +# define LZO_OS_VMS 1 +# define LZO_INFO_OS "vms" +#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PS2 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "ps2" +#elif (defined(__mips__) && defined(__psp__)) +# define LZO_OS_CONSOLE 1 +# define LZO_OS_CONSOLE_PSP 1 +# define LZO_INFO_OS "console" +# define LZO_INFO_OS_CONSOLE "psp" +#else +# define LZO_OS_POSIX 1 +# define LZO_INFO_OS "posix" +#endif +#if (LZO_OS_POSIX) +# if defined(_AIX) || defined(__AIX__) || defined(__aix__) +# define LZO_OS_POSIX_AIX 1 +# define LZO_INFO_OS_POSIX "aix" +# elif defined(__FreeBSD__) +# define LZO_OS_POSIX_FREEBSD 1 +# define LZO_INFO_OS_POSIX "freebsd" +# elif defined(__hpux__) || defined(__hpux) +# define LZO_OS_POSIX_HPUX 1 +# define LZO_INFO_OS_POSIX "hpux" +# elif defined(__INTERIX) +# define LZO_OS_POSIX_INTERIX 1 +# define LZO_INFO_OS_POSIX "interix" +# elif defined(__IRIX__) || defined(__irix__) +# define LZO_OS_POSIX_IRIX 1 +# define LZO_INFO_OS_POSIX "irix" +# elif defined(__linux__) || defined(__linux) || defined(__LINUX__) +# define LZO_OS_POSIX_LINUX 1 +# define LZO_INFO_OS_POSIX "linux" +# elif defined(__APPLE__) || defined(__MACOS__) +# define LZO_OS_POSIX_MACOSX 1 +# define LZO_INFO_OS_POSIX "macosx" +# elif defined(__minix__) || defined(__minix) +# define LZO_OS_POSIX_MINIX 1 +# define LZO_INFO_OS_POSIX "minix" +# elif defined(__NetBSD__) +# define LZO_OS_POSIX_NETBSD 1 +# define LZO_INFO_OS_POSIX "netbsd" +# elif defined(__OpenBSD__) +# define LZO_OS_POSIX_OPENBSD 1 +# define LZO_INFO_OS_POSIX "openbsd" +# elif defined(__osf__) +# define LZO_OS_POSIX_OSF 1 +# define LZO_INFO_OS_POSIX "osf" +# elif defined(__solaris__) || defined(__sun) +# if defined(__SVR4) || defined(__svr4__) +# define LZO_OS_POSIX_SOLARIS 1 +# define LZO_INFO_OS_POSIX "solaris" +# else +# define LZO_OS_POSIX_SUNOS 1 +# define LZO_INFO_OS_POSIX "sunos" +# endif +# elif defined(__ultrix__) || defined(__ultrix) +# define LZO_OS_POSIX_ULTRIX 1 +# define LZO_INFO_OS_POSIX "ultrix" +# elif defined(_UNICOS) +# define LZO_OS_POSIX_UNICOS 1 +# define LZO_INFO_OS_POSIX "unicos" +# else +# define LZO_OS_POSIX_UNKNOWN 1 +# define LZO_INFO_OS_POSIX "unknown" +# endif +#endif +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (UINT_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) +# define LZO_CC_CILLY 1 +# define LZO_INFO_CC "Cilly" +# if defined(__CILLY__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) +# define LZO_CC_SDCC 1 +# define LZO_INFO_CC "sdcc" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC) +#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) +# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) +# define LZO_INFO_CC "Pathscale C" +# define LZO_INFO_CCVER __PATHSCALE__ +#elif defined(__INTEL_COMPILER) +# define LZO_CC_INTELC 1 +# define LZO_INFO_CC "Intel C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER) +# if defined(_WIN32) || defined(_WIN64) +# define LZO_CC_SYNTAX_MSC 1 +# else +# define LZO_CC_SYNTAX_GNUC 1 +# endif +#elif defined(__POCC__) && defined(_WIN32) +# define LZO_CC_PELLESC 1 +# define LZO_INFO_CC "Pelles C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__) +#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__) +# else +# define LZO_CC_CLANG_CLANG 0x010000L +# endif +# define LZO_CC_CLANG LZO_CC_CLANG_GNUC +# define LZO_INFO_CC "clang" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__) +# if defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# else +# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# endif +# define LZO_CC_LLVM LZO_CC_LLVM_GNUC +# define LZO_INFO_CC "llvm-gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__GNUC__) && defined(__VERSION__) +# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) +# elif defined(__GNUC_MINOR__) +# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) +# else +# define LZO_CC_GNUC (__GNUC__ * 0x10000L) +# endif +# define LZO_INFO_CC "gcc" +# define LZO_INFO_CCVER __VERSION__ +#elif defined(__ACK__) && defined(_ACK) +# define LZO_CC_ACK 1 +# define LZO_INFO_CC "Amsterdam Compiler Kit C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__AZTEC_C__) +# define LZO_CC_AZTECC 1 +# define LZO_INFO_CC "Aztec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__) +#elif defined(__CODEGEARC__) +# define LZO_CC_CODEGEARC 1 +# define LZO_INFO_CC "CodeGear C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__) +#elif defined(__BORLANDC__) +# define LZO_CC_BORLANDC 1 +# define LZO_INFO_CC "Borland C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__) +#elif defined(_CRAYC) && defined(_RELEASE) +# define LZO_CC_CRAYC 1 +# define LZO_INFO_CC "Cray C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE) +#elif defined(__DMC__) && defined(__SC__) +# define LZO_CC_DMC 1 +# define LZO_INFO_CC "Digital Mars C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__) +#elif defined(__DECC) +# define LZO_CC_DECC 1 +# define LZO_INFO_CC "DEC C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC) +#elif defined(__HIGHC__) +# define LZO_CC_HIGHC 1 +# define LZO_INFO_CC "MetaWare High C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__IAR_SYSTEMS_ICC__) +# define LZO_CC_IARC 1 +# define LZO_INFO_CC "IAR C" +# if defined(__VER__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__IBMC__) +# define LZO_CC_IBMC 1 +# define LZO_INFO_CC "IBM C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__) +#elif defined(__KEIL__) && defined(__C166__) +# define LZO_CC_KEILC 1 +# define LZO_INFO_CC "Keil C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__) +#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) +# define LZO_CC_LCCWIN32 1 +# define LZO_INFO_CC "lcc-win32" +# define LZO_INFO_CCVER "unknown" +#elif defined(__LCC__) +# define LZO_CC_LCC 1 +# define LZO_INFO_CC "lcc" +# if defined(__LCC_VERSION__) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__) +# else +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(_MSC_VER) +# define LZO_CC_MSC 1 +# define LZO_INFO_CC "Microsoft C" +# if defined(_MSC_FULL_VER) +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER) +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) +# endif +#elif defined(__MWERKS__) +# define LZO_CC_MWERKS 1 +# define LZO_INFO_CC "Metrowerks C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__) +#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) +# define LZO_CC_NDPC 1 +# define LZO_INFO_CC "Microway NDP C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PACIFIC__) +# define LZO_CC_PACIFICC 1 +# define LZO_INFO_CC "Pacific C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__) +#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) +# define LZO_CC_PGI 1 +# define LZO_INFO_CC "Portland Group PGI C" +# define LZO_INFO_CCVER "unknown" +#elif defined(__PUREC__) && defined(__TOS__) +# define LZO_CC_PUREC 1 +# define LZO_INFO_CC "Pure C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__) +#elif defined(__SC__) && defined(__ZTC__) +# define LZO_CC_SYMANTECC 1 +# define LZO_INFO_CC "Symantec C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__) +#elif defined(__SUNPRO_C) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_C)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_C +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__SUNPRO_CC) +# define LZO_INFO_CC "SunPro C" +# if ((__SUNPRO_CC)+0 > 0) +# define LZO_CC_SUNPROC __SUNPRO_CC +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC) +# else +# define LZO_CC_SUNPROC 1 +# define LZO_INFO_CCVER "unknown" +# endif +#elif defined(__TINYC__) +# define LZO_CC_TINYC 1 +# define LZO_INFO_CC "Tiny C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__) +#elif defined(__TSC__) +# define LZO_CC_TOPSPEEDC 1 +# define LZO_INFO_CC "TopSpeed C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__) +#elif defined(__WATCOMC__) +# define LZO_CC_WATCOMC 1 +# define LZO_INFO_CC "Watcom C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__) +#elif defined(__TURBOC__) +# define LZO_CC_TURBOC 1 +# define LZO_INFO_CC "Turbo C" +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__) +#elif defined(__ZTC__) +# define LZO_CC_ZORTECHC 1 +# define LZO_INFO_CC "Zortech C" +# if (__ZTC__ == 0x310) +# define LZO_INFO_CCVER "0x310" +# else +# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__) +# endif +#else +# define LZO_CC_UNKNOWN 1 +# define LZO_INFO_CC "unknown" +# define LZO_INFO_CCVER "unknown" +#endif +#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) +# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" +#endif +#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY) +# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY) +# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) +# define LZO_ARCH_CRAY_MPP 1 +# elif defined(_CRAY1) +# define LZO_ARCH_CRAY_PVP 1 +# endif +# endif +#endif +#if !defined(__LZO_ARCH_OVERRIDE) +#if (LZO_ARCH_GENERIC) +# define LZO_INFO_ARCH "generic" +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086 1 +# define LZO_ARCH_IA16 1 +# define LZO_INFO_ARCH "i086" +#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) +# define LZO_ARCH_ALPHA 1 +# define LZO_INFO_ARCH "alpha" +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) +# define LZO_ARCH_AMD64 1 +# define LZO_INFO_ARCH "amd64" +#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) +# define LZO_ARCH_ARM 1 +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) +# define LZO_ARCH_ARM 1 +# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) +# define LZO_ARCH_ARM_THUMB 1 +# define LZO_INFO_ARCH "arm_thumb" +# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) +# define LZO_INFO_ARCH "arm" +# else +# define LZO_INFO_ARCH "arm" +# endif +#elif defined(__arm__) || defined(_M_ARM) +# define LZO_ARCH_ARM 1 +# define LZO_INFO_ARCH "arm" +#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) +# define LZO_ARCH_AVR 1 +# define LZO_INFO_ARCH "avr" +#elif defined(__avr32__) || defined(__AVR32__) +# define LZO_ARCH_AVR32 1 +# define LZO_INFO_ARCH "avr32" +#elif defined(__bfin__) +# define LZO_ARCH_BLACKFIN 1 +# define LZO_INFO_ARCH "blackfin" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) +# define LZO_ARCH_C166 1 +# define LZO_INFO_ARCH "c166" +#elif defined(__cris__) +# define LZO_ARCH_CRIS 1 +# define LZO_INFO_ARCH "cris" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) +# define LZO_ARCH_EZ80 1 +# define LZO_INFO_ARCH "ez80" +#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define LZO_ARCH_H8300 1 +# define LZO_INFO_ARCH "h8300" +#elif defined(__hppa__) || defined(__hppa) +# define LZO_ARCH_HPPA 1 +# define LZO_INFO_ARCH "hppa" +#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_CC_ZORTECHC && defined(__I86__)) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) +# define LZO_ARCH_I386 1 +# define LZO_ARCH_IA32 1 +# define LZO_INFO_ARCH "i386" +#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) +# define LZO_ARCH_IA64 1 +# define LZO_INFO_ARCH "ia64" +#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) +# define LZO_ARCH_M16C 1 +# define LZO_INFO_ARCH "m16c" +#elif defined(__m32r__) +# define LZO_ARCH_M32R 1 +# define LZO_INFO_ARCH "m32r" +#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) +# define LZO_ARCH_M68K 1 +# define LZO_INFO_ARCH "m68k" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) +# define LZO_ARCH_MCS251 1 +# define LZO_INFO_ARCH "mcs251" +#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) +# define LZO_ARCH_MCS51 1 +# define LZO_INFO_ARCH "mcs51" +#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) +# define LZO_ARCH_MIPS 1 +# define LZO_INFO_ARCH "mips" +#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) +# define LZO_ARCH_MSP430 1 +# define LZO_INFO_ARCH "msp430" +#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) +# define LZO_ARCH_POWERPC 1 +# define LZO_INFO_ARCH "powerpc" +#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) +# define LZO_ARCH_S390 1 +# define LZO_INFO_ARCH "s390" +#elif defined(__sh__) || defined(_M_SH) +# define LZO_ARCH_SH 1 +# define LZO_INFO_ARCH "sh" +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) +# define LZO_ARCH_SPARC 1 +# define LZO_INFO_ARCH "sparc" +#elif defined(__SPU__) +# define LZO_ARCH_SPU 1 +# define LZO_INFO_ARCH "spu" +#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) +# define LZO_ARCH_Z80 1 +# define LZO_INFO_ARCH "z80" +#elif (LZO_ARCH_CRAY_PVP) +# if defined(_CRAYSV1) +# define LZO_ARCH_CRAY_SV1 1 +# define LZO_INFO_ARCH "cray_sv1" +# elif (_ADDR64) +# define LZO_ARCH_CRAY_T90 1 +# define LZO_INFO_ARCH "cray_t90" +# elif (_ADDR32) +# define LZO_ARCH_CRAY_YMP 1 +# define LZO_INFO_ARCH "cray_ymp" +# else +# define LZO_ARCH_CRAY_XMP 1 +# define LZO_INFO_ARCH "cray_xmp" +# endif +#else +# define LZO_ARCH_UNKNOWN 1 +# define LZO_INFO_ARCH "unknown" +#endif +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) +# error "FIXME - missing define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) +# error "FIXME - missing WIN32 define for CPU architecture" +#endif +#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) +# error "FIXME - missing WIN64 define for CPU architecture" +#endif +#if (LZO_OS_OS216 || LZO_OS_WIN16) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) +# define LZO_ARCH_I086PM 1 +# define LZO_ARCH_IA16PM 1 +#endif +#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086) +# error "this should not happen" +#endif +#if (LZO_ARCH_I086) +# if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if (LZO_ARCH_I386) +# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) +# error "this should not happen" +# endif +# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) +# error "this should not happen" +# endif +# if (ULONG_MAX != LZO_0xffffffffL) +# error "this should not happen" +# endif +#endif +#if !defined(__LZO_MM_OVERRIDE) +#if (LZO_ARCH_I086) +#if (UINT_MAX != LZO_0xffffL) +# error "this should not happen" +#endif +#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) +# define LZO_MM_TINY 1 +#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) +# define LZO_MM_HUGE 1 +#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) +# define LZO_MM_SMALL 1 +#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) +# define LZO_MM_MEDIUM 1 +#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) +# define LZO_MM_COMPACT 1 +#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) +# define LZO_MM_LARGE 1 +#elif (LZO_CC_AZTECC) +# if defined(_LARGE_CODE) && defined(_LARGE_DATA) +# define LZO_MM_LARGE 1 +# elif defined(_LARGE_CODE) +# define LZO_MM_MEDIUM 1 +# elif defined(_LARGE_DATA) +# define LZO_MM_COMPACT 1 +# else +# define LZO_MM_SMALL 1 +# endif +#elif (LZO_CC_ZORTECHC && defined(__VCM__)) +# define LZO_MM_LARGE 1 +#else +# error "unknown memory model" +#endif +#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +#define LZO_HAVE_MM_HUGE_PTR 1 +#define LZO_HAVE_MM_HUGE_ARRAY 1 +#if (LZO_MM_TINY) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) +# undef LZO_HAVE_MM_HUGE_PTR +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# undef LZO_HAVE_MM_HUGE_ARRAY +#elif (LZO_CC_MSC && defined(_QC)) +# undef LZO_HAVE_MM_HUGE_ARRAY +# if (_MSC_VER < 600) +# undef LZO_HAVE_MM_HUGE_PTR +# endif +#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) +# undef LZO_HAVE_MM_HUGE_ARRAY +#endif +#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR) +# if (LZO_OS_DOS16) +# error "this should not happen" +# elif (LZO_CC_ZORTECHC) +# else +# error "this should not happen" +# endif +#endif +#ifdef __cplusplus +extern "C" { +#endif +#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) + extern void __near __cdecl _AHSHIFT(void); +# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) +#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) +# define LZO_MM_AHSHIFT 12 +#elif (LZO_CC_WATCOMC) + extern unsigned char _HShift; +# define LZO_MM_AHSHIFT ((unsigned) _HShift) +#else +# error "FIXME - implement LZO_MM_AHSHIFT" +#endif +#ifdef __cplusplus +} +#endif +#endif +#elif (LZO_ARCH_C166) +#if !defined(__MODEL__) +# error "FIXME - C166 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - C166 __MODEL__" +#endif +#elif (LZO_ARCH_MCS251) +#if !defined(__MODEL__) +# error "FIXME - MCS251 __MODEL__" +#elif ((__MODEL__) == 0) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS251 __MODEL__" +#endif +#elif (LZO_ARCH_MCS51) +#if !defined(__MODEL__) +# error "FIXME - MCS51 __MODEL__" +#elif ((__MODEL__) == 1) +# define LZO_MM_SMALL 1 +#elif ((__MODEL__) == 2) +# define LZO_MM_LARGE 1 +#elif ((__MODEL__) == 3) +# define LZO_MM_TINY 1 +#elif ((__MODEL__) == 4) +# define LZO_MM_XTINY 1 +#elif ((__MODEL__) == 5) +# define LZO_MM_XSMALL 1 +#else +# error "FIXME - MCS51 __MODEL__" +#endif +#elif (LZO_ARCH_CRAY_PVP) +# define LZO_MM_PVP 1 +#else +# define LZO_MM_FLAT 1 +#endif +#if (LZO_MM_COMPACT) +# define LZO_INFO_MM "compact" +#elif (LZO_MM_FLAT) +# define LZO_INFO_MM "flat" +#elif (LZO_MM_HUGE) +# define LZO_INFO_MM "huge" +#elif (LZO_MM_LARGE) +# define LZO_INFO_MM "large" +#elif (LZO_MM_MEDIUM) +# define LZO_INFO_MM "medium" +#elif (LZO_MM_PVP) +# define LZO_INFO_MM "pvp" +#elif (LZO_MM_SMALL) +# define LZO_INFO_MM "small" +#elif (LZO_MM_TINY) +# define LZO_INFO_MM "tiny" +#else +# error "unknown memory model" +#endif +#endif +#if defined(SIZEOF_SHORT) +# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) +#endif +#if defined(SIZEOF_INT) +# define LZO_SIZEOF_INT (SIZEOF_INT) +#endif +#if defined(SIZEOF_LONG) +# define LZO_SIZEOF_LONG (SIZEOF_LONG) +#endif +#if defined(SIZEOF_LONG_LONG) +# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) +#endif +#if defined(SIZEOF___INT16) +# define LZO_SIZEOF___INT16 (SIZEOF___INT16) +#endif +#if defined(SIZEOF___INT32) +# define LZO_SIZEOF___INT32 (SIZEOF___INT32) +#endif +#if defined(SIZEOF___INT64) +# define LZO_SIZEOF___INT64 (SIZEOF___INT64) +#endif +#if defined(SIZEOF_VOID_P) +# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) +#endif +#if defined(SIZEOF_SIZE_T) +# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) +#endif +#if defined(SIZEOF_PTRDIFF_T) +# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) +#endif +#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) +#if !defined(LZO_SIZEOF_SHORT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_SHORT 8 +# elif (USHRT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,7) == 1) +# define LZO_SIZEOF_SHORT 1 +# elif (__LZO_LSR(USHRT_MAX,15) == 1) +# define LZO_SIZEOF_SHORT 2 +# elif (__LZO_LSR(USHRT_MAX,31) == 1) +# define LZO_SIZEOF_SHORT 4 +# elif (__LZO_LSR(USHRT_MAX,63) == 1) +# define LZO_SIZEOF_SHORT 8 +# elif (__LZO_LSR(USHRT_MAX,127) == 1) +# define LZO_SIZEOF_SHORT 16 +# else +# error "LZO_SIZEOF_SHORT" +# endif +#endif +#if !defined(LZO_SIZEOF_INT) +# if (LZO_ARCH_CRAY_PVP) +# define LZO_SIZEOF_INT 8 +# elif (UINT_MAX == LZO_0xffffL) +# define LZO_SIZEOF_INT 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,7) == 1) +# define LZO_SIZEOF_INT 1 +# elif (__LZO_LSR(UINT_MAX,15) == 1) +# define LZO_SIZEOF_INT 2 +# elif (__LZO_LSR(UINT_MAX,31) == 1) +# define LZO_SIZEOF_INT 4 +# elif (__LZO_LSR(UINT_MAX,63) == 1) +# define LZO_SIZEOF_INT 8 +# elif (__LZO_LSR(UINT_MAX,127) == 1) +# define LZO_SIZEOF_INT 16 +# else +# error "LZO_SIZEOF_INT" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,7) == 1) +# define LZO_SIZEOF_LONG 1 +# elif (__LZO_LSR(ULONG_MAX,15) == 1) +# define LZO_SIZEOF_LONG 2 +# elif (__LZO_LSR(ULONG_MAX,31) == 1) +# define LZO_SIZEOF_LONG 4 +# elif (__LZO_LSR(ULONG_MAX,63) == 1) +# define LZO_SIZEOF_LONG 8 +# elif (__LZO_LSR(ULONG_MAX,127) == 1) +# define LZO_SIZEOF_LONG 16 +# else +# error "LZO_SIZEOF_LONG" +# endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) +# if (LZO_CC_GNUC >= 0x030300ul) +# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) +# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG +# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1) +# define LZO_SIZEOF_LONG_LONG 4 +# endif +# endif +# endif +#endif +#endif +#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) +#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) +#if (LZO_ARCH_I086 && LZO_CC_DMC) +#elif (LZO_CC_CILLY) && defined(__GNUC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_SIZEOF_LONG_LONG 8 +#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_OS_WIN64 || defined(_WIN64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC)) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) +# define LZO_SIZEOF___INT64 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_LONG_LONG 8 +#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) +#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define LZO_SIZEOF_LONG_LONG 8 +#endif +#endif +#endif +#if defined(__cplusplus) && (LZO_CC_GNUC) +# if (LZO_CC_GNUC < 0x020800ul) +# undef LZO_SIZEOF_LONG_LONG +# endif +#endif +#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) +# undef LZO_SIZEOF_LONG_LONG +#endif +#if !defined(LZO_SIZEOF_VOID_P) +#if (LZO_ARCH_I086) +# define __LZO_WORDSIZE 2 +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) +# define LZO_SIZEOF_VOID_P 2 +# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) +# define LZO_SIZEOF_VOID_P 4 +# else +# error "LZO_MM" +# endif +#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) +# define __LZO_WORDSIZE 1 +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) +# define LZO_SIZEOF_VOID_P 2 +#elif (LZO_ARCH_H8300) +# if defined(__NORMAL_MODE__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 2 +# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) +# define __LZO_WORDSIZE 4 +# define LZO_SIZEOF_VOID_P 4 +# else +# define __LZO_WORDSIZE 2 +# define LZO_SIZEOF_VOID_P 2 +# endif +# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT +# endif +#elif (LZO_ARCH_M16C) +# define __LZO_WORDSIZE 2 +# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) +# define LZO_SIZEOF_VOID_P 4 +# else +# define LZO_SIZEOF_VOID_P 2 +# endif +#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 4 +#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) +# define __LZO_WORDSIZE 8 +# define LZO_SIZEOF_VOID_P 8 +#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_OS_OS400 || defined(__OS400__)) +# define __LZO_WORDSIZE LZO_SIZEOF_LONG +# define LZO_SIZEOF_VOID_P 16 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) +# define LZO_SIZEOF_VOID_P 8 +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG +#elif (LZO_ARCH_SPU) +# if 0 +# define __LZO_WORDSIZE 16 +# endif +# define LZO_SIZEOF_VOID_P 4 +#else +# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG +#endif +#endif +#if !defined(LZO_WORDSIZE) +# if defined(__LZO_WORDSIZE) +# define LZO_WORDSIZE __LZO_WORDSIZE +# else +# define LZO_WORDSIZE LZO_SIZEOF_VOID_P +# endif +#endif +#if !defined(LZO_SIZEOF_SIZE_T) +#if (LZO_ARCH_I086 || LZO_ARCH_M16C) +# define LZO_SIZEOF_SIZE_T 2 +#else +# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P +#endif +#endif +#if !defined(LZO_SIZEOF_PTRDIFF_T) +#if (LZO_ARCH_I086) +# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P +# elif (LZO_MM_COMPACT || LZO_MM_LARGE) +# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) +# define LZO_SIZEOF_PTRDIFF_T 4 +# else +# define LZO_SIZEOF_PTRDIFF_T 2 +# endif +# else +# error "LZO_MM" +# endif +#else +# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T +#endif +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# undef LZO_ABI_BIG_ENDIAN +# undef LZO_ABI_LITTLE_ENDIAN +#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN) +#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP) +# define LZO_ABI_BIG_ENDIAN 1 +#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) +# if (__LITTLE_ENDIAN__ == 1) +# define LZO_ABI_LITTLE_ENDIAN 1 +# else +# define LZO_ABI_BIG_ENDIAN 1 +# endif +#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) +# define LZO_ABI_BIG_ENDIAN 1 +#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) +# define LZO_ABI_LITTLE_ENDIAN 1 +#endif +#endif +#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN) +# error "this should not happen" +#endif +#if (LZO_ABI_BIG_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "be" +#elif (LZO_ABI_LITTLE_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "le" +#elif (LZO_ABI_NEUTRAL_ENDIAN) +# define LZO_INFO_ABI_ENDIAN "neutral" +#endif +#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_I8LP16 1 +# define LZO_INFO_ABI_PM "i8lp16" +#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) +# define LZO_ABI_ILP16 1 +# define LZO_INFO_ABI_PM "ilp16" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_ILP32 1 +# define LZO_INFO_ABI_PM "ilp32" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) +# define LZO_ABI_LLP64 1 +# define LZO_INFO_ABI_PM "llp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_LP64 1 +# define LZO_INFO_ABI_PM "lp64" +#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) +# define LZO_ABI_ILP64 1 +# define LZO_INFO_ABI_PM "ilp64" +#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) +# define LZO_ABI_IP32L64 1 +# define LZO_INFO_ABI_PM "ip32l64" +#endif +#if !defined(__LZO_LIBC_OVERRIDE) +#if (LZO_LIBC_NAKED) +# define LZO_INFO_LIBC "naked" +#elif (LZO_LIBC_FREESTANDING) +# define LZO_INFO_LIBC "freestanding" +#elif (LZO_LIBC_MOSTLY_FREESTANDING) +# define LZO_INFO_LIBC "mfreestanding" +#elif (LZO_LIBC_ISOC90) +# define LZO_INFO_LIBC "isoc90" +#elif (LZO_LIBC_ISOC99) +# define LZO_INFO_LIBC "isoc99" +#elif defined(__dietlibc__) +# define LZO_LIBC_DIETLIBC 1 +# define LZO_INFO_LIBC "dietlibc" +#elif defined(_NEWLIB_VERSION) +# define LZO_LIBC_NEWLIB 1 +# define LZO_INFO_LIBC "newlib" +#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) +# if defined(__UCLIBC_SUBLEVEL__) +# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) +# else +# define LZO_LIBC_UCLIBC 0x00090bL +# endif +# define LZO_INFO_LIBC "uclibc" +#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) +# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) +# define LZO_INFO_LIBC "glibc" +#elif (LZO_CC_MWERKS) && defined(__MSL__) +# define LZO_LIBC_MSL __MSL__ +# define LZO_INFO_LIBC "msl" +#elif 1 && defined(__IAR_SYSTEMS_ICC__) +# define LZO_LIBC_ISOC90 1 +# define LZO_INFO_LIBC "isoc90" +#else +# define LZO_LIBC_DEFAULT 1 +# define LZO_INFO_LIBC "default" +#endif +#endif +#if !defined(__lzo_gnuc_extension__) +#if (LZO_CC_GNUC >= 0x020800ul) +# define __lzo_gnuc_extension__ __extension__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_gnuc_extension__ __extension__ +#else +# define __lzo_gnuc_extension__ /*empty*/ +#endif +#endif +#if !defined(__lzo_ua_volatile) +# define __lzo_ua_volatile volatile +#endif +#if !defined(__lzo_alignof) +#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) +# define __lzo_alignof(e) __alignof__(e) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_alignof(e) __alignof(e) +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_alignof(e) __alignof__(e) +#endif +#endif +#if defined(__lzo_alignof) +# define __lzo_HAVE_alignof 1 +#endif +#if !defined(__lzo_constructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_constructor __attribute__((__constructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_constructor __attribute__((__constructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_constructor __attribute__((__constructor__)) +#endif +#endif +#if defined(__lzo_constructor) +# define __lzo_HAVE_constructor 1 +#endif +#if !defined(__lzo_destructor) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_destructor __attribute__((__destructor__,__used__)) +#elif (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_destructor __attribute__((__destructor__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_destructor __attribute__((__destructor__)) +#endif +#endif +#if defined(__lzo_destructor) +# define __lzo_HAVE_destructor 1 +#endif +#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor) +# error "this should not happen" +#endif +#if !defined(__lzo_inline) +#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) +#elif defined(__cplusplus) +# define __lzo_inline inline +#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) +# define __lzo_inline __inline +#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) +# define __lzo_inline __inline__ +#elif (LZO_CC_DMC) +# define __lzo_inline __inline +#elif (LZO_CC_INTELC) +# define __lzo_inline __inline +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) +# define __lzo_inline __inline +#elif (LZO_CC_MSC && (_MSC_VER >= 900)) +# define __lzo_inline __inline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_inline __inline__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define __lzo_inline inline +#endif +#endif +#if defined(__lzo_inline) +# define __lzo_HAVE_inline 1 +#else +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_forceinline __forceinline +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) +#endif +#endif +#if defined(__lzo_forceinline) +# define __lzo_HAVE_forceinline 1 +#else +# define __lzo_forceinline /*empty*/ +#endif +#if !defined(__lzo_noinline) +#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul) +# define __lzo_noinline __attribute__((__noinline__,__used__)) +#elif (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noinline __attribute__((__noinline__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) +# define __lzo_noinline __declspec(noinline) +#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) +# if defined(__cplusplus) +# else +# define __lzo_noinline __declspec(noinline) +# endif +#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100)) +# define __lzo_noinline __attribute__((__noinline__)) +#endif +#endif +#if defined(__lzo_noinline) +# define __lzo_HAVE_noinline 1 +#else +# define __lzo_noinline /*empty*/ +#endif +#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline) +# error "this should not happen" +#endif +#if !defined(__lzo_noreturn) +#if (LZO_CC_GNUC >= 0x020700ul) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) +# define __lzo_noreturn __declspec(noreturn) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_noreturn __attribute__((__noreturn__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) +# define __lzo_noreturn __declspec(noreturn) +#endif +#endif +#if defined(__lzo_noreturn) +# define __lzo_HAVE_noreturn 1 +#else +# define __lzo_noreturn /*empty*/ +#endif +#if !defined(__lzo_nothrow) +#if (LZO_CC_GNUC >= 0x030300ul) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_nothrow __attribute__((__nothrow__)) +#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) +# define __lzo_nothrow __declspec(nothrow) +#endif +#endif +#if defined(__lzo_nothrow) +# define __lzo_HAVE_nothrow 1 +#else +# define __lzo_nothrow /*empty*/ +#endif +#if !defined(__lzo_restrict) +#if (LZO_CC_GNUC >= 0x030400ul) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define __lzo_restrict __restrict__ +#elif (LZO_CC_MSC && (_MSC_VER >= 1400)) +# define __lzo_restrict __restrict +#endif +#endif +#if defined(__lzo_restrict) +# define __lzo_HAVE_restrict 1 +#else +# define __lzo_restrict /*empty*/ +#endif +#if !defined(__lzo_likely) && !defined(__lzo_unlikely) +#if (LZO_CC_GNUC >= 0x030200ul) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define __lzo_likely(e) (__builtin_expect(!!(e),1)) +# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) +#endif +#endif +#if defined(__lzo_likely) +# define __lzo_HAVE_likely 1 +#else +# define __lzo_likely(e) (e) +#endif +#if defined(__lzo_unlikely) +# define __lzo_HAVE_unlikely 1 +#else +# define __lzo_unlikely(e) (e) +#endif +#if !defined(LZO_UNUSED) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED(var) ((void) &var) +# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNUSED(var) ((void) var) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED(var) if (&var) ; else +# elif (LZO_CC_KEILC) +# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} +# elif (LZO_CC_PACIFICC) +# define LZO_UNUSED(var) ((void) sizeof(var)) +# elif (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED(var) ((void) var) +# else +# define LZO_UNUSED(var) ((void) &var) +# endif +#endif +#if !defined(LZO_UNUSED_FUNC) +# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) +# define LZO_UNUSED_FUNC(func) ((void) func) +# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_CLANG || LZO_CC_LLVM) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_UNUSED_FUNC(func) if (func) ; else +# elif (LZO_CC_MSC) +# define LZO_UNUSED_FUNC(func) ((void) &func) +# elif (LZO_CC_KEILC || LZO_CC_PELLESC) +# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} +# else +# define LZO_UNUSED_FUNC(func) ((void) func) +# endif +#endif +#if !defined(LZO_UNUSED_LABEL) +# if (LZO_CC_WATCOMC) && defined(__cplusplus) +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC) +# define LZO_UNUSED_LABEL(l) if (0) goto l +# else +# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l +# endif +#endif +#if !defined(LZO_DEFINE_UNINITIALIZED_VAR) +# if 0 +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var +# elif 0 && (LZO_CC_GNUC) +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var +# else +# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init +# endif +#endif +#if !defined(LZO_UNCONST_CAST) +# if 0 && defined(__cplusplus) +# define LZO_UNCONST_CAST(t,e) (const_cast (e)) +# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e)))))) +# else +# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e))))) +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) +# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; +# else +# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; +# endif +#endif +#if !defined(LZO_COMPILE_TIME_ASSERT) +# if (LZO_CC_AZTECC) +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} +# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_MSC && (_MSC_VER < 900)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) +# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; +# else +# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} +# endif +#endif +#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) +# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit /*empty*/ +# define __lzo_cdecl_main __cdecl +# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_qsort __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_qsort _stdcall +# else +# define __lzo_cdecl_qsort __cdecl +# endif +# elif (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +# else +# define __lzo_cdecl __cdecl +# define __lzo_cdecl_atexit __cdecl +# define __lzo_cdecl_main __cdecl +# define __lzo_cdecl_qsort __cdecl +# endif +# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) +# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) +# define __lzo_cdecl_sighandler __pascal +# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) +# define __lzo_cdecl_sighandler _stdcall +# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) +# define __lzo_cdecl_sighandler __clrcall +# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) +# if defined(_DLL) +# define __lzo_cdecl_sighandler _far _cdecl _loadds +# elif defined(_MT) +# define __lzo_cdecl_sighandler _far _cdecl +# else +# define __lzo_cdecl_sighandler _cdecl +# endif +# else +# define __lzo_cdecl_sighandler __cdecl +# endif +#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC) +# define __lzo_cdecl __cdecl +#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) +# define __lzo_cdecl cdecl +#endif +#if !defined(__lzo_cdecl) +# define __lzo_cdecl /*empty*/ +#endif +#if !defined(__lzo_cdecl_atexit) +# define __lzo_cdecl_atexit /*empty*/ +#endif +#if !defined(__lzo_cdecl_main) +# define __lzo_cdecl_main /*empty*/ +#endif +#if !defined(__lzo_cdecl_qsort) +# define __lzo_cdecl_qsort /*empty*/ +#endif +#if !defined(__lzo_cdecl_sighandler) +# define __lzo_cdecl_sighandler /*empty*/ +#endif +#if !defined(__lzo_cdecl_va) +# define __lzo_cdecl_va __lzo_cdecl +#endif +#if !(LZO_CFG_NO_WINDOWS_H) +#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) +# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) +# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) +# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) +# else +# define LZO_HAVE_WINDOWS_H 1 +# endif +#endif +#endif +#if (LZO_ARCH_ALPHA) +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_AMD64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# define LZO_OPT_UNALIGNED64 1 +#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) +#elif (LZO_ARCH_ARM) +# define LZO_OPT_AVOID_SHORT 1 +# define LZO_OPT_AVOID_USHORT 1 +#elif (LZO_ARCH_CRIS) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_I386) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +#elif (LZO_ARCH_IA64) +# define LZO_OPT_AVOID_INT_INDEX 1 +# define LZO_OPT_AVOID_UINT_INDEX 1 +# define LZO_OPT_PREFER_POSTINC 1 +#elif (LZO_ARCH_M68K) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if defined(__mc68020__) && !defined(__mcoldfire__) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_MIPS) +# define LZO_OPT_AVOID_UINT_INDEX 1 +#elif (LZO_ARCH_POWERPC) +# define LZO_OPT_PREFER_PREINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +# if (LZO_ABI_BIG_ENDIAN) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# endif +#elif (LZO_ARCH_S390) +# define LZO_OPT_UNALIGNED16 1 +# define LZO_OPT_UNALIGNED32 1 +# if (LZO_SIZEOF_SIZE_T == 8) +# define LZO_OPT_UNALIGNED64 1 +# endif +#elif (LZO_ARCH_SH) +# define LZO_OPT_PREFER_POSTINC 1 +# define LZO_OPT_PREFER_PREDEC 1 +#endif +#ifndef LZO_CFG_NO_INLINE_ASM +#if (LZO_CC_LLVM) +# define LZO_CFG_NO_INLINE_ASM 1 +#endif +#endif +#ifndef LZO_CFG_NO_UNALIGNED +#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC) +# define LZO_CFG_NO_UNALIGNED 1 +#endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_OPT_UNALIGNED16 +# undef LZO_OPT_UNALIGNED32 +# undef LZO_OPT_UNALIGNED64 +#endif +#if (LZO_CFG_NO_INLINE_ASM) +#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +# define LZO_ASM_SYNTAX_MSC 1 +#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) +#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul)) +#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) +# define LZO_ASM_SYNTAX_GNUC 1 +#endif +#if (LZO_ASM_SYNTAX_GNUC) +#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) +# define __LZO_ASM_CLOBBER "ax" +#elif (LZO_CC_INTELC) +# define __LZO_ASM_CLOBBER "memory" +#else +# define __LZO_ASM_CLOBBER "cc", "memory" +#endif +#endif +#if defined(__LZO_INFOSTR_MM) +#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) +# define __LZO_INFOSTR_MM "" +#elif defined(LZO_INFO_MM) +# define __LZO_INFOSTR_MM "." LZO_INFO_MM +#else +# define __LZO_INFOSTR_MM "" +#endif +#if defined(__LZO_INFOSTR_PM) +#elif defined(LZO_INFO_ABI_PM) +# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM +#else +# define __LZO_INFOSTR_PM "" +#endif +#if defined(__LZO_INFOSTR_ENDIAN) +#elif defined(LZO_INFO_ABI_ENDIAN) +# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN +#else +# define __LZO_INFOSTR_ENDIAN "" +#endif +#if defined(__LZO_INFOSTR_OSNAME) +#elif defined(LZO_INFO_OS_CONSOLE) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE +#elif defined(LZO_INFO_OS_POSIX) +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX +#else +# define __LZO_INFOSTR_OSNAME LZO_INFO_OS +#endif +#if defined(__LZO_INFOSTR_LIBC) +#elif defined(LZO_INFO_LIBC) +# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC +#else +# define __LZO_INFOSTR_LIBC "" +#endif +#if defined(__LZO_INFOSTR_CCVER) +#elif defined(LZO_INFO_CCVER) +# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER +#else +# define __LZO_INFOSTR_CCVER "" +#endif +#define LZO_INFO_STRING \ + LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ + " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER + +#endif + +#endif + +#undef LZO_HAVE_CONFIG_H +#include "minilzo.h" + +#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2050) +# error "version mismatch in miniLZO source files" +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# define LZO_HAVE_CONFIG_H 1 +#endif + +#ifndef __LZO_CONF_H +#define __LZO_CONF_H 1 + +#if !defined(__LZO_IN_MINILZO) +#if (LZO_CFG_FREESTANDING) +# define LZO_LIBC_FREESTANDING 1 +# define LZO_OS_FREESTANDING 1 +# define ACC_LIBC_FREESTANDING 1 +# define ACC_OS_FREESTANDING 1 +#endif +#if (LZO_CFG_NO_UNALIGNED) +# define ACC_CFG_NO_UNALIGNED 1 +#endif +#if (LZO_ARCH_GENERIC) +# define ACC_ARCH_GENERIC 1 +#endif +#if (LZO_ABI_NEUTRAL_ENDIAN) +# define ACC_ABI_NEUTRAL_ENDIAN 1 +#endif +#if (LZO_HAVE_CONFIG_H) +# define ACC_CONFIG_NO_HEADER 1 +#endif +#if defined(LZO_CFG_EXTRA_CONFIG_HEADER) +# include LZO_CFG_EXTRA_CONFIG_HEADER +#endif +#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED) +# error "include this file first" +#endif +#include "lzo/lzoconf.h" +#endif + +#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED) +# error "version mismatch" +#endif + +#if (LZO_CC_BORLANDC && LZO_ARCH_I086) +# pragma option -h +#endif + +#if (LZO_CC_MSC && (_MSC_VER >= 1000)) +# pragma warning(disable: 4127 4701) +#endif +#if (LZO_CC_MSC && (_MSC_VER >= 1300)) +# pragma warning(disable: 4820) +# pragma warning(disable: 4514 4710 4711) +#endif + +#if (LZO_CC_SUNPROC) +#if !defined(__cplusplus) +# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED) +# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP) +# pragma error_messages(off,E_STATEMENT_NOT_REACHED) +#endif +#endif + +#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR) +# error "this should not happen - check defines for __huge" +#endif + +#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING) +#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) +# define ACC_WANT_ACC_INCD_H 1 +# define ACC_WANT_ACC_INCE_H 1 +# define ACC_WANT_ACC_INCI_H 1 +#elif 1 +# include +#else +# define ACC_WANT_ACC_INCD_H 1 +#endif + +#if (LZO_ARCH_I086) +# define ACC_MM_AHSHIFT LZO_MM_AHSHIFT +# define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) +# define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) +# define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) +#endif + +#if !defined(lzo_uintptr_t) +# if defined(__LZO_MMODEL_HUGE) +# define lzo_uintptr_t unsigned long +# elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16) +# define __LZO_UINTPTR_T_IS_POINTER 1 + typedef char* lzo_uintptr_t; +# define lzo_uintptr_t lzo_uintptr_t +# elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t size_t +# elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned long +# elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned int +# elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P) +# define lzo_uintptr_t unsigned long long +# else +# define lzo_uintptr_t size_t +# endif +#endif +LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + +#if 1 && !defined(LZO_CFG_FREESTANDING) +#if 1 && !defined(HAVE_STRING_H) +#define HAVE_STRING_H 1 +#endif +#if 1 && !defined(HAVE_MEMCMP) +#define HAVE_MEMCMP 1 +#endif +#if 1 && !defined(HAVE_MEMCPY) +#define HAVE_MEMCPY 1 +#endif +#if 1 && !defined(HAVE_MEMMOVE) +#define HAVE_MEMMOVE 1 +#endif +#if 1 && !defined(HAVE_MEMSET) +#define HAVE_MEMSET 1 +#endif +#endif + +#if 1 && defined(HAVE_STRING_H) +#include +#endif + +#if (LZO_CFG_FREESTANDING) +# undef HAVE_MEMCMP +# undef HAVE_MEMCPY +# undef HAVE_MEMMOVE +# undef HAVE_MEMSET +#endif + +#if !(HAVE_MEMCMP) +# undef memcmp +# define memcmp(a,b,c) lzo_memcmp(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memcmp +# define lzo_memcmp(a,b,c) memcmp(a,b,c) +#endif +#if !(HAVE_MEMCPY) +# undef memcpy +# define memcpy(a,b,c) lzo_memcpy(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memcpy +# define lzo_memcpy(a,b,c) memcpy(a,b,c) +#endif +#if !(HAVE_MEMMOVE) +# undef memmove +# define memmove(a,b,c) lzo_memmove(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memmove +# define lzo_memmove(a,b,c) memmove(a,b,c) +#endif +#if !(HAVE_MEMSET) +# undef memset +# define memset(a,b,c) lzo_memset(a,b,c) +#elif !(__LZO_MMODEL_HUGE) +# undef lzo_memset +# define lzo_memset(a,b,c) memset(a,b,c) +#endif + +#undef NDEBUG +#if (LZO_CFG_FREESTANDING) +# undef LZO_DEBUG +# define NDEBUG 1 +# undef assert +# define assert(e) ((void)0) +#else +# if !defined(LZO_DEBUG) +# define NDEBUG 1 +# endif +# include +#endif + +#if 0 && defined(__BOUNDS_CHECKING_ON) +# include +#else +# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt +# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) +#endif + +#if !defined(__lzo_inline) +# define __lzo_inline /*empty*/ +#endif +#if !defined(__lzo_forceinline) +# define __lzo_forceinline /*empty*/ +#endif +#if !defined(__lzo_noinline) +# define __lzo_noinline /*empty*/ +#endif + +#if (LZO_CFG_PGO) +# undef __acc_likely +# undef __acc_unlikely +# undef __lzo_likely +# undef __lzo_unlikely +# define __acc_likely(e) (e) +# define __acc_unlikely(e) (e) +# define __lzo_likely(e) (e) +# define __lzo_unlikely(e) (e) +#endif + +#if 1 +# define LZO_BYTE(x) ((unsigned char) (x)) +#else +# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) +#endif + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) +#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) + +#define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) + +#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) + +#define LZO_SIZE(bits) (1u << (bits)) +#define LZO_MASK(bits) (LZO_SIZE(bits) - 1) + +#define LZO_LSIZE(bits) (1ul << (bits)) +#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1) + +#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) +#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) + +#if !defined(DMUL) +#if 0 + +# define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b))) +#else +# define DMUL(a,b) ((lzo_xint) ((a) * (b))) +#endif +#endif + +#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC) +# if (LZO_SIZEOF_SHORT == 2) +# define LZO_UNALIGNED_OK_2 1 +# endif +# if (LZO_SIZEOF_INT == 4) +# define LZO_UNALIGNED_OK_4 1 +# endif +#endif +#if 1 && (LZO_ARCH_AMD64) +# if defined(LZO_UINT64_MAX) +# define LZO_UNALIGNED_OK_8 1 +# endif +#endif +#if (LZO_CFG_NO_UNALIGNED) +# undef LZO_UNALIGNED_OK_2 +# undef LZO_UNALIGNED_OK_4 +# undef LZO_UNALIGNED_OK_8 +#endif + +#undef UA_GET16 +#undef UA_SET16 +#undef UA_COPY16 +#undef UA_GET32 +#undef UA_SET32 +#undef UA_COPY32 +#undef UA_GET64 +#undef UA_SET64 +#undef UA_COPY64 +#if defined(LZO_UNALIGNED_OK_2) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2) +# if 1 && defined(ACC_UA_COPY16) +# define UA_GET16 ACC_UA_GET16 +# define UA_SET16 ACC_UA_SET16 +# define UA_COPY16 ACC_UA_COPY16 +# else +# define UA_GET16(p) (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET16(p,v) ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v)) +# define UA_COPY16(d,s) UA_SET16(d, UA_GET16(s)) +# endif +#endif +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4) +# if 1 && defined(ACC_UA_COPY32) +# define UA_GET32 ACC_UA_GET32 +# define UA_SET32 ACC_UA_SET32 +# define UA_COPY32 ACC_UA_COPY32 +# else +# define UA_GET32(p) (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET32(p,v) ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v)) +# define UA_COPY32(d,s) UA_SET32(d, UA_GET32(s)) +# endif +#endif +#if defined(LZO_UNALIGNED_OK_8) + LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8) +# if 1 && defined(ACC_UA_COPY64) +# define UA_GET64 ACC_UA_GET64 +# define UA_SET64 ACC_UA_SET64 +# define UA_COPY64 ACC_UA_COPY64 +# else +# define UA_GET64(p) (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p)) +# define UA_SET64(p,v) ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v)) +# define UA_COPY64(d,s) UA_SET64(d, UA_GET64(s)) +# endif +#endif + +#define MEMCPY8_DS(dest,src,len) \ + lzo_memcpy(dest,src,len); dest += len; src += len + +#define BZERO8_PTR(s,l,n) \ + lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) + +#define MEMCPY_DS(dest,src,len) \ + do *dest++ = *src++; while (--len > 0) + +LZO_EXTERN(const lzo_bytep) lzo_copyright(void); + +#ifndef __LZO_PTR_H +#define __LZO_PTR_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(lzo_uintptr_t) +# if (__LZO_MMODEL_HUGE) +# define lzo_uintptr_t unsigned long +# else +# define lzo_uintptr_t acc_uintptr_t +# ifdef __ACC_INTPTR_T_IS_POINTER +# define __LZO_UINTPTR_T_IS_POINTER 1 +# endif +# endif +#endif + +#if (LZO_ARCH_I086) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_4(a) ((ACC_PTR_FP_OFF(a) & 3) == 0) +#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0) +#elif (LZO_MM_PVP) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_8(a) ((((lzo_uintptr_t)(a)) >> 61) == 0) +#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0) +#else +#define PTR(a) ((lzo_uintptr_t) (a)) +#define PTR_LINEAR(a) PTR(a) +#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) +#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) +#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) +#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) +#endif + +#define PTR_LT(a,b) (PTR(a) < PTR(b)) +#define PTR_GE(a,b) (PTR(a) >= PTR(b)) +#define PTR_DIFF(a,b) (PTR(a) - PTR(b)) +#define pd(a,b) ((lzo_uint) ((a)-(b))) + +LZO_EXTERN(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr); + +typedef union +{ + char a_char; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long a_long; + unsigned long a_ulong; + lzo_int a_lzo_int; + lzo_uint a_lzo_uint; + lzo_int32 a_lzo_int32; + lzo_uint32 a_lzo_uint32; +#if defined(LZO_UINT64_MAX) + lzo_int64 a_lzo_int64; + lzo_uint64 a_lzo_uint64; +#endif + ptrdiff_t a_ptrdiff_t; + lzo_uintptr_t a_lzo_uintptr_t; + lzo_voidp a_lzo_voidp; + void * a_void_p; + lzo_bytep a_lzo_bytep; + lzo_bytepp a_lzo_bytepp; + lzo_uintp a_lzo_uintp; + lzo_uint * a_lzo_uint_p; + lzo_uint32p a_lzo_uint32p; + lzo_uint32 * a_lzo_uint32_p; + unsigned char * a_uchar_p; + char * a_char_p; +} +lzo_full_align_t; + +#ifdef __cplusplus +} +#endif + +#endif + +#ifndef LZO_DETERMINISTIC +#define LZO_DETERMINISTIC 1 +#endif + +#ifndef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 1 +#if 0 && (LZO_ARCH_I086) +# undef LZO_DICT_USE_PTR +# define LZO_DICT_USE_PTR 0 +#endif +#endif + +#if (LZO_DICT_USE_PTR) +# define lzo_dict_t const lzo_bytep +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#else +# define lzo_dict_t lzo_uint +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#endif + +#endif + +#if !defined(MINILZO_CFG_SKIP_LZO_PTR) + +LZO_PUBLIC(lzo_uintptr_t) +__lzo_ptr_linear(const lzo_voidp ptr) +{ + lzo_uintptr_t p; + +#if (LZO_ARCH_I086) + p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr)); +#elif (LZO_MM_PVP) + p = (lzo_uintptr_t) (ptr); + p = (p << 3) | (p >> 61); +#else + p = (lzo_uintptr_t) PTR_LINEAR(ptr); +#endif + + return p; +} + +LZO_PUBLIC(unsigned) +__lzo_align_gap(const lzo_voidp ptr, lzo_uint size) +{ +#if defined(__LZO_UINTPTR_T_IS_POINTER) + size_t n = (size_t) ptr; + n = (((n + size - 1) / size) * size) - n; +#else + lzo_uintptr_t p, n; + p = __lzo_ptr_linear(ptr); + n = (((p + size - 1) / size) * size) - p; +#endif + + assert(size > 0); + assert((long)n >= 0); + assert(n <= size); + return (unsigned)n; +} + +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_UTIL) + +/* If you use the LZO library in a product, I would appreciate that you + * keep this copyright string in the executable of your product. + */ + +static const char __lzo_copyright[] = +#if !defined(__LZO_IN_MINLZO) + LZO_VERSION_STRING; +#else + "\r\n\n" + "LZO data compression library.\n" + "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n" + "\n" + "http://www.oberhumer.com $\n\n" + "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n" + "$Info: " LZO_INFO_STRING " $\n"; +#endif + +LZO_PUBLIC(const lzo_bytep) +lzo_copyright(void) +{ +#if (LZO_OS_DOS16 && LZO_CC_TURBOC) + return (lzo_voidp) __lzo_copyright; +#else + return (const lzo_bytep) __lzo_copyright; +#endif +} + +LZO_PUBLIC(unsigned) +lzo_version(void) +{ + return LZO_VERSION; +} + +LZO_PUBLIC(const char *) +lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const char *) +lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +#define LZO_BASE 65521u +#define LZO_NMAX 5552 + +#define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1 +#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1); +#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2); +#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4); +#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8); + +LZO_PUBLIC(lzo_uint32) +lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len) +{ + lzo_uint32 s1 = adler & 0xffff; + lzo_uint32 s2 = (adler >> 16) & 0xffff; + unsigned k; + + if (buf == NULL) + return 1; + + while (len > 0) + { + k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; + len -= k; + if (k >= 16) do + { + LZO_DO16(buf,0); + buf += 16; + k -= 16; + } while (k >= 16); + if (k != 0) do + { + s1 += *buf++; + s2 += s1; + } while (--k > 0); + s1 %= LZO_BASE; + s2 %= LZO_BASE; + } + return (s2 << 16) | s1; +} + +#undef LZO_DO1 +#undef LZO_DO2 +#undef LZO_DO4 +#undef LZO_DO8 +#undef LZO_DO16 + +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_STRING) +#undef lzo_memcmp +#undef lzo_memcpy +#undef lzo_memmove +#undef lzo_memset +#if !defined(__LZO_MMODEL_HUGE) +# undef LZO_HAVE_MM_HUGE_PTR +#endif +#define lzo_hsize_t lzo_uint +#define lzo_hvoid_p lzo_voidp +#define lzo_hbyte_p lzo_bytep +#define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f +#define lzo_hmemcmp lzo_memcmp +#define lzo_hmemcpy lzo_memcpy +#define lzo_hmemmove lzo_memmove +#define lzo_hmemset lzo_memset +#define __LZOLIB_HMEMCPY_CH_INCLUDED 1 +#if !defined(LZOLIB_PUBLIC) +# define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f) +#endif +LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP) + const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2; + if __lzo_likely(len > 0) do + { + int d = *p1 - *p2; + if (d != 0) + return d; + p1++; p2++; + } while __lzo_likely(--len > 0); + return 0; +#else + return memcmp(s1, s2, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY) + lzo_hbyte_p p1 = (lzo_hbyte_p) dest; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; + if (!(len > 0) || p1 == p2) + return dest; + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + return dest; +#else + return memcpy(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE) + lzo_hbyte_p p1 = (lzo_hbyte_p) dest; + const lzo_hbyte_p p2 = (const lzo_hbyte_p) src; + if (!(len > 0) || p1 == p2) + return dest; + if (p1 < p2) + { + do + *p1++ = *p2++; + while __lzo_likely(--len > 0); + } + else + { + p1 += len; + p2 += len; + do + *--p1 = *--p2; + while __lzo_likely(--len > 0); + } + return dest; +#else + return memmove(dest, src, len); +#endif +} +LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len) +{ +#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET) + lzo_hbyte_p p = (lzo_hbyte_p) s; + if __lzo_likely(len > 0) do + *p++ = (unsigned char) c; + while __lzo_likely(--len > 0); + return s; +#else + return memset(s, c, len); +#endif +} +#undef LZOLIB_PUBLIC +#endif +#if !defined(MINILZO_CFG_SKIP_LZO_INIT) + +#if !defined(__LZO_IN_MINILZO) + +#define ACC_WANT_ACC_CHK_CH 1 +#undef ACCCHK_ASSERT + + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint) + + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32) + ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0) + ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4) +#if defined(LZO_UINT64_MAX) + ACCCHK_ASSERT(sizeof(lzo_uint64) == 8) + ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64) +#endif + +#if !defined(__LZO_UINTPTR_T_IS_POINTER) + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t) +#endif + ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp)) + + ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint) + ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32)) + ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint)) + ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint)) + +#endif +#undef ACCCHK_ASSERT + +#if 0 +#define WANT_lzo_bitops_clz32 1 +#define WANT_lzo_bitops_clz64 1 +#endif +#define WANT_lzo_bitops_ctz32 1 +#define WANT_lzo_bitops_ctz64 1 + +#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#include +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 +#pragma intrinsic(_BitScanReverse) +static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanReverse(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz32 lzo_bitops_clz32 +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 +#pragma intrinsic(_BitScanReverse64) +static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanReverse64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz64 lzo_bitops_clz64 +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#pragma intrinsic(_BitScanForward) +static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanForward(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz32 lzo_bitops_ctz32 +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#pragma intrinsic(_BitScanForward64) +static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanForward64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz64 lzo_bitops_ctz64 +#endif + +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM) +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) +#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) +#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) +#endif +#endif + +#if 0 +#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off))) +#else +static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off) +{ + return (lzo_voidp) ((lzo_bytep) ptr + off); +} +#endif + +LZO_PUBLIC(int) +_lzo_config_check(void) +{ + lzo_bool r = 1; + union { + lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))]; +#if defined(LZO_UNALIGNED_OK_8) + lzo_uint64 c[2]; +#endif + unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2]; + } u; + lzo_voidp p; + + u.a[0] = u.a[1] = 0; + p = u2p(&u, 0); + r &= ((* (lzo_bytep) p) == 0); +#if !defined(LZO_CFG_NO_CONFIG_CHECK) +#if defined(LZO_ABI_BIG_ENDIAN) + u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); +#endif +#if defined(LZO_ABI_LITTLE_ENDIAN) + u.a[0] = u.a[1] = 0; u.b[0] = 128; + p = u2p(&u, 0); + r &= ((* (lzo_uintp) p) == 128); +#endif +#if defined(LZO_UNALIGNED_OK_2) + u.a[0] = u.a[1] = 0; + u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2; + p = u2p(&u, 1); + r &= ((* (lzo_ushortp) p) == 0); +#endif +#if defined(LZO_UNALIGNED_OK_4) + u.a[0] = u.a[1] = 0; + u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4; + p = u2p(&u, 1); + r &= ((* (lzo_uint32p) p) == 0); +#endif +#if defined(LZO_UNALIGNED_OK_8) + u.c[0] = u.c[1] = 0; + u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6; + p = u2p(&u, 1); + r &= ((* (lzo_uint64p) p) == 0); +#endif +#if defined(lzo_bitops_clz32) + { unsigned i; lzo_uint32 v = 1; + for (i = 0; i < 31; i++, v <<= 1) + r &= lzo_bitops_clz32(v) == 31 - i; + } +#endif +#if defined(lzo_bitops_clz64) + { unsigned i; lzo_uint64 v = 1; + for (i = 0; i < 63; i++, v <<= 1) + r &= lzo_bitops_clz64(v) == 63 - i; + } +#endif +#if defined(lzo_bitops_ctz32) + { unsigned i; lzo_uint32 v = 1; + for (i = 0; i < 31; i++, v <<= 1) + r &= lzo_bitops_ctz32(v) == i; + } +#endif +#if defined(lzo_bitops_ctz64) + { unsigned i; lzo_uint64 v = 1; + for (i = 0; i < 63; i++, v <<= 1) + r &= lzo_bitops_ctz64(v) == i; + } +#endif +#endif + + return r == 1 ? LZO_E_OK : LZO_E_ERROR; +} + +LZO_PUBLIC(int) +__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5, + int s6, int s7, int s8, int s9) +{ + int r; + +#if defined(__LZO_IN_MINILZO) +#elif (LZO_CC_MSC && ((_MSC_VER) < 700)) +#else +#define ACC_WANT_ACC_CHK_CH 1 +#undef ACCCHK_ASSERT +#define ACCCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) +#endif +#undef ACCCHK_ASSERT + + if (v == 0) + return LZO_E_ERROR; + + r = (s1 == -1 || s1 == (int) sizeof(short)) && + (s2 == -1 || s2 == (int) sizeof(int)) && + (s3 == -1 || s3 == (int) sizeof(long)) && + (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) && + (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && + (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && + (s7 == -1 || s7 == (int) sizeof(char *)) && + (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && + (s9 == -1 || s9 == (int) sizeof(lzo_callback_t)); + if (!r) + return LZO_E_ERROR; + + r = _lzo_config_check(); + if (r != LZO_E_OK) + return r; + + return r; +} + +#if !defined(__LZO_IN_MINILZO) + +#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD) + +#if 0 +BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment, + WORD wHeapSize, LPSTR lpszCmdLine ) +#else +int __far __pascal LibMain ( int a, short b, short c, long d ) +#endif +{ + LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d); + return 1; +} + +#endif + +#endif + +#endif + +#define LZO1X 1 +#define LZO_EOF_CODE 1 +#define M2_MAX_OFFSET 0x0800 + +#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS) + +#if 1 && defined(UA_GET32) +#undef LZO_DICT_USE_PTR +#define LZO_DICT_USE_PTR 0 +#undef lzo_dict_t +#define lzo_dict_t unsigned short +#endif + +#define LZO_NEED_DICT_H 1 +#ifndef D_BITS +#define D_BITS 14 +#endif +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) +#if 1 +#define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS))) +#else +#define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS))) +#endif + +#ifndef __LZO_CONFIG1X_H +#define __LZO_CONFIG1X_H 1 + +#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) +# define LZO1X 1 +#endif + +#if !defined(__LZO_IN_MINILZO) +#include "lzo/lzo1x.h" +#endif + +#ifndef LZO_EOF_CODE +#define LZO_EOF_CODE 1 +#endif +#undef LZO_DETERMINISTIC + +#define M1_MAX_OFFSET 0x0400 +#ifndef M2_MAX_OFFSET +#define M2_MAX_OFFSET 0x0800 +#endif +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) + +#define M1_MIN_LEN 2 +#define M1_MAX_LEN 2 +#define M2_MIN_LEN 3 +#ifndef M2_MAX_LEN +#define M2_MAX_LEN 8 +#endif +#define M3_MIN_LEN 3 +#define M3_MAX_LEN 33 +#define M4_MIN_LEN 3 +#define M4_MAX_LEN 9 + +#define M1_MARKER 0 +#define M2_MARKER 64 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#ifndef MIN_LOOKAHEAD +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) +#endif + +#if defined(LZO_NEED_DICT_H) + +#ifndef LZO_HASH +#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B +#endif +#define DL_MIN_LEN M2_MIN_LEN + +#ifndef __LZO_DICT_H +#define __LZO_DICT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(D_BITS) && defined(DBITS) +# define D_BITS DBITS +#endif +#if !defined(D_BITS) +# error "D_BITS is not defined" +#endif +#if (D_BITS < 16) +# define D_SIZE LZO_SIZE(D_BITS) +# define D_MASK LZO_MASK(D_BITS) +#else +# define D_SIZE LZO_USIZE(D_BITS) +# define D_MASK LZO_UMASK(D_BITS) +#endif +#define D_HIGH ((D_MASK >> 1) + 1) + +#if !defined(DD_BITS) +# define DD_BITS 0 +#endif +#define DD_SIZE LZO_SIZE(DD_BITS) +#define DD_MASK LZO_MASK(DD_BITS) + +#if !defined(DL_BITS) +# define DL_BITS (D_BITS - DD_BITS) +#endif +#if (DL_BITS < 16) +# define DL_SIZE LZO_SIZE(DL_BITS) +# define DL_MASK LZO_MASK(DL_BITS) +#else +# define DL_SIZE LZO_USIZE(DL_BITS) +# define DL_MASK LZO_UMASK(DL_BITS) +#endif + +#if (D_BITS != DL_BITS + DD_BITS) +# error "D_BITS does not match" +#endif +#if (D_BITS < 6 || D_BITS > 18) +# error "invalid D_BITS" +#endif +#if (DL_BITS < 6 || DL_BITS > 20) +# error "invalid DL_BITS" +#endif +#if (DD_BITS < 0 || DD_BITS > 6) +# error "invalid DD_BITS" +#endif + +#if !defined(DL_MIN_LEN) +# define DL_MIN_LEN 3 +#endif +#if !defined(DL_SHIFT) +# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) +#endif + +#define LZO_HASH_GZIP 1 +#define LZO_HASH_GZIP_INCREMENTAL 2 +#define LZO_HASH_LZO_INCREMENTAL_A 3 +#define LZO_HASH_LZO_INCREMENTAL_B 4 + +#if !defined(LZO_HASH) +# error "choose a hashing strategy" +#endif + +#undef DM +#undef DX + +#if (DL_MIN_LEN == 3) +# define _DV2_A(p,shift1,shift2) \ + (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) +# define _DV2_B(p,shift1,shift2) \ + (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) +# define _DV3_B(p,shift1,shift2,shift3) \ + ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) +#elif (DL_MIN_LEN == 2) +# define _DV2_A(p,shift1,shift2) \ + (( (lzo_xint)(p[0]) << shift1) ^ p[1]) +# define _DV2_B(p,shift1,shift2) \ + (( (lzo_xint)(p[1]) << shift1) ^ p[2]) +#else +# error "invalid DL_MIN_LEN" +#endif +#define _DV_A(p,shift) _DV2_A(p,shift,shift) +#define _DV_B(p,shift) _DV2_B(p,shift,shift) +#define DA2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) +#define DS2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) +#define DX2(p,s1,s2) \ + (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) +#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) DMS(v,0) + +#if (LZO_HASH == LZO_HASH_GZIP) +# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) + +#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) +# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) +# define _DINDEX(dv,p) (dv) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_A((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) +# define __LZO_HASH_INCREMENTAL 1 +# define DVAL_FIRST(dv,p) dv = _DV_B((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5))) +# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#else +# error "choose a hashing strategy" +#endif + +#ifndef DINDEX +#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) +#endif +#if !defined(DINDEX1) && defined(D_INDEX1) +#define DINDEX1 D_INDEX1 +#endif +#if !defined(DINDEX2) && defined(D_INDEX2) +#define DINDEX2 D_INDEX2 +#endif + +#if !defined(__LZO_HASH_INCREMENTAL) +# define DVAL_FIRST(dv,p) ((void) 0) +# define DVAL_NEXT(dv,p) ((void) 0) +# define DVAL_LOOKAHEAD 0 +#endif + +#if !defined(DVAL_ASSERT) +#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) +#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM) +static void __attribute__((__unused__)) +#else +static void +#endif +DVAL_ASSERT(lzo_xint dv, const lzo_bytep p) +{ + lzo_xint df; + DVAL_FIRST(df,(p)); + assert(DINDEX(dv,p) == DINDEX(df,p)); +} +#else +# define DVAL_ASSERT(dv,p) ((void) 0) +#endif +#endif + +#if (LZO_DICT_USE_PTR) +# define DENTRY(p,in) (p) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#else +# define DENTRY(p,in) ((lzo_dict_t) pd(p, in)) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] +#endif + +#if (DD_BITS == 0) + +# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) +# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) +# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) + +#else + +# define UPDATE_D(dict,drun,dv,p,in) \ + dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_I(dict,drun,index,p,in) \ + dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_P(ptr,drun,p,in) \ + (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK + +#endif + +#if (LZO_DICT_USE_PTR) + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (BOUNDS_CHECKING_OFF_IN_EXPR(( \ + m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \ + PTR_LT(m_pos,in) || \ + (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \ + m_off > max_offset ))) + +#else + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_off == 0 || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (pd(ip, in) <= m_off || \ + ((m_off = pd(ip, in) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#endif + +#if (LZO_DETERMINISTIC) +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET +#else +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +#endif + +#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR) + +#ifndef DO_COMPRESS +#define DO_COMPRESS lzo1x_1_compress +#endif + +#if 1 && defined(DO_COMPRESS) && !defined(do_compress) +# define do_compress LZO_CPP_ECONCAT2(DO_COMPRESS,_core) +#endif + +#if defined(UA_GET64) +# define WANT_lzo_bitops_ctz64 1 +#elif defined(UA_GET32) +# define WANT_lzo_bitops_ctz32 1 +#endif + +#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400))) +#include +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0 +#pragma intrinsic(_BitScanReverse) +static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanReverse(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz32 lzo_bitops_clz32 +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0 +#pragma intrinsic(_BitScanReverse64) +static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanReverse64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_clz64 lzo_bitops_clz64 +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#pragma intrinsic(_BitScanForward) +static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v) +{ + unsigned long r; + (void) _BitScanForward(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz32 lzo_bitops_ctz32 +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#pragma intrinsic(_BitScanForward64) +static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v) +{ + unsigned long r; + (void) _BitScanForward64(&r, v); + return (unsigned) r; +} +#define lzo_bitops_ctz64 lzo_bitops_ctz64 +#endif + +#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM) +#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) +#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v)) +#endif +#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v)) +#endif +#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32) +#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v)) +#endif +#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32) +#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v)) +#endif +#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX) +#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v)) +#endif +#endif + +static __lzo_noinline lzo_uint +do_compress ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_uint ti, lzo_voidp wrkmem) +{ + register const lzo_bytep ip; + lzo_bytep op; + const lzo_bytep const in_end = in + in_len; + const lzo_bytep const ip_end = in + in_len - 20; + const lzo_bytep ii; + lzo_dict_p const dict = (lzo_dict_p) wrkmem; + + op = out; + ip = in; + ii = ip - ti; + + ip += ti < 4 ? 4 - ti : 0; + for (;;) + { + const lzo_bytep m_pos; +#if !(LZO_DETERMINISTIC) + LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0); + lzo_uint m_len; + lzo_uint dindex; +next: + if __lzo_unlikely(ip >= ip_end) + break; + DINDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + DINDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + +try_match: +#if defined(UA_GET32) + if (UA_GET32(m_pos) != UA_GET32(ip)) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3]) +#endif + { +literal: + UPDATE_I(dict,0,dindex,ip,in); + ip += 1 + ((ip - ii) >> 5); + continue; + } + UPDATE_I(dict,0,dindex,ip,in); +#else + lzo_uint m_off; + lzo_uint m_len; + { + lzo_uint32 dv; + lzo_uint dindex; +literal: + ip += 1 + ((ip - ii) >> 5); +next: + if __lzo_unlikely(ip >= ip_end) + break; + dv = UA_GET32(ip); + dindex = DINDEX(dv,ip); + GINDEX(m_off,m_pos,in+dict,dindex,in); + UPDATE_I(dict,0,dindex,ip,in); + if __lzo_unlikely(dv != UA_GET32(m_pos)) + goto literal; + } +#endif + + { + register lzo_uint t = pd(ip,ii); + if (t != 0) + { + if (t <= 3) + { + op[-2] |= LZO_BYTE(t); +#if defined(UA_COPY32) + UA_COPY32(op, ii); + op += t; +#else + { do *op++ = *ii++; while (--t > 0); } +#endif + } +#if defined(UA_COPY32) || defined(UA_COPY64) + else if (t <= 16) + { + *op++ = LZO_BYTE(t - 3); +#if defined(UA_COPY64) + UA_COPY64(op, ii); + UA_COPY64(op+8, ii+8); +#else + UA_COPY32(op, ii); + UA_COPY32(op+4, ii+4); + UA_COPY32(op+8, ii+8); + UA_COPY32(op+12, ii+12); +#endif + op += t; + } +#endif + else + { + if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + register lzo_uint tt = t - 18; + *op++ = 0; + while __lzo_unlikely(tt > 255) + { + tt -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } +#if defined(UA_COPY32) || defined(UA_COPY64) + do { +#if defined(UA_COPY64) + UA_COPY64(op, ii); + UA_COPY64(op+8, ii+8); +#else + UA_COPY32(op, ii); + UA_COPY32(op+4, ii+4); + UA_COPY32(op+8, ii+8); + UA_COPY32(op+12, ii+12); +#endif + op += 16; ii += 16; t -= 16; + } while (t >= 16); if (t > 0) +#endif + { do *op++ = *ii++; while (--t > 0); } + } + } + } + m_len = 4; + { +#if defined(UA_GET64) + lzo_uint64 v; + v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 8; + v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64) + m_len += lzo_bitops_ctz64(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#elif defined(UA_GET32) + lzo_uint32 v; + v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); + if __lzo_unlikely(v == 0) { + do { + m_len += 4; + v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len); + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (v == 0); + } +#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32) + m_len += lzo_bitops_ctz32(v) / CHAR_BIT; +#elif (LZO_ABI_LITTLE_ENDIAN) + if ((v & UCHAR_MAX) == 0) do { + v >>= CHAR_BIT; + m_len += 1; + } while ((v & UCHAR_MAX) == 0); +#else + if (ip[m_len] == m_pos[m_len]) do { + m_len += 1; + } while (ip[m_len] == m_pos[m_len]); +#endif +#else + if __lzo_unlikely(ip[m_len] == m_pos[m_len]) { + do { + m_len += 1; + if __lzo_unlikely(ip + m_len >= ip_end) + goto m_len_done; + } while (ip[m_len] == m_pos[m_len]); + } +#endif + } +m_len_done: + m_off = pd(ip,m_pos); + ip += m_len; + ii = ip; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) + { + m_off -= 1; +#if defined(LZO1X) + *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = LZO_BYTE(m_off >> 3); +#elif defined(LZO1Y) + *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + if (m_len <= M3_MAX_LEN) + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + else + { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + else + { + m_off -= 0x4000; + if (m_len <= M4_MAX_LEN) + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); + else + { + m_len -= M4_MAX_LEN; + *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8)); + while __lzo_unlikely(m_len > 255) + { + m_len -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + *op++ = LZO_BYTE(m_len); + } + *op++ = LZO_BYTE(m_off << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + goto next; + } + + *out_len = pd(op, out); + return pd(in_end,ii); +} + +LZO_PUBLIC(int) +DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ + const lzo_bytep ip = in; + lzo_bytep op = out; + lzo_uint l = in_len; + lzo_uint t = 0; + + while (l > 20) + { + lzo_uint ll = l; + lzo_uintptr_t ll_end; +#if 0 || (LZO_DETERMINISTIC) + ll = LZO_MIN(ll, 49152); +#endif + ll_end = (lzo_uintptr_t)ip + ll; + if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll) + break; +#if (LZO_DETERMINISTIC) + lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t)); +#endif + t = do_compress(ip,ll,op,out_len,t,wrkmem); + ip += ll; + op += *out_len; + l -= ll; + } + t += l; + + if (t > 0) + { + const lzo_bytep ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = LZO_BYTE(17 + t); + else if (t <= 3) + op[-2] |= LZO_BYTE(t); + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; +#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400)) + + * (volatile unsigned char *) op++ = 0; +#else + *op++ = 0; +#endif + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return LZO_E_OK; +} + +#endif + +#undef do_compress +#undef DO_COMPRESS +#undef LZO_HASH + +#undef LZO_TEST_OVERRUN +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP 1 +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP 1 +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP 1 +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP 1 +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP 1 +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP 1 +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_bytep op; + register const lzo_bytep ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + register const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + t += 3; + if (t >= 8) do + { + UA_COPY64(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + UA_COPY32(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + do { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY64(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +#define LZO_TEST_OVERRUN 1 +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress_safe + +#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE) + +#if defined(LZO_TEST_OVERRUN) +# if !defined(LZO_TEST_OVERRUN_INPUT) +# define LZO_TEST_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_OUTPUT) +# define LZO_TEST_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define LZO_TEST_OVERRUN_LOOKBEHIND 1 +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LB +#undef TEST_LBO +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_OVERRUN_INPUT) +# if (LZO_TEST_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_OUTPUT) +# if (LZO_TEST_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +#else +# define TEST_LB(m_pos) ((void) 0) +# define TEST_LBO(m_pos,o) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP 1 +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP 1 +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP 1 +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP 1 +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP 1 +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP 1 +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, + lzo_bytep out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_bytep op; + register const lzo_bytep ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_bytep dict_end; +#else + register const lzo_bytep m_pos; +#endif + + const lzo_bytep const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_bytep const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + t += 3; + if (t >= 8) do + { + UA_COPY64(op,ip); + op += 8; ip += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } + if (t > 0) + { + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } + } +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + UA_COPY32(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + UA_COPY32(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + do { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= UA_GET16(ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const lzo_bytep)op, m_pos); +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4) + if (op - m_pos >= 8) + { + t += (3 - 1); + if (t >= 8) do + { + UA_COPY64(op,m_pos); + op += 8; m_pos += 8; t -= 8; + } while (t >= 8); + if (t >= 4) + { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } + if (t > 0) + { + *op++ = m_pos[0]; + if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } + } + } + else +#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + UA_COPY32(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#endif + +/***** End of minilzo.c *****/ + diff --git a/grub-core/lib/minilzo/minilzo.h b/grub-core/lib/minilzo/minilzo.h new file mode 100644 index 000000000..74fefa9fe --- /dev/null +++ b/grub-core/lib/minilzo/minilzo.h @@ -0,0 +1,109 @@ +/* minilzo.h -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library 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 the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __MINILZO_H +#define __MINILZO_H 1 + +#define MINILZO_VERSION 0x2050 + +#ifdef __LZOCONF_H +# error "you cannot use both LZO and miniLZO" +#endif + +#undef LZO_HAVE_CONFIG_H +#include "lzoconf.h" + +#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION) +# error "version mismatch in header files" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// +************************************************************************/ + +/* Memory required for the wrkmem parameter. + * When the required size is 0, you can also pass a NULL pointer. + */ + +#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS +#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) +#define LZO1X_MEM_DECOMPRESS (0) + + +/* compression */ +LZO_EXTERN(int) +lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +/* decompression */ +LZO_EXTERN(int) +lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + +/* safe decompression with overrun testing */ +LZO_EXTERN(int) +lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, + lzo_bytep dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + diff --git a/grub-core/lib/mips/arc/reboot.c b/grub-core/lib/mips/arc/reboot.c new file mode 100644 index 000000000..ecf12a7ed --- /dev/null +++ b/grub-core/lib/mips/arc/reboot.c @@ -0,0 +1,35 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +void +grub_reboot (void) +{ + GRUB_ARC_FIRMWARE_VECTOR->restart (); + + grub_millisleep (1500); + + grub_puts_ (N_("Reboot failed")); + grub_refresh (); + while (1); +} diff --git a/grub-core/lib/mips/loongson/reboot.c b/grub-core/lib/mips/loongson/reboot.c new file mode 100644 index 000000000..1b510784b --- /dev/null +++ b/grub-core/lib/mips/loongson/reboot.c @@ -0,0 +1,58 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +void +grub_reboot (void) +{ + switch (grub_arch_machine) + { + case GRUB_ARCH_MACHINE_FULOONG2E: + grub_outb (grub_inb (0xbfe00104) & ~4, 0xbfe00104); + grub_outb (grub_inb (0xbfe00104) | 4, 0xbfe00104); + break; + case GRUB_ARCH_MACHINE_FULOONG2F: + { + grub_pci_device_t dev; + if (!grub_cs5536_find (&dev)) + break; + grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_RESET, + grub_cs5536_read_msr (dev, + GRUB_CS5536_MSR_DIVIL_RESET) + | 1); + break; + } + case GRUB_ARCH_MACHINE_YEELOONG: + grub_write_ec (GRUB_MACHINE_EC_COMMAND_REBOOT); + break; + } + grub_millisleep (1500); + + grub_puts_ (N_("Reboot failed")); + grub_refresh (); + while (1); +} diff --git a/grub-core/lib/mips/qemu_mips/reboot.c b/grub-core/lib/mips/qemu_mips/reboot.c new file mode 100644 index 000000000..a5c41ee78 --- /dev/null +++ b/grub-core/lib/mips/qemu_mips/reboot.c @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +void +grub_reboot (void) +{ + while (1); +} diff --git a/grub-core/lib/mips/setjmp.S b/grub-core/lib/mips/setjmp.S index 8ab6222c4..8259c9d22 100644 --- a/grub-core/lib/mips/setjmp.S +++ b/grub-core/lib/mips/setjmp.S @@ -17,9 +17,12 @@ */ #include +#include .file "setjmp.S" +GRUB_MOD_LICENSE ("GPLv3+") + .text /* diff --git a/grub-core/lib/pbkdf2.c b/grub-core/lib/pbkdf2.c index 083446ab9..09b8c7360 100644 --- a/grub-core/lib/pbkdf2.c +++ b/grub-core/lib/pbkdf2.c @@ -21,6 +21,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv2+"); /* 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/grub-core/lib/posix_wrap/assert.h b/grub-core/lib/posix_wrap/assert.h index 94cfdd543..6b00a0ba3 100644 --- a/grub-core/lib/posix_wrap/assert.h +++ b/grub-core/lib/posix_wrap/assert.h @@ -27,7 +27,7 @@ static inline void assert_real (const char *file, int line, int cond) { if (!cond) - grub_fatal ("Assertion failed at %s:%d\n", file, line); + grub_printf ("Assertion failed at %s:%d\n", file, line); } #endif diff --git a/grub-core/lib/posix_wrap/ctype.h b/grub-core/lib/posix_wrap/ctype.h index 2dc3e53e9..38b572703 100644 --- a/grub-core/lib/posix_wrap/ctype.h +++ b/grub-core/lib/posix_wrap/ctype.h @@ -42,20 +42,25 @@ isdigit (int c) static inline int islower (int c) { - return (c >= 'a' && c <= 'z'); + return grub_islower (c); +} + +static inline int +isascii (int c) +{ + return !(c & ~0x7f); } static inline int isupper (int c) { - return (c >= 'A' && c <= 'Z'); + return grub_isupper (c); } static inline int isxdigit (int c) { - return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') - || (c >= '0' && c <= '9'); + return grub_isxdigit (c); } static inline int diff --git a/grub-core/lib/posix_wrap/inttypes.h b/grub-core/lib/posix_wrap/inttypes.h new file mode 100644 index 000000000..a12c43b15 --- /dev/null +++ b/grub-core/lib/posix_wrap/inttypes.h @@ -0,0 +1 @@ +#include diff --git a/grub-core/lib/posix_wrap/langinfo.h b/grub-core/lib/posix_wrap/langinfo.h index 72b5b9612..ab75af15d 100644 --- a/grub-core/lib/posix_wrap/langinfo.h +++ b/grub-core/lib/posix_wrap/langinfo.h @@ -23,7 +23,7 @@ typedef enum { CODESET } nl_item; -static inline char * +static inline const char * nl_langinfo (nl_item item) { switch (item) diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h index e69de29bb..588e5899a 100644 --- a/grub-core/lib/posix_wrap/limits.h +++ b/grub-core/lib/posix_wrap/limits.h @@ -0,0 +1,34 @@ +/* + * 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_POSIX_LIMITS_H +#define GRUB_POSIX_LIMITS_H + +#include + +#define UCHAR_MAX GRUB_UCHAR_MAX +#define USHRT_MAX GRUB_USHRT_MAX +#define UINT_MAX GRUB_UINT_MAX +#define ULONG_MAX GRUB_ULONG_MAX + +#define SHRT_MAX GRUB_SHRT_MAX +#define INT_MAX GRUB_INT_MAX + +#define CHAR_BIT 8 + +#endif diff --git a/grub-core/lib/posix_wrap/stdio.h b/grub-core/lib/posix_wrap/stdio.h index 701fceaa4..e6b1178c5 100644 --- a/grub-core/lib/posix_wrap/stdio.h +++ b/grub-core/lib/posix_wrap/stdio.h @@ -26,4 +26,17 @@ typedef struct grub_file FILE; #define EOF -1 +static inline int +snprintf (char *str, size_t n, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start (ap, fmt); + ret = grub_vsnprintf (str, n, fmt, ap); + va_end (ap); + + return ret; +} + #endif diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h index 4c725f6e2..3b46f47ff 100644 --- a/grub-core/lib/posix_wrap/stdlib.h +++ b/grub-core/lib/posix_wrap/stdlib.h @@ -46,12 +46,10 @@ realloc (void *ptr, grub_size_t size) return grub_realloc (ptr, size); } -static inline void -abort (void) +static inline int +abs (int c) { - grub_abort (); + return (c >= 0) ? c : -c; } -#define MB_CUR_MAX 6 - #endif diff --git a/grub-core/lib/posix_wrap/string.h b/grub-core/lib/posix_wrap/string.h index 4224836e2..77fbe383b 100644 --- a/grub-core/lib/posix_wrap/string.h +++ b/grub-core/lib/posix_wrap/string.h @@ -39,4 +39,67 @@ strcasecmp (const char *s1, const char *s2) return grub_strcasecmp (s1, s2); } +#ifdef GRUB_UTIL +static inline void * +memcpy (void *dest, const void *src, grub_size_t n) +{ + return grub_memcpy (dest, src, n); +} + +static inline int +memcmp (const void *s1, const void *s2, size_t n) +{ + return grub_memcmp (s1, s2, n); +} + +#endif + +static inline char * +strcpy (char *dest, const char *src) +{ + return grub_strcpy (dest, src); +} + +static inline char * +strstr (const char *haystack, const char *needle) +{ + return grub_strstr (haystack, needle); +} + +static inline char * +strchr (const char *s, int c) +{ + return grub_strchr (s, c); +} + +static inline char * +strncpy (char *dest, const char *src, size_t n) +{ + return grub_strncpy (dest, src, n); +} + +static inline char * +strcat (char *dest, const char *src) +{ + return grub_strcat (dest, src); +} + +static inline char * +strncat (char *dest, const char *src, size_t n) +{ + return grub_strncat (dest, src, n); +} + +static inline int +strcoll (const char *s1, const char *s2) +{ + return grub_strcmp (s1, s2); +} + +static inline void * +memchr (const void *s, int c, size_t n) +{ + return grub_memchr (s, c, n); +} + #endif diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h index 28e354759..b21811606 100644 --- a/grub-core/lib/posix_wrap/sys/types.h +++ b/grub-core/lib/posix_wrap/sys/types.h @@ -22,14 +22,26 @@ #include typedef grub_size_t size_t; +typedef grub_ssize_t ssize_t; +#ifndef GRUB_POSIX_BOOL_DEFINED typedef enum { false = 0, true = 1 } bool; - -#define ULONG_MAX GRUB_ULONG_MAX -#define UCHAR_MAX 0xff +#define GRUB_POSIX_BOOL_DEFINED 1 +#endif typedef grub_uint8_t uint8_t; typedef grub_uint16_t uint16_t; typedef grub_uint32_t uint32_t; typedef grub_uint64_t uint64_t; +typedef grub_int8_t int8_t; +typedef grub_int16_t int16_t; +typedef grub_int32_t int32_t; +typedef grub_int64_t int64_t; + +#ifdef GRUB_CPU_WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#else +#undef WORDS_BIGENDIAN +#endif + #endif diff --git a/grub-core/lib/posix_wrap/unistd.h b/grub-core/lib/posix_wrap/unistd.h index e69de29bb..a12c43b15 100644 --- a/grub-core/lib/posix_wrap/unistd.h +++ b/grub-core/lib/posix_wrap/unistd.h @@ -0,0 +1 @@ +#include diff --git a/grub-core/lib/posix_wrap/wchar.h b/grub-core/lib/posix_wrap/wchar.h index fd56fd332..371133880 100644 --- a/grub-core/lib/posix_wrap/wchar.h +++ b/grub-core/lib/posix_wrap/wchar.h @@ -19,7 +19,94 @@ #ifndef GRUB_POSIX_WCHAR_H #define GRUB_POSIX_WCHAR_H 1 +#include + /* UCS-4. */ -typedef grub_uint32_t wchar_t; +typedef grub_int32_t wint_t; +enum + { + WEOF = -1 + }; + +/* UCS-4. */ +typedef grub_int32_t wchar_t; + +typedef struct mbstate { + grub_uint32_t code; + int count; +} mbstate_t; + +/* UTF-8. */ +#define MB_CUR_MAX 4 +#define MB_LEN_MAX 4 + +static inline size_t +mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) +{ + const char *ptr; + if (!s) + { + pwc = 0; + s = ""; + n = 1; + } + + for (ptr = s; ptr < s + n; ptr++) + { + if (!grub_utf8_process (*ptr, &ps->code, &ps->count)) + return -1; + if (ps->count) + continue; + if (pwc) + *pwc = ps->code; + if (ps->code == 0) + return 0; + return ptr - s + 1; + } + return -2; +} + +static inline int +mbsinit(const mbstate_t *ps) +{ + return ps->count == 0; +} + +static inline size_t +wcrtomb (char *s, wchar_t wc, mbstate_t *ps __attribute__ ((unused))) +{ + if (s == 0) + return 1; + return grub_encode_utf8_character ((grub_uint8_t *) s, + (grub_uint8_t *) s + MB_LEN_MAX, + wc); +} + +static inline wint_t btowc (int c) +{ + if (c & ~0x7f) + return WEOF; + return c; +} + + +static inline int +wcscoll (const wchar_t *s1, const wchar_t *s2) +{ + while (*s1 && *s2) + { + if (*s1 != *s2) + break; + + s1++; + s2++; + } + + if (*s1 < *s2) + return -1; + if (*s1 > *s2) + return +1; + return 0; +} #endif diff --git a/grub-core/lib/posix_wrap/wctype.h b/grub-core/lib/posix_wrap/wctype.h index e69de29bb..0dab48b97 100644 --- a/grub-core/lib/posix_wrap/wctype.h +++ b/grub-core/lib/posix_wrap/wctype.h @@ -0,0 +1,108 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009, 2010, 2011 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_POSIX_WCTYPE_H +#define GRUB_POSIX_WCTYPE_H 1 + +#include +#include + +typedef enum { GRUB_CTYPE_INVALID, + GRUB_CTYPE_ALNUM, GRUB_CTYPE_CNTRL, GRUB_CTYPE_LOWER, + GRUB_CTYPE_SPACE, GRUB_CTYPE_ALPHA, GRUB_CTYPE_DIGIT, + GRUB_CTYPE_PRINT, GRUB_CTYPE_UPPER, GRUB_CTYPE_BLANK, + GRUB_CTYPE_GRAPH, GRUB_CTYPE_PUNCT, GRUB_CTYPE_XDIGIT, + GRUB_CTYPE_MAX} wctype_t; + +#define CHARCLASS_NAME_MAX (sizeof ("xdigit") - 1) + +static inline wctype_t +wctype (const char *name) +{ + wctype_t i; + static const char names[][10] = { "", + "alnum", "cntrl", "lower", + "space", "alpha", "digit", + "print", "upper", "blank", + "graph", "punct", "xdigit" }; + for (i = GRUB_CTYPE_INVALID; i < GRUB_CTYPE_MAX; i++) + if (grub_strcmp (names[i], name) == 0) + return i; + return GRUB_CTYPE_INVALID; +} + +/* FIXME: take into account international lowercase characters. */ +static inline int +iswlower (wint_t wc) +{ + return grub_islower (wc); +} + +static inline wint_t +towlower (wint_t c) +{ + return grub_tolower (c); +} + +static inline wint_t +towupper (wint_t c) +{ + return grub_toupper (c); +} + +static inline int +iswalnum (wint_t c) +{ + return grub_isalpha (c) || grub_isdigit (c); +} + +static inline int +iswctype (wint_t wc, wctype_t desc) +{ + switch (desc) + { + case GRUB_CTYPE_ALNUM: + return iswalnum (wc); + case GRUB_CTYPE_CNTRL: + return grub_iscntrl (wc); + case GRUB_CTYPE_LOWER: + return iswlower (wc); + case GRUB_CTYPE_SPACE: + return grub_isspace (wc); + case GRUB_CTYPE_ALPHA: + return grub_isalpha (wc); + case GRUB_CTYPE_DIGIT: + return grub_isdigit (wc); + case GRUB_CTYPE_PRINT: + return grub_isprint (wc); + case GRUB_CTYPE_UPPER: + return grub_isupper (wc); + case GRUB_CTYPE_BLANK: + return wc == ' ' || wc == '\t'; + case GRUB_CTYPE_GRAPH: + return grub_isgraph (wc); + case GRUB_CTYPE_PUNCT: + return grub_isprint (wc) && !grub_isspace (wc) && !iswalnum (wc); + case GRUB_CTYPE_XDIGIT: + return grub_isxdigit (wc); + default: + return 0; + } +} + +#endif diff --git a/grub-core/lib/powerpc/setjmp.S b/grub-core/lib/powerpc/setjmp.S index 25cbaa3e9..8c7540e3c 100644 --- a/grub-core/lib/powerpc/setjmp.S +++ b/grub-core/lib/powerpc/setjmp.S @@ -17,9 +17,12 @@ */ #include +#include .file "setjmp.S" +GRUB_MOD_LICENSE ("GPLv3+") + .text /* diff --git a/grub-core/lib/priority_queue.c b/grub-core/lib/priority_queue.c new file mode 100644 index 000000000..a790910a8 --- /dev/null +++ b/grub-core/lib/priority_queue.c @@ -0,0 +1,257 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 TEST +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#else +#include +#include +#include + +#include + +using namespace std; + +typedef size_t grub_size_t; +typedef int (*grub_comparator_t) (const void *a, const void *b); +typedef unsigned char grub_uint8_t; +#define grub_malloc malloc +#define grub_memcpy memcpy +#define grub_realloc realloc +#define grub_free free + +typedef enum + { + GRUB_ERR_NONE, + grub_errno + } grub_err_t; +#endif + +struct grub_priority_queue +{ + grub_size_t elsize; + grub_size_t allocated; + grub_size_t used; + grub_comparator_t cmp; + void *els; +}; + +#ifdef TEST +typedef struct grub_priority_queue *grub_priority_queue_t; +#endif + +static inline void * +element (struct grub_priority_queue *pq, grub_size_t k) +{ + return ((grub_uint8_t *) pq->els) + k * pq->elsize; +} + +static inline void +swap (struct grub_priority_queue *pq, grub_size_t m, grub_size_t n) +{ + grub_uint8_t *p1, *p2; + grub_size_t l; + p1 = (grub_uint8_t *) element (pq, m); + p2 = (grub_uint8_t *) element (pq, n); + for (l = pq->elsize; l; l--, p1++, p2++) + { + grub_uint8_t t; + t = *p1; + *p1 = *p2; + *p2 = t; + } +} + +static inline grub_size_t +parent (grub_size_t v) +{ + return (v - 1) / 2; +} + +static inline grub_size_t +left_child (grub_size_t v) +{ + return 2 * v + 1; +} + +static inline grub_size_t +right_child (grub_size_t v) +{ + return 2 * v + 2; +} + +void * +grub_priority_queue_top (grub_priority_queue_t pq) +{ + if (!pq->used) + return 0; + return element (pq, 0); +} + +void +grub_priority_queue_destroy (grub_priority_queue_t pq) +{ + grub_free (pq->els); + grub_free (pq); +} + +grub_priority_queue_t +grub_priority_queue_new (grub_size_t elsize, + grub_comparator_t cmp) +{ + struct grub_priority_queue *ret; + void *els; + els = grub_malloc (elsize * 8); + if (!els) + return 0; + ret = (struct grub_priority_queue *) grub_malloc (sizeof (*ret)); + if (!ret) + { + grub_free (els); + return 0; + } + ret->elsize = elsize; + ret->allocated = 8; + ret->used = 0; + ret->cmp = cmp; + ret->els = els; + return ret; +} + +/* Heap property: pq->cmp (element (pq, p), element (pq, parent (p))) <= 0. */ +grub_err_t +grub_priority_queue_push (grub_priority_queue_t pq, const void *el) +{ + grub_size_t p; + if (pq->used == pq->allocated) + { + void *els; + els = grub_realloc (pq->els, pq->elsize * 2 * pq->allocated); + if (!els) + return grub_errno; + pq->allocated *= 2; + pq->els = els; + } + pq->used++; + grub_memcpy (element (pq, pq->used - 1), el, pq->elsize); + for (p = pq->used - 1; p; p = parent (p)) + { + if (pq->cmp (element (pq, p), element (pq, parent (p))) <= 0) + break; + swap (pq, p, parent (p)); + } + + return GRUB_ERR_NONE; +} + +void +grub_priority_queue_pop (grub_priority_queue_t pq) +{ + grub_size_t p; + + swap (pq, 0, pq->used - 1); + pq->used--; + for (p = 0; left_child (p) < pq->used; ) + { + grub_size_t c; + if (pq->cmp (element (pq, left_child (p)), element (pq, p)) <= 0 + && (right_child (p) >= pq->used + || pq->cmp (element (pq, right_child (p)), element (pq, p)) <= 0)) + break; + if (right_child (p) >= pq->used + || pq->cmp (element (pq, left_child (p)), + element (pq, right_child (p))) > 0) + c = left_child (p); + else + c = right_child (p); + swap (pq, p, c); + p = c; + } +} + +#ifdef TEST + +static int +compar (const void *a_, const void *b_) +{ + int a = *(int *) a_; + int b = *(int *) b_; + if (a < b) + return -1; + if (a > b) + return +1; + return 0; +} + +int +main (void) +{ + priority_queue pq; + grub_priority_queue_t pq2; + int counter; + int s = 0; + pq2 = grub_priority_queue_new (sizeof (int), compar); + if (!pq2) + return 1; + srand (1); + + for (counter = 0; counter < 1000000; counter++) + { + int op = rand () % 10; + if (s && *(int *) grub_priority_queue_top (pq2) != pq.top ()) + { + printf ("Error at %d\n", counter); + return 2; + } + if (op < 3 && s) + { + grub_priority_queue_pop (pq2); + pq.pop (); + s--; + } + else + { + int v = rand (); + int e; + pq.push (v); + e = grub_priority_queue_push (pq2, &v); + if (e) + return 3; + s++; + } + } + while (s) + { + if (*(int *) grub_priority_queue_top (pq2) != pq.top ()) + { + printf ("Error at the end. %d elements remaining.\n", s); + return 4; + } + grub_priority_queue_pop (pq2); + pq.pop (); + s--; + } + printf ("All tests passed successfully\n"); + return 0; +} +#endif diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c index 4c6e160e4..704ebd3f2 100644 --- a/grub-core/lib/reed_solomon.c +++ b/grub-core/lib/reed_solomon.c @@ -18,18 +18,21 @@ #ifdef TEST #include +#include +#include #define xmalloc malloc #define grub_memset memset #define grub_memcpy memcpy #endif +#ifndef STANDALONE +#include +#endif + #ifndef STANDALONE #ifdef TEST -#include -#include typedef unsigned int grub_size_t; typedef unsigned char grub_uint8_t; -typedef unsigned short grub_uint16_t; #else #include #include @@ -38,13 +41,16 @@ typedef unsigned short grub_uint16_t; #endif #endif +#define SECTOR_SIZE 512 +#define MAX_BLOCK_SIZE (200 * SECTOR_SIZE) + #ifdef STANDALONE #ifdef TEST typedef unsigned int grub_size_t; typedef unsigned char grub_uint8_t; -typedef unsigned short grub_uint16_t; #else #include +#include #endif void grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs); @@ -52,63 +58,80 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs); #define GF_SIZE 8 typedef grub_uint8_t gf_single_t; -typedef grub_uint16_t gf_double_t; #define GF_POLYNOMIAL 0x1d #define GF_INVERT2 0x8e #if defined (STANDALONE) && !defined (TEST) -static char *gf_invert __attribute__ ((section(".text"))) = (void *) 0x100000; -static char *scratch __attribute__ ((section(".text"))) = (void *) 0x100100; +static gf_single_t * const gf_powx __attribute__ ((section(".text"))) = (void *) 0x100000; +static gf_single_t * const gf_powx_inv __attribute__ ((section(".text"))) = (void *) 0x100200; +static int *const chosenstat __attribute__ ((section(".text"))) = (void *) 0x100300; +static gf_single_t *const sigma __attribute__ ((section(".text"))) = (void *) 0x100700; +static gf_single_t *const errpot __attribute__ ((section(".text"))) = (void *) 0x100800; +static int *const errpos __attribute__ ((section(".text"))) = (void *) 0x100900; +static gf_single_t *const sy __attribute__ ((section(".text"))) = (void *) 0x100d00; +static gf_single_t *const mstat __attribute__ ((section(".text"))) = (void *) 0x100e00; +static gf_single_t *const errvals __attribute__ ((section(".text"))) = (void *) 0x100f00; +static gf_single_t *const eqstat __attribute__ ((section(".text"))) = (void *) 0x101000; +/* Next available address: (void *) 0x112000. */ #else -static char *scratch; -static grub_uint8_t gf_invert[256]; + +static gf_single_t gf_powx[255 * 2]; +static gf_single_t gf_powx_inv[256]; +static int chosenstat[256]; +static gf_single_t sigma[256]; +static gf_single_t errpot[256]; +static int errpos[256]; +static gf_single_t sy[256]; +static gf_single_t mstat[256]; +static gf_single_t errvals[256]; +static gf_single_t eqstat[65536 + 256]; #endif -#define SECTOR_SIZE 512 -#define MAX_BLOCK_SIZE (200 * SECTOR_SIZE) - -static gf_single_t -gf_reduce (gf_double_t a) -{ - int i; - for (i = GF_SIZE - 1; i >= 0; i--) - if (a & (1ULL << (i + GF_SIZE))) - a ^= (((gf_double_t) GF_POLYNOMIAL) << i); - return a & ((1ULL << GF_SIZE) - 1); -} - static gf_single_t gf_mul (gf_single_t a, gf_single_t b) { - gf_double_t res = 0; - int i; - for (i = 0; i < GF_SIZE; i++) - if (b & (1 << i)) - res ^= ((gf_double_t) a) << i; - return gf_reduce (res); + if (a == 0 || b == 0) + return 0; + return gf_powx[(int) gf_powx_inv[a] + (int) gf_powx_inv[b]]; +} + +static inline gf_single_t +gf_invert (gf_single_t a) +{ + return gf_powx[255 - (int) gf_powx_inv[a]]; } static void -init_inverts (void) +init_powx (void) { - gf_single_t a = 1, ai = 1; - do + int i; + grub_uint8_t cur = 1; + + gf_powx_inv[0] = 0; + for (i = 0; i < 255; i++) { - a = gf_mul (a, 2); - ai = gf_mul (ai, GF_INVERT2); - gf_invert[a] = ai; + gf_powx[i] = cur; + gf_powx[i + 255] = cur; + gf_powx_inv[cur] = i; + if (cur & (1ULL << (GF_SIZE - 1))) + cur = (cur << 1) ^ GF_POLYNOMIAL; + else + cur <<= 1; } - while (a != 1); } static gf_single_t -pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x) +pol_evaluate (gf_single_t *pol, grub_size_t degree, int log_x) { int i; - gf_single_t xn = 1, s = 0; + gf_single_t s = 0; + int log_xn = 0; for (i = degree; i >= 0; i--) { - s ^= gf_mul (pol[i], xn); - xn = gf_mul (x, xn); + if (pol[i]) + s ^= gf_powx[(int) gf_powx_inv[pol[i]] + log_xn]; + log_xn += log_x; + if (log_xn >= ((1 << GF_SIZE) - 1)) + log_xn -= ((1 << GF_SIZE) - 1); } return s; } @@ -117,7 +140,7 @@ pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x) static void rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) { - gf_single_t *rs_polynomial, a = 1; + gf_single_t *rs_polynomial; int i, j; gf_single_t *m; m = xmalloc ((s + rs) * sizeof (gf_single_t)); @@ -129,16 +152,14 @@ rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) /* Multiply with X - a^r */ for (j = 0; j < rs; j++) { - if (a & (1 << (GF_SIZE - 1))) - { - a <<= 1; - a ^= GF_POLYNOMIAL; - } - else - a <<= 1; for (i = 0; i < rs; i++) - rs_polynomial[i] = rs_polynomial[i + 1] ^ gf_mul (a, rs_polynomial[i]); - rs_polynomial[rs] = gf_mul (a, rs_polynomial[rs]); + if (rs_polynomial[i]) + rs_polynomial[i] = (rs_polynomial[i + 1] + ^ gf_powx[j + (int) gf_powx_inv[rs_polynomial[i]]]); + else + rs_polynomial[i] = rs_polynomial[i + 1]; + if (rs_polynomial[rs]) + rs_polynomial[rs] = gf_powx[j + (int) gf_powx_inv[rs_polynomial[rs]]]; } for (j = 0; j < s; j++) if (m[j]) @@ -153,25 +174,6 @@ rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) } #endif -static void -syndroms (gf_single_t *m, grub_size_t s, grub_size_t rs, - gf_single_t *sy) -{ - gf_single_t xn = 1; - unsigned i; - for (i = 0; i < rs; i++) - { - if (xn & (1 << (GF_SIZE - 1))) - { - xn <<= 1; - xn ^= GF_POLYNOMIAL; - } - else - xn <<= 1; - sy[i] = pol_evaluate (m, s + rs - 1, xn); - } -} - static void gauss_eliminate (gf_single_t *eq, int n, int m, int *chosen) { @@ -187,7 +189,7 @@ gauss_eliminate (gf_single_t *eq, int n, int m, int *chosen) if (nzidx == m) continue; chosen[i] = nzidx; - r = gf_invert [eq[i * (m + 1) + nzidx]]; + r = gf_invert (eq[i * (m + 1) + nzidx]); for (j = 0; j < m + 1; j++) eq[i * (m + 1) + j] = gf_mul (eq[i * (m + 1) + j], r); for (j = i + 1; j < n; j++) @@ -202,161 +204,79 @@ gauss_eliminate (gf_single_t *eq, int n, int m, int *chosen) static void gauss_solve (gf_single_t *eq, int n, int m, gf_single_t *sol) { - int *chosen; int i, j; -#ifndef STANDALONE - chosen = xmalloc (n * sizeof (int)); - grub_memset (chosen, -1, n * sizeof (int)); -#else - chosen = (void *) scratch; - scratch += n; -#endif + for (i = 0; i < n; i++) + chosenstat[i] = -1; for (i = 0; i < m; i++) sol[i] = 0; - gauss_eliminate (eq, n, m, chosen); + gauss_eliminate (eq, n, m, chosenstat); for (i = n - 1; i >= 0; i--) { gf_single_t s = 0; - if (chosen[i] == -1) + if (chosenstat[i] == -1) continue; for (j = 0; j < m; j++) s ^= gf_mul (eq[i * (m + 1) + j], sol[j]); s ^= eq[i * (m + 1) + m]; - sol[chosen[i]] = s; + sol[chosenstat[i]] = s; } -#ifndef STANDALONE - free (chosen); -#else - scratch -= n; -#endif } static void -rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) +rs_recover (gf_single_t *mm, grub_size_t s, grub_size_t rs) { grub_size_t rs2 = rs / 2; - gf_single_t *sigma; - gf_single_t *errpot; - int *errpos; - gf_single_t *sy; int errnum = 0; int i, j; -#ifndef STANDALONE - sigma = xmalloc (rs2 * sizeof (gf_single_t)); - errpot = xmalloc (rs2 * sizeof (gf_single_t)); - errpos = xmalloc (rs2 * sizeof (int)); - sy = xmalloc (rs * sizeof (gf_single_t)); -#else - sigma = (void *) scratch; - scratch += rs2 * sizeof (gf_single_t); - errpot = (void *) scratch; - scratch += rs2 * sizeof (gf_single_t); - errpos = (void *) scratch; - scratch += rs2 * sizeof (int); - sy = (void *) scratch; - scratch += rs * sizeof (gf_single_t); -#endif + for (i = 0; i < (int) rs; i++) + sy[i] = pol_evaluate (mm, s + rs - 1, i); - syndroms (m, s, rs, sy); + for (i = 0; i < (int) rs; i++) + if (sy[i] != 0) + break; + + /* No error detected. */ + if (i == (int) rs) + return; { - gf_single_t *eq; - -#ifndef STANDALONE - eq = xmalloc (rs2 * (rs2 + 1) * sizeof (gf_single_t)); -#else - eq = (void *) scratch; - scratch += rs2 * (rs2 + 1) * sizeof (gf_single_t); -#endif - - for (i = 0; i < (int) rs; i++) - if (sy[i] != 0) - break; - - /* No error detected. */ - if (i == (int) rs) - return; for (i = 0; i < (int) rs2; i++) for (j = 0; j < (int) rs2 + 1; j++) - eq[i * (rs2 + 1) + j] = sy[i+j]; + eqstat[i * (rs2 + 1) + j] = sy[i+j]; for (i = 0; i < (int) rs2; i++) sigma[i] = 0; - gauss_solve (eq, rs2, rs2, sigma); - -#ifndef STANDALONE - free (eq); -#else - scratch -= rs2 * (rs2 + 1) * sizeof (gf_single_t); -#endif + gauss_solve (eqstat, rs2, rs2, sigma); } - { - gf_single_t xn = 1, yn = 1; - for (i = 0; i < (int) (rs + s); i++) + for (i = 0; i < (int) (rs + s); i++) + if (pol_evaluate (sigma, rs2 - 1, 255 - i) == gf_powx[i]) { - gf_single_t ev = (gf_mul (pol_evaluate (sigma, rs2 - 1, xn), xn) ^ 1); - if (ev == 0) - { - errpot[errnum] = yn; - errpos[errnum++] = s + rs - i - 1; - } - yn = gf_mul (yn, 2); - xn = gf_mul (xn, GF_INVERT2); + errpot[errnum] = gf_powx[i]; + errpos[errnum++] = s + rs - i - 1; } - } { - gf_single_t *errvals; - gf_single_t *eq; - -#ifndef STANDALONE - eq = xmalloc (rs * (errnum + 1) * sizeof (gf_single_t)); - errvals = xmalloc (errnum * sizeof (int)); -#else - eq = (void *) scratch; - scratch += rs * (errnum + 1) * sizeof (gf_single_t); - errvals = (void *) scratch; - scratch += errnum * sizeof (int); -#endif - for (j = 0; j < errnum; j++) - eq[j] = errpot[j]; - eq[errnum] = sy[0]; + eqstat[j] = 1; + eqstat[errnum] = sy[0]; for (i = 1; i < (int) rs; i++) { for (j = 0; j < (int) errnum; j++) - eq[(errnum + 1) * i + j] = gf_mul (errpot[j], - eq[(errnum + 1) * (i - 1) + j]); - eq[(errnum + 1) * i + errnum] = sy[i]; + eqstat[(errnum + 1) * i + j] = gf_mul (errpot[j], + eqstat[(errnum + 1) * (i - 1) + + j]); + eqstat[(errnum + 1) * i + errnum] = sy[i]; } - gauss_solve (eq, rs, errnum, errvals); + gauss_solve (eqstat, rs, errnum, errvals); for (i = 0; i < (int) errnum; i++) - m[errpos[i]] ^= errvals[i]; -#ifndef STANDALONE - free (eq); - free (errvals); -#else - scratch -= rs * (errnum + 1) * sizeof (gf_single_t); - scratch -= errnum * sizeof (int); -#endif + mm[errpos[i]] ^= errvals[i]; } -#ifndef STANDALONE - free (sigma); - free (errpot); - free (errpos); - free (sy); -#else - scratch -= rs2 * sizeof (gf_single_t); - scratch -= rs2 * sizeof (gf_single_t); - scratch -= rs2 * sizeof (int); - scratch -= rs * sizeof (gf_single_t); -#endif } static void @@ -368,17 +288,20 @@ decode_block (gf_single_t *ptr, grub_size_t s, { grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; grub_size_t rr = (rs + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; - gf_single_t m[ds + rr]; + + /* Nothing to do. */ + if (!ds || !rr) + continue; for (j = 0; j < (int) ds; j++) - m[j] = ptr[SECTOR_SIZE * j + i]; + mstat[j] = ptr[SECTOR_SIZE * j + i]; for (j = 0; j < (int) rr; j++) - m[j + ds] = rptr[SECTOR_SIZE * j + i]; + mstat[j + ds] = rptr[SECTOR_SIZE * j + i]; - rs_recover (m, ds, rr); + rs_recover (mstat, ds, rr); for (j = 0; j < (int) ds; j++) - ptr[SECTOR_SIZE * j + i] = m[j]; + ptr[SECTOR_SIZE * j + i] = mstat[j]; } } @@ -392,12 +315,18 @@ encode_block (gf_single_t *ptr, grub_size_t s, { grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; grub_size_t rr = (rs + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; - gf_single_t m[ds + rr]; + gf_single_t *m; + + if (!ds || !rr) + continue; + + m = xmalloc (ds + rr); for (j = 0; j < ds; j++) m[j] = ptr[SECTOR_SIZE * j + i]; rs_encode (m, ds, rr); for (j = 0; j < rr; j++) rptr[SECTOR_SIZE * j + i] = m[j + ds]; + free (m); } } #endif @@ -411,6 +340,16 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, grub_size_t rs = redundancy; gf_single_t *ptr = buffer; gf_single_t *rptr = ptr + s; + void *tmp; + + tmp = xmalloc (data_size); + grub_memcpy (tmp, buffer, data_size); + + /* Nothing to do. */ + if (!rs) + return; + + init_powx (); while (s > 0) { @@ -421,8 +360,8 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, tt = cs + crs; if (tt > MAX_BLOCK_SIZE) { - cs = (cs * MAX_BLOCK_SIZE) / tt; - crs = (crs * MAX_BLOCK_SIZE) / tt; + cs = ((cs * (MAX_BLOCK_SIZE / 512)) / tt) * 512; + crs = ((crs * (MAX_BLOCK_SIZE / 512)) / tt) * 512; } encode_block (ptr, cs, rptr, crs); ptr += cs; @@ -430,6 +369,11 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, s -= cs; rs -= crs; } + +#ifndef TEST + assert (grub_memcmp (tmp, buffer, data_size) == 0); +#endif + free (tmp); } #endif @@ -439,9 +383,11 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs) gf_single_t *ptr = ptr_; gf_single_t *rptr = ptr + s; -#if defined (STANDALONE) - init_inverts (); -#endif + /* Nothing to do. */ + if (!rs) + return; + + init_powx (); while (s > 0) { @@ -452,8 +398,8 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs) tt = cs + crs; if (tt > MAX_BLOCK_SIZE) { - cs = cs * MAX_BLOCK_SIZE / tt; - crs = crs * MAX_BLOCK_SIZE / tt; + cs = ((cs * (MAX_BLOCK_SIZE / 512)) / tt) * 512; + crs = ((crs * (MAX_BLOCK_SIZE / 512)) / tt) * 512; } decode_block (ptr, cs, rptr, crs); ptr += cs; @@ -471,42 +417,49 @@ main (int argc, char **argv) grub_size_t s, rs; char *buf; -#ifdef STANDALONE - scratch = xmalloc (1048576); + grub_memset (gf_powx, 0xee, sizeof (gf_powx)); + grub_memset (gf_powx_inv, 0xdd, sizeof (gf_powx_inv)); + +#ifndef STANDALONE + init_powx (); #endif #ifndef STANDALONE - init_inverts (); -#endif - in = fopen ("tst.bin", "rb"); if (!in) return 1; fseek (in, 0, SEEK_END); s = ftell (in); fseek (in, 0, SEEK_SET); - rs = 1024 * ((s + MAX_BLOCK_SIZE - 1) / (MAX_BLOCK_SIZE - 1024)); + rs = 0x7007; buf = xmalloc (s + rs + SECTOR_SIZE); fread (buf, 1, s, in); + fclose (in); - s = 0x5fbb; - rs = 0x6af9; - -#if 0 grub_reed_solomon_add_redundancy (buf, s, rs); out = fopen ("tst_rs.bin", "wb"); fwrite (buf, 1, s + rs, out); fclose (out); +#else + out = fopen ("tst_rs.bin", "rb"); + fseek (out, 0, SEEK_END); + s = ftell (out); + fseek (out, 0, SEEK_SET); + rs = 0x7007; + s -= rs; + buf = xmalloc (s + rs + SECTOR_SIZE); + fread (buf, 1, s + rs, out); + fclose (out); +#endif +#if 1 grub_memset (buf + 512 * 15, 0, 512); +#endif out = fopen ("tst_dam.bin", "wb"); fwrite (buf, 1, s + rs, out); fclose (out); -#endif - s = 0x5fbb; - rs = 0x6af9; grub_reed_solomon_recover (buf, s, rs); out = fopen ("tst_rec.bin", "wb"); diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index a0cab55af..363bba2f0 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -22,6 +22,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); struct grub_relocator { @@ -40,7 +43,6 @@ struct grub_relocator_subchunk #endif } type; grub_mm_region_t reg; - grub_mm_header_t head; grub_phys_addr_t start; grub_size_t size; grub_size_t pre_size; @@ -78,10 +80,10 @@ struct grub_relocator_fw_leftover grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8]; }; -struct grub_relocator_fw_leftover *leftovers; +static struct grub_relocator_fw_leftover *leftovers; #endif -struct grub_relocator_extra_block *extra_blocks; +static struct grub_relocator_extra_block *extra_blocks; void * get_virtual_current_address (grub_relocator_chunk_t in) @@ -135,9 +137,10 @@ allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb, 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); +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "ra = %p, rb = %p\n", regancestor, rb); +#endif 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); @@ -180,11 +183,12 @@ allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb, if ((void *) h < (void *) (newreg + 1)) grub_fatal ("Failed to adjust memory region: %p, %p, %p, %p, %p", newreg, newreg->first, h, hp, hb); +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF if ((void *) h == (void *) (newreg + 1)) grub_dprintf ("relocator", "Free start memory region: %p, %p, %p, %p, %p", newreg, newreg->first, h, hp, hb); - +#endif hp = h; h = h->next; } @@ -201,10 +205,12 @@ allocate_inreg (grub_phys_addr_t paddr, grub_size_t size, struct grub_mm_header *foll = NULL; grub_addr_t vaddr = (grub_addr_t) hb + (paddr - grub_vtop (hb)); +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF 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); +#endif if (ALIGN_UP (vaddr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN <= (grub_addr_t) (hb + hb->size)) @@ -212,8 +218,10 @@ allocate_inreg (grub_phys_addr_t paddr, grub_size_t size, foll = (void *) ALIGN_UP (vaddr + size, GRUB_MM_ALIGN); foll->magic = GRUB_MM_FREE_MAGIC; foll->size = hb + hb->size - foll; +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF grub_dprintf ("relocator", "foll = %p, foll->size = %lu\n", foll, (unsigned long) foll->size); +#endif } if (vaddr - (grub_addr_t) hb >= sizeof (*hb)) @@ -355,11 +363,11 @@ free_subchunk (const struct grub_relocator_subchunk *subchu) } case CHUNK_TYPE_IN_REGION: { - grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->head, + grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->start, GRUB_MM_ALIGN); h->size = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN) - - (subchu->start / GRUB_MM_ALIGN); + - (subchu->start / GRUB_MM_ALIGN) - 1; h->next = h; h->magic = GRUB_MM_ALLOC_MAGIC; grub_free (h + 1); @@ -516,9 +524,11 @@ malloc_in_range (struct grub_relocator *rel, #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS for (r = grub_mm_base; r; r = r->next) { +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", (unsigned long) r - r->pre_size, (unsigned long) (r + 1) + r->size); +#endif events[N].type = FIRMWARE_BLOCK_START; events[N].pos = (grub_addr_t) r - r->pre_size; N++; @@ -530,8 +540,10 @@ malloc_in_range (struct grub_relocator *rel, struct grub_relocator_extra_block *cur; for (cur = extra_blocks; cur; cur = cur->next) { +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", (unsigned long) cur->start, (unsigned long) cur->end); +#endif events[N].type = FIRMWARE_BLOCK_START; events[N].pos = cur->start; N++; @@ -579,7 +591,6 @@ malloc_in_range (struct grub_relocator *rel, 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) @@ -591,7 +602,6 @@ malloc_in_range (struct grub_relocator *rel, __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; @@ -600,7 +610,8 @@ malloc_in_range (struct grub_relocator *rel, events[N].hancestor = pa; N++; events[N].type = REG_BEG_END; - events[N].pos = grub_vtop (p + p->size) - sizeof (*r); + events[N].pos = grub_vtop (p + p->size) - sizeof (*r) + - sizeof (struct grub_mm_header); N++; } else @@ -667,7 +678,6 @@ malloc_in_range (struct grub_relocator *rel, 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--) { @@ -725,11 +735,8 @@ malloc_in_range (struct grub_relocator *rel, 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; - } + starta = from_low_priv ? ALIGN_UP (events[j].pos, align) + : ALIGN_DOWN (events[j].pos - size, align) + size; if (isinsidebefore && !isinsideafter && from_low_priv) { target = starta; @@ -761,6 +768,9 @@ malloc_in_range (struct grub_relocator *rel, int inreg = 0, regbeg = 0, ncol = 0; #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS int fwin = 0, fwb = 0, fwlefto = 0; +#endif +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + int last_lo = 0; #endif int last_start = 0; for (j = 0; j < N; j++) @@ -825,9 +835,11 @@ malloc_in_range (struct grub_relocator *rel, fend = ALIGN_UP (alloc_end, GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF grub_dprintf ("relocator", "requesting %lx-%lx\n", (unsigned long) fstart, (unsigned long) fend); +#endif /* The failure here can be very expensive. */ if (!grub_relocator_firmware_alloc_region (fstart, fend - fstart)) @@ -850,7 +862,7 @@ malloc_in_range (struct grub_relocator *rel, unsigned offend = alloc_end % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; struct grub_relocator_fw_leftover *lo - = events[last_start].leftover; + = events[last_lo].leftover; lo->freebytes[offstart / 8] &= ((1 << (8 - (start % 8))) - 1); grub_memset (lo->freebytes + (offstart + 7) / 8, 0, @@ -905,6 +917,7 @@ malloc_in_range (struct grub_relocator *rel, #if GRUB_RELOCATOR_HAVE_LEFTOVERS case REG_LEFTOVER_START: fwlefto++; + last_lo = j; break; case REG_LEFTOVER_END: @@ -977,7 +990,6 @@ malloc_in_range (struct grub_relocator *rel, || 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 @@ -1005,7 +1017,8 @@ malloc_in_range (struct grub_relocator *rel, curschu->extra = ne; } } -#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS if (!oom && typepre == CHUNK_TYPE_FIRMWARE) { grub_addr_t fstart, fend; @@ -1017,7 +1030,6 @@ malloc_in_range (struct grub_relocator *rel, = 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; @@ -1077,10 +1089,8 @@ malloc_in_range (struct grub_relocator *rel, curschu->pre = lo1; curschu->post = lo2; } -#endif } -#if GRUB_RELOCATOR_HAVE_LEFTOVERS if (typepre == CHUNK_TYPE_LEFTOVER) { curschu->pre = events[last_start].leftover; @@ -1088,7 +1098,6 @@ malloc_in_range (struct grub_relocator *rel, } #endif -#endif if (!oom) cural++; else @@ -1289,23 +1298,8 @@ grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, 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); - } - } + grub_memset (chunk->srcv, 0xfa, chunk->size); + grub_mm_check (); #endif return GRUB_ERR_NONE; } @@ -1430,11 +1424,17 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, break; } + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + if (chunk->src < chunk->target) rel->relocators_size += grub_relocator_backward_size; if (chunk->src > chunk->target) rel->relocators_size += grub_relocator_forward_size; + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + chunk->size = size; chunk->next = rel->chunks; rel->chunks = chunk; @@ -1443,24 +1443,8 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, 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); - } - } + grub_memset (chunk->srcv, 0xfa, chunk->size); + grub_mm_check (); #endif return GRUB_ERR_NONE; } diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S index c39c91b9c..2e4974297 100644 --- a/grub-core/lib/setjmp.S +++ b/grub-core/lib/setjmp.S @@ -6,8 +6,11 @@ #include "./sparc64/setjmp.S" #elif defined(__mips__) #include "./mips/setjmp.S" -#elif defined(__powerpc__) +#elif defined(__powerpc__) || defined(__PPC__) #include "./powerpc/setjmp.S" +#elif defined(__ia64__) +#include "./ia64/setjmp.S" +#include "./ia64/longjmp.S" #else -#error "Unknwon target cpu type" +#error "Unknown target cpu type" #endif diff --git a/grub-core/lib/sparc64/setjmp.S b/grub-core/lib/sparc64/setjmp.S index 0e23ecfa1..5c2ec2cf3 100644 --- a/grub-core/lib/sparc64/setjmp.S +++ b/grub-core/lib/sparc64/setjmp.S @@ -17,9 +17,12 @@ */ #include +#include .file "setjmp.S" +GRUB_MOD_LICENSE ("GPLv3+") + .text /* diff --git a/grub-core/lib/x86_64/setjmp.S b/grub-core/lib/x86_64/setjmp.S index 621b09b93..b1f1b22cb 100644 --- a/grub-core/lib/x86_64/setjmp.S +++ b/grub-core/lib/x86_64/setjmp.S @@ -17,9 +17,12 @@ */ #include +#include .file "setjmp.S" +GRUB_MOD_LICENSE ("GPLv3+") + .text /* diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h index f0a7dbbca..fe7158bb2 100644 --- a/grub-core/lib/xzembed/xz.h +++ b/grub-core/lib/xzembed/xz.h @@ -25,6 +25,13 @@ #define XZ_H #include +#include +#include +#include + +#ifndef GRUB_POSIX_BOOL_DEFINED +typedef enum { false = 0, true = 1 } bool; +#endif /** * enum xz_ret - Return codes diff --git a/grub-core/lib/xzembed/xz_config.h b/grub-core/lib/xzembed/xz_config.h index 0af0d2b81..55b88c476 100644 --- a/grub-core/lib/xzembed/xz_config.h +++ b/grub-core/lib/xzembed/xz_config.h @@ -26,27 +26,27 @@ /* Enable BCJ filter decoders. */ -#if defined(__i386__) || defined(__x86_64__) +#if defined(GRUB_TARGET_CPU_I386) || defined(GRUB_TARGET_CPU_X86_64) #define XZ_DEC_X86 #endif -#ifdef __powerpc__ +#ifdef GRUB_TARGET_CPU_POWERPC #define XZ_DEC_POWERPC #endif -#ifdef __ia64__ +#ifdef GRUB_TARGET_CPU_IA64 #define XZ_DEC_IA64 #endif -#ifdef __arm__ +#ifdef GRUB_TARGET_CPU_ARM #define XZ_DEC_ARM #endif -#ifdef __thumb__ +#if 0 #define XZ_DEC_ARMTHUMB #endif -#ifdef __sparc__ +#ifdef GRUB_TARGET_CPU_SPARC #define XZ_DEC_SPARC #endif diff --git a/grub-core/lib/xzembed/xz_dec_stream.c b/grub-core/lib/xzembed/xz_dec_stream.c index 3bf201d50..1d789d9ba 100644 --- a/grub-core/lib/xzembed/xz_dec_stream.c +++ b/grub-core/lib/xzembed/xz_dec_stream.c @@ -32,10 +32,13 @@ struct xz_dec_hash { vli_type unpadded; vli_type uncompressed; #ifndef GRUB_EMBED_DECOMPRESSOR - uint8_t *crc32_context; + uint64_t *hash_context; #endif }; +/* Enough for up to 512 bits. */ +#define MAX_HASH_SIZE 64 + struct xz_dec { /* Position in dec_main() */ enum { @@ -62,11 +65,22 @@ struct xz_dec { size_t out_start; /* CRC32 value in Block or Index */ - uint32_t crc32_temp; /* need for crc32_validate*/ - uint8_t *crc32_context; +#ifndef GRUB_EMBED_DECOMPRESSOR + uint8_t hash_value[MAX_HASH_SIZE]; /* need for crc32_validate*/ +#endif + int have_hash_value; +#ifndef GRUB_EMBED_DECOMPRESSOR + uint64_t *hash_context; + uint64_t *crc32_context; +#endif - /* True if CRC32 is calculated from uncompressed data */ - bool has_crc32; + /* Hash function calculated from uncompressed data */ +#ifndef GRUB_EMBED_DECOMPRESSOR + const gcry_md_spec_t *hash; + const gcry_md_spec_t *crc32; + grub_uint8_t hash_id; +#endif + grub_size_t hash_size; /* True if we are operating in single-call mode. */ bool single_call; @@ -250,9 +264,12 @@ static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) return XZ_DATA_ERROR; #ifndef GRUB_EMBED_DECOMPRESSOR - if (s->has_crc32) - GRUB_MD_CRC32->write(s->crc32_context,b->out + s->out_start, - b->out_pos - s->out_start); + if (s->hash) + s->hash->write(s->hash_context,b->out + s->out_start, + b->out_pos - s->out_start); + if (s->crc32) + s->crc32->write(s->crc32_context,b->out + s->out_start, + b->out_pos - s->out_start); #endif if (ret == XZ_STREAM_END) { @@ -268,14 +285,15 @@ static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) s->block.hash.unpadded += s->block_header.size + s->block.compressed; - if (s->has_crc32) - s->block.hash.unpadded += 4; + s->block.hash.unpadded += s->hash_size; s->block.hash.uncompressed += s->block.uncompressed; #ifndef GRUB_EMBED_DECOMPRESSOR - GRUB_MD_CRC32->write(s->block.hash.crc32_context, - (const uint8_t *)&s->block.hash, 2 * sizeof(vli_type)); + if (s->hash) + s->hash->write(s->block.hash.hash_context, + (const uint8_t *)&s->block.hash, + 2 * sizeof(vli_type)); #endif ++s->block.count; @@ -290,7 +308,10 @@ 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; #ifndef GRUB_EMBED_DECOMPRESSOR - GRUB_MD_CRC32->write(s->crc32_context,b->in + s->in_start, in_used); + if (s->hash) + s->hash->write(s->hash_context,b->in + s->in_start, in_used); + if (s->crc32) + s->crc32->write(s->crc32_context,b->in + s->in_start, in_used); #endif } @@ -337,8 +358,9 @@ static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) s->index.hash.uncompressed += s->vli; #ifndef GRUB_EMBED_DECOMPRESSOR - GRUB_MD_CRC32->write(s->index.hash.crc32_context, - (const uint8_t *)&s->index.hash, 2 * sizeof(vli_type)); + if (s->hash) + s->hash->write(s->index.hash.hash_context, + (const uint8_t *)&s->index.hash, 2 * sizeof(vli_type)); #endif --s->index.count; @@ -354,13 +376,30 @@ static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) * 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) +static enum xz_ret hash_validate(struct xz_dec *s, struct xz_buf *b, + int crc32) { #ifndef GRUB_EMBED_DECOMPRESSOR - if(s->crc32_temp == 0) + const gcry_md_spec_t *hash = crc32 ? s->crc32 : s->hash; + grub_uint64_t *hash_context = crc32 ? s->crc32_context + : s->hash_context; + if(!s->have_hash_value && hash + && sizeof (s->hash_value) >= hash->mdlen) { - GRUB_MD_CRC32->final(s->crc32_context); - s->crc32_temp = get_unaligned_be32(GRUB_MD_CRC32->read(s->crc32_context)); + hash->final(hash_context); + grub_memcpy (s->hash_value, hash->read(hash_context), + hash->mdlen); + s->have_hash_value = 1; + if (s->hash_id == 1 || crc32) + { + grub_uint8_t t; + t = s->hash_value[0]; + s->hash_value[0] = s->hash_value[3]; + s->hash_value[3] = t; + t = s->hash_value[1]; + s->hash_value[1] = s->hash_value[2]; + s->hash_value[2] = t; + } } #endif @@ -369,23 +408,36 @@ static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b) return XZ_OK; #ifndef GRUB_EMBED_DECOMPRESSOR - if (((s->crc32_temp >> s->pos) & 0xFF) != b->in[b->in_pos++]) + if (hash && s->hash_value[s->pos / 8] != b->in[b->in_pos++]) return XZ_DATA_ERROR; #endif s->pos += 8; - } while (s->pos < 32); + } while (s->pos < (crc32 ? 32 : s->hash_size * 8)); #ifndef GRUB_EMBED_DECOMPRESSOR - GRUB_MD_CRC32->init(s->crc32_context); + if (s->hash) + s->hash->init(s->hash_context); + if (s->crc32) + s->crc32->init(s->crc32_context); #endif - s->crc32_temp = 0; + s->have_hash_value = 0; s->pos = 0; return XZ_STREAM_END; } +static const struct +{ + const char *name; + grub_size_t size; +} hashes[] = { + [0x01] = { "CRC32", 4}, + [0x04] = { "CRC64", 8}, + [0x0A] = { "SHA256", 32}, +}; + /* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ static enum xz_ret dec_stream_header(struct xz_dec *s) { @@ -393,28 +445,104 @@ static enum xz_ret dec_stream_header(struct xz_dec *s) return XZ_FORMAT_ERROR; #ifndef GRUB_EMBED_DECOMPRESSOR - uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + s->crc32 = grub_crypto_lookup_md_by_name ("CRC32"); - 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); + if (s->crc32) + { + uint64_t hash_context[(s->crc32->contextsize + 7) / 8]; + uint8_t resulthash[s->crc32->mdlen]; + uint8_t readhash[4]; - 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); + s->crc32->init(hash_context); + s->crc32->write(hash_context,s->temp.buf + HEADER_MAGIC_SIZE, 2); + s->crc32->final(hash_context); - if(resultcrc != readcrc) - return XZ_DATA_ERROR; + grub_memcpy (resulthash, s->crc32->read(hash_context), + s->crc32->mdlen); + readhash[0] = s->temp.buf[HEADER_MAGIC_SIZE + 5]; + readhash[1] = s->temp.buf[HEADER_MAGIC_SIZE + 4]; + readhash[2] = s->temp.buf[HEADER_MAGIC_SIZE + 3]; + readhash[3] = s->temp.buf[HEADER_MAGIC_SIZE + 2]; + + if(4 != s->crc32->mdlen + || grub_memcmp (readhash, resulthash, s->crc32->mdlen) != 0) + return XZ_DATA_ERROR; + } #endif +#ifndef GRUB_EMBED_DECOMPRESSOR /* - * Decode the Stream Flags field. Of integrity checks, we support - * only none (Check ID = 0) and CRC32 (Check ID = 1). + * Decode the Stream Flags field. */ if (s->temp.buf[HEADER_MAGIC_SIZE] != 0 - || s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1) + || s->temp.buf[HEADER_MAGIC_SIZE + 1] >= ARRAY_SIZE (hashes) + || (hashes[s->temp.buf[HEADER_MAGIC_SIZE + 1]].name == 0 + && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0)) return XZ_OPTIONS_ERROR; - s->has_crc32 = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + s->hash_id = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + + if (s->crc32) + { + s->crc32_context = kmalloc(s->crc32->contextsize, GFP_KERNEL); + if (s->crc32_context == NULL) + return XZ_MEMLIMIT_ERROR; + s->crc32->init(s->crc32_context); + } +#endif + + if (s->temp.buf[HEADER_MAGIC_SIZE + 1]) + { + s->hash_size = hashes[s->temp.buf[HEADER_MAGIC_SIZE + 1]].size; +#ifndef GRUB_EMBED_DECOMPRESSOR + s->hash = grub_crypto_lookup_md_by_name (hashes[s->temp.buf[HEADER_MAGIC_SIZE + 1]].name); + if (s->hash) + { + if (s->hash->mdlen != s->hash_size) + return XZ_OPTIONS_ERROR; + s->hash_context = kmalloc(s->hash->contextsize, GFP_KERNEL); + if (s->hash_context == NULL) + { + kfree(s->crc32_context); + return XZ_MEMLIMIT_ERROR; + } + + s->index.hash.hash_context = kmalloc(s->hash->contextsize, + GFP_KERNEL); + if (s->index.hash.hash_context == NULL) + { + kfree(s->hash_context); + kfree(s->crc32_context); + return XZ_MEMLIMIT_ERROR; + } + + s->block.hash.hash_context = kmalloc(s->hash->contextsize, GFP_KERNEL); + if (s->block.hash.hash_context == NULL) + { + kfree(s->index.hash.hash_context); + kfree(s->hash_context); + kfree(s->crc32_context); + return XZ_MEMLIMIT_ERROR; + } + + s->hash->init(s->hash_context); + s->hash->init(s->index.hash.hash_context); + s->hash->init(s->block.hash.hash_context); + } + if (!s->hash) + return XZ_OPTIONS_ERROR; +#endif + } + else + { +#ifndef GRUB_EMBED_DECOMPRESSOR + s->hash = 0; +#endif + s->hash_size = 0; + } + + s->have_hash_value = 0; + return XZ_OK; } @@ -426,19 +554,30 @@ static enum xz_ret dec_stream_footer(struct xz_dec *s) return XZ_DATA_ERROR; #ifndef GRUB_EMBED_DECOMPRESSOR - uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + if (s->crc32) + { + uint64_t hash_context[(s->crc32->contextsize + 7) / 8]; + uint8_t resulthash[s->crc32->mdlen]; + uint8_t readhash[4]; - GRUB_MD_CRC32->init(crc32_context); - GRUB_MD_CRC32->write(crc32_context, s->temp.buf + 4, 6); - GRUB_MD_CRC32->final(crc32_context); + s->crc32->init(hash_context); + s->crc32->write(hash_context,s->temp.buf + 4, 6); + s->crc32->final(hash_context); - uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context)); - uint32_t readcrc = get_unaligned_le32(s->temp.buf); + grub_memcpy (resulthash, s->crc32->read(hash_context), + s->crc32->mdlen); + readhash[0] = s->temp.buf[3]; + readhash[1] = s->temp.buf[2]; + readhash[2] = s->temp.buf[1]; + readhash[3] = s->temp.buf[0]; - if(resultcrc != readcrc) - return XZ_DATA_ERROR; + if(4 != s->crc32->mdlen + || grub_memcmp (readhash, resulthash, s->crc32->mdlen) != 0) + return XZ_DATA_ERROR; + } #endif + /* * 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 @@ -447,8 +586,10 @@ static enum xz_ret dec_stream_footer(struct xz_dec *s) 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) +#ifndef GRUB_EMBED_DECOMPRESSOR + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->hash_id) return XZ_DATA_ERROR; +#endif /* * Use XZ_STREAM_END instead of XZ_OK to be more convenient @@ -468,17 +609,27 @@ static enum xz_ret dec_block_header(struct xz_dec *s) */ s->temp.size -= 4; #ifndef GRUB_EMBED_DECOMPRESSOR - uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + if (s->crc32) + { + uint64_t hash_context[(s->crc32->contextsize + 7) / 8]; + uint8_t resulthash[s->crc32->mdlen]; + uint8_t readhash[4]; - GRUB_MD_CRC32->init(crc32_context); - GRUB_MD_CRC32->write(crc32_context, s->temp.buf, s->temp.size); - GRUB_MD_CRC32->final(crc32_context); + s->crc32->init(hash_context); + s->crc32->write(hash_context,s->temp.buf, s->temp.size); + s->crc32->final(hash_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); + grub_memcpy (resulthash, s->crc32->read(hash_context), + s->crc32->mdlen); + readhash[3] = s->temp.buf[s->temp.size]; + readhash[2] = s->temp.buf[s->temp.size + 1]; + readhash[1] = s->temp.buf[s->temp.size + 2]; + readhash[0] = s->temp.buf[s->temp.size + 3]; - if (resultcrc != readcrc) - return XZ_DATA_ERROR; + if(4 != s->crc32->mdlen + || grub_memcmp (readhash, resulthash, s->crc32->mdlen) != 0) + return XZ_DATA_ERROR; + } #endif s->temp.pos = 2; @@ -659,11 +810,9 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) 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; - } + ret = hash_validate(s, b, 0); + if (ret != XZ_STREAM_END) + return ret; s->sequence = SEQ_BLOCK_START; break; @@ -691,24 +840,31 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) index_update(s, b); #ifndef GRUB_EMBED_DECOMPRESSOR - /* Compare the hashes to validate the Index field. */ - GRUB_MD_CRC32->final(s->block.hash.crc32_context); - GRUB_MD_CRC32->final(s->index.hash.crc32_context); - uint32_t block_crc = *(uint32_t*)GRUB_MD_CRC32->read(s->block.hash.crc32_context); - uint32_t index_crc = *(uint32_t*)GRUB_MD_CRC32->read(s->index.hash.crc32_context); - - if (s->block.hash.unpadded != s->index.hash.unpadded - || s->block.hash.uncompressed != s->index.hash.uncompressed - || block_crc != index_crc) + if (s->hash) { - return XZ_DATA_ERROR; + uint8_t block_hash[s->hash->mdlen]; + uint8_t index_hash[s->hash->mdlen]; + /* Compare the hashes to validate the Index field. */ + s->hash->final(s->block.hash.hash_context); + s->hash->final(s->index.hash.hash_context); + grub_memcpy (block_hash, + s->hash->read(s->block.hash.hash_context), + s->hash->mdlen); + grub_memcpy (index_hash, + s->hash->read(s->index.hash.hash_context), + s->hash->mdlen); + + if (s->block.hash.unpadded != s->index.hash.unpadded + || s->block.hash.uncompressed != s->index.hash.uncompressed + || grub_memcmp (block_hash, index_hash, s->hash->mdlen) != 0) + return XZ_DATA_ERROR; } #endif s->sequence = SEQ_INDEX_CRC32; case SEQ_INDEX_CRC32: - ret = crc32_validate(s, b); + ret = hash_validate(s, b, 1); if (ret != XZ_STREAM_END) return ret; @@ -802,45 +958,7 @@ struct xz_dec * xz_dec_init(uint32_t dict_max) return NULL; #endif -#ifndef GRUB_EMBED_DECOMPRESSOR - /* 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); - GRUB_MD_CRC32->init(s->index.hash.crc32_context); - GRUB_MD_CRC32->init(s->block.hash.crc32_context); -#endif - - s->crc32_temp = 0; + memset (s, 0, sizeof (*s)); s->single_call = dict_max == 0; @@ -876,28 +994,31 @@ void xz_dec_reset(struct xz_dec *s) { #ifndef GRUB_EMBED_DECOMPRESSOR - uint8_t *t; - t = s->block.hash.crc32_context; + uint64_t *t; + t = s->block.hash.hash_context; #endif memzero(&s->block, sizeof(s->block)); #ifndef GRUB_EMBED_DECOMPRESSOR - s->block.hash.crc32_context = t; - t = s->index.hash.crc32_context; + s->block.hash.hash_context = t; + t = s->index.hash.hash_context; #endif memzero(&s->index, sizeof(s->index)); #ifndef GRUB_EMBED_DECOMPRESSOR - s->index.hash.crc32_context = t; + s->index.hash.hash_context = t; #endif } s->temp.pos = 0; s->temp.size = STREAM_HEADER_SIZE; #ifndef GRUB_EMBED_DECOMPRESSOR - GRUB_MD_CRC32->init(s->crc32_context); - GRUB_MD_CRC32->init(s->index.hash.crc32_context); - GRUB_MD_CRC32->init(s->block.hash.crc32_context); + if (s->hash) + { + s->hash->init(s->hash_context); + s->hash->init(s->index.hash.hash_context); + s->hash->init(s->block.hash.hash_context); + } #endif - s->crc32_temp = 0; + s->have_hash_value = 0; } void xz_dec_end(struct xz_dec *s) @@ -905,8 +1026,9 @@ void xz_dec_end(struct xz_dec *s) if (s != NULL) { xz_dec_lzma2_end(s->lzma2); #ifndef GRUB_EMBED_DECOMPRESSOR - kfree(s->index.hash.crc32_context); - kfree(s->block.hash.crc32_context); + kfree(s->index.hash.hash_context); + kfree(s->block.hash.hash_context); + kfree(s->hash_context); kfree(s->crc32_context); #endif #ifdef XZ_DEC_BCJ diff --git a/grub-core/loader/aout.c b/grub-core/loader/aout.c index 611960f92..69bf6e6ad 100644 --- a/grub-core/loader/aout.c +++ b/grub-core/loader/aout.c @@ -21,6 +21,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + int grub_aout_get_type (union grub_aout_header *header) { diff --git a/grub-core/loader/efi/appleloader.c b/grub-core/loader/efi/appleloader.c index dc42683a6..d0211a80f 100644 --- a/grub-core/loader/efi/appleloader.c +++ b/grub-core/loader/efi/appleloader.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; static grub_efi_handle_t image_handle; @@ -67,169 +69,64 @@ struct piwg_full_device_path struct grub_efi_device_path end; }; -/* early 2006 Core Duo / Core Solo models */ -static struct piwg_full_device_path devpath_1 = -{ - .comp1 = - { - .header = { - .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} - }, - .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, - .start_address = 0xffe00000, - .end_address = 0xfff9ffff - }, - .comp2 = - { - .header = { - .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_piwg_device_path), 0} - }, - .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7}} - }, - .end = - { - .type = GRUB_EFI_END_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_device_path), 0} +#define MAKE_PIWG_PATH(st, en) \ + { \ + .comp1 = \ + { \ + .header = { \ + .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, \ + .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, \ + .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} \ + }, \ + .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, \ + .start_address = st, \ + .end_address = en \ + }, \ + .comp2 = \ + { \ + .header = { \ + .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, \ + .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, \ + .length = {sizeof (struct grub_efi_piwg_device_path), 0} \ + }, \ + .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, \ + 0x01, 0xAE, 0xF2, 0xB7}} \ + }, \ + .end = \ + { \ + .type = GRUB_EFI_END_DEVICE_PATH_TYPE, \ + .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, \ + .length = {sizeof (struct grub_efi_device_path), 0} \ + } \ } -}; + +/* early 2006 Core Duo / Core Solo models */ +static struct piwg_full_device_path devpath_1 = MAKE_PIWG_PATH (0xffe00000, + 0xfff9ffff); /* mid-2006 Mac Pro (and probably other Core 2 models) */ -static struct piwg_full_device_path devpath_2 = -{ - .comp1 = - { - .header = { - .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} - }, - .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, - .start_address = 0xffe00000, - .end_address = 0xfff7ffff - }, - .comp2 = - { - .header = { - .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_piwg_device_path), 0} - }, - .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7}} - }, - .end = - { - .type = GRUB_EFI_END_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_device_path), 0} - } -}; +static struct piwg_full_device_path devpath_2 = MAKE_PIWG_PATH (0xffe00000, + 0xfff7ffff); /* mid-2007 MBP ("Santa Rosa" based models) */ -static struct piwg_full_device_path devpath_3 = -{ - .comp1 = - { - .header = { - .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} - }, - .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, - .start_address = 0xffe00000, - .end_address = 0xfff8ffff - }, - .comp2 = - { - .header = { - .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_piwg_device_path), 0} - }, - .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7}} - }, - .end = - { - .type = GRUB_EFI_END_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_device_path), 0} - } -}; +static struct piwg_full_device_path devpath_3 = MAKE_PIWG_PATH (0xffe00000, + 0xfff8ffff); /* early-2008 MBA */ -static struct piwg_full_device_path devpath_4 = -{ - .comp1 = - { - .header = { - .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} - }, - .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, - .start_address = 0xffc00000, - .end_address = 0xfff8ffff - }, - .comp2 = - { - .header = { - .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_piwg_device_path), 0} - }, - .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7}} - }, - .end = - { - .type = GRUB_EFI_END_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_device_path), 0} - } -}; +static struct piwg_full_device_path devpath_4 = MAKE_PIWG_PATH (0xffc00000, + 0xfff8ffff); /* late-2008 MB/MBP (NVidia chipset) */ -static struct piwg_full_device_path devpath_5 = -{ - .comp1 = - { - .header = { - .type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_memory_mapped_device_path), 0} - }, - .memory_type = GRUB_EFI_MEMORY_MAPPED_IO, - .start_address = 0xffcb4000, - .end_address = 0xffffbfff - }, - .comp2 = - { - .header = { - .type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_piwg_device_path), 0} - }, - .guid = {0x2B0585EB, 0xD8B8, 0x49A9, {0x8B, 0x8C, 0xE2, 0x1B, - 0x01, 0xAE, 0xF2, 0xB7}} - }, - .end = - { - .type = GRUB_EFI_END_DEVICE_PATH_TYPE, - .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE, - .length = {sizeof (struct grub_efi_device_path), 0} - } -}; +static struct piwg_full_device_path devpath_5 = MAKE_PIWG_PATH (0xffcb4000, + 0xffffbfff); + +/* mid-2010 MB/MBP (NVidia chipset) */ +static struct piwg_full_device_path devpath_6 = MAKE_PIWG_PATH (0xffcc4000, + 0xffffbfff); struct devdata { - char *model; + const char *model; grub_efi_device_path_t *devpath; }; @@ -240,6 +137,7 @@ struct devdata devs[] = {"MBP", (grub_efi_device_path_t *) &devpath_3}, {"MBA", (grub_efi_device_path_t *) &devpath_4}, {"MB NV", (grub_efi_device_path_t *) &devpath_5}, + {"MB NV2", (grub_efi_device_path_t *) &devpath_6}, {NULL, NULL}, }; diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c index a095ad931..3ecdca534 100644 --- a/grub-core/loader/efi/chainloader.c +++ b/grub-core/loader/efi/chainloader.c @@ -35,6 +35,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; static grub_efi_physical_address_t address; @@ -55,6 +57,7 @@ grub_chainloader_unload (void) grub_free (file_path); grub_free (cmdline); cmdline = 0; + file_path = 0; grub_dl_unref (my_mod); return GRUB_ERR_NONE; @@ -66,7 +69,7 @@ grub_chainloader_boot (void) grub_efi_boot_services_t *b; grub_efi_status_t status; grub_efi_uintn_t exit_data_size; - grub_efi_char16_t *exit_data; + grub_efi_char16_t *exit_data = NULL; b = grub_efi_system_table->boot_services; status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); @@ -93,7 +96,7 @@ grub_chainloader_boot (void) if (exit_data) efi_call_1 (b->free_pool, exit_data); - grub_chainloader_unload (); + grub_loader_unset (); return grub_errno; } @@ -236,6 +239,11 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), grub_efi_print_device_path (file_path); size = grub_file_size (file); + if (!size) + { + grub_error (GRUB_ERR_BAD_OS, "file is empty"); + goto fail; + } pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, @@ -321,8 +329,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), if (file) grub_file_close (file); - if (file_path) - grub_free (file_path); + grub_free (file_path); if (address) efi_call_2 (b->free_pages, address, pages); diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index b7cf115d9..835f14695 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -33,6 +33,10 @@ #include #include #include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #include #ifdef GRUB_MACHINE_PCBIOS @@ -65,7 +69,7 @@ static void *kern_chunk_src; static grub_uint32_t bootflags; static int is_elf_kernel, is_64bit; static grub_uint32_t openbsd_root; -struct grub_relocator *relocator = NULL; +static struct grub_relocator *relocator = NULL; static struct grub_openbsd_ramdisk_descriptor openbsd_ramdisk; struct bsd_tag @@ -202,7 +206,7 @@ grub_bsd_get_device (grub_uint32_t * biosdev, } grub_err_t -grub_bsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len) +grub_bsd_add_meta (grub_uint32_t type, const void *data, grub_uint32_t len) { struct bsd_tag *newtag; @@ -252,7 +256,7 @@ struct grub_e820_mmap #define GRUB_E820_RESERVED 2 #define GRUB_E820_ACPI 3 #define GRUB_E820_NVS 4 -#define GRUB_E820_EXEC_CODE 5 +#define GRUB_E820_BADRAM 5 static void generate_e820_mmap (grub_size_t *len, grub_size_t *cnt, void *buf) @@ -379,10 +383,11 @@ grub_bsd_add_mmap (void) } grub_err_t -grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, +grub_freebsd_add_meta_module (const char *filename, const char *type, + int argc, char **argv, grub_addr_t addr, grub_uint32_t size) { - char *name; + const char *name; name = grub_strrchr (filename, '/'); if (name) name++; @@ -446,7 +451,8 @@ grub_freebsd_list_modules (void) { struct bsd_tag *tag; - grub_printf (" %-18s %-18s%14s%14s\n", "name", "type", "addr", "size"); + grub_printf (" %-18s %-18s%14s%14s\n", _("name"), _("type"), _("addr"), + _("size")); for (tag = tags; tag; tag = tag->next) { @@ -511,7 +517,8 @@ grub_netbsd_list_modules (void) { struct netbsd_module *mod; - grub_printf (" %-18s%14s%14s%14s\n", "name", "type", "addr", "size"); + 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, @@ -521,6 +528,8 @@ grub_netbsd_list_modules (void) /* This function would be here but it's under different license. */ #include "bsd_pagetable.c" +static grub_uint32_t freebsd_bootdev, freebsd_biosdev; + static grub_err_t grub_freebsd_boot (void) { @@ -528,7 +537,6 @@ grub_freebsd_boot (void) 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; @@ -564,11 +572,7 @@ grub_freebsd_boot (void) bi.version = FREEBSD_BOOTINFO_VERSION; bi.length = sizeof (bi); - grub_bsd_get_device (&biosdev, &unit, &slice, &part); - bootdev = (FREEBSD_B_DEVMAGIC + ((slice + 1) << FREEBSD_B_SLICESHIFT) + - (unit << FREEBSD_B_UNITSHIFT) + (part << FREEBSD_B_PARTSHIFT)); - - bi.boot_device = biosdev; + bi.boot_device = freebsd_biosdev; p_size = 0; grub_env_iterate (iterate_env_count); @@ -741,7 +745,7 @@ grub_freebsd_boot (void) state.ebp = stack_target; stack[0] = entry; /* "Return" address. */ stack[1] = bootflags | FREEBSD_RB_BOOTINFO; - stack[2] = bootdev; + stack[2] = freebsd_bootdev; stack[3] = 0; stack[4] = 0; stack[5] = 0; @@ -947,6 +951,88 @@ grub_netbsd_add_modules (void) return err; } +/* + * Adds NetBSD bootinfo bootdisk and bootwedge. The partition identified + * in these bootinfo fields is the root device. + */ +static void +grub_netbsd_add_boot_disk_and_wedge (void) +{ + grub_device_t dev; + grub_disk_t disk; + grub_partition_t part; + grub_uint32_t biosdev; + grub_uint32_t partmapsector; + union { + grub_uint64_t raw[GRUB_DISK_SECTOR_SIZE / 8]; + struct grub_partition_bsd_disk_label label; + } buf; + grub_uint8_t *hash; + grub_uint64_t ctx[(GRUB_MD_MD5->contextsize + 7) / 8]; + + dev = grub_device_open (0); + if (! (dev && dev->disk && dev->disk->partition)) + goto fail; + + disk = dev->disk; + part = disk->partition; + + if (disk->dev && disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID) + biosdev = (grub_uint32_t) disk->id & 0xff; + else + biosdev = 0xff; + + /* Absolute sector of the partition map describing this partition. */ + partmapsector = grub_partition_get_start (part->parent) + part->offset; + + disk->partition = part->parent; + if (grub_disk_read (disk, part->offset, 0, GRUB_DISK_SECTOR_SIZE, buf.raw) + != GRUB_ERR_NONE) + goto fail; + disk->partition = part; + + /* Fill bootwedge. */ + { + struct grub_netbsd_btinfo_bootwedge biw; + + grub_memset (&biw, 0, sizeof (biw)); + biw.biosdev = biosdev; + biw.startblk = grub_partition_get_start (part); + biw.nblks = part->len; + biw.matchblk = partmapsector; + biw.matchnblks = 1; + + GRUB_MD_MD5->init (&ctx); + GRUB_MD_MD5->write (&ctx, buf.raw, GRUB_DISK_SECTOR_SIZE); + GRUB_MD_MD5->final (&ctx); + hash = GRUB_MD_MD5->read (&ctx); + memcpy (biw.matchhash, hash, 16); + + grub_bsd_add_meta (NETBSD_BTINFO_BOOTWEDGE, &biw, sizeof (biw)); + } + + /* Fill bootdisk if this a NetBSD disk label. */ + if (part->partmap != NULL && + (grub_strcmp (part->partmap->name, "netbsd") == 0) && + buf.label.magic == grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) + { + struct grub_netbsd_btinfo_bootdisk bid; + + grub_memset (&bid, 0, sizeof (bid)); + bid.labelsector = partmapsector; + bid.label.type = buf.label.type; + bid.label.checksum = buf.label.checksum; + memcpy (bid.label.packname, buf.label.packname, 16); + bid.biosdev = biosdev; + bid.partition = part->number; + grub_bsd_add_meta (NETBSD_BTINFO_BOOTDISK, &bid, sizeof (bid)); + } + +fail: + if (dev) + grub_device_close (dev); +} + static grub_err_t grub_netbsd_boot (void) { @@ -967,7 +1053,7 @@ grub_netbsd_boot (void) if (err) { grub_print_error (); - grub_printf ("Booting however\n"); + grub_puts_ (N_("Booting in blind mode")); grub_errno = GRUB_ERR_NONE; } @@ -1073,7 +1159,7 @@ grub_bsd_unload (void) } static grub_err_t -grub_bsd_load_aout (grub_file_t file) +grub_bsd_load_aout (grub_file_t file, const char *filename) { grub_addr_t load_addr, load_end; int ofs, align_page; @@ -1085,7 +1171,12 @@ grub_bsd_load_aout (grub_file_t file) return grub_errno; if (grub_file_read (file, &ah, sizeof (ah)) != sizeof (ah)) - return grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + { + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"), + filename); + return grub_errno; + } if (grub_aout_get_type (&ah) != AOUT_TYPE_AOUT32) return grub_error (GRUB_ERR_BAD_OS, "invalid a.out header"); @@ -1323,6 +1414,11 @@ grub_bsd_load (int argc, char *argv[]) goto fail; relocator = grub_relocator_new (); + if (!relocator) + { + grub_file_close (file); + goto fail; + } elf = grub_elf_file (file); if (elf) @@ -1335,7 +1431,7 @@ grub_bsd_load (int argc, char *argv[]) { is_elf_kernel = 0; grub_errno = 0; - grub_bsd_load_aout (file); + grub_bsd_load_aout (file, argv[0]); grub_file_close (file); } @@ -1344,7 +1440,7 @@ grub_bsd_load (int argc, char *argv[]) fail: if (grub_errno != GRUB_ERR_NONE) - grub_dl_unref (my_mod); + grub_dl_unref (my_mod); return grub_errno; } @@ -1371,6 +1467,8 @@ grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { + grub_uint32_t unit, slice, part; + kern_end = ALIGN_PAGE (kern_end); if (is_elf_kernel) { @@ -1414,6 +1512,10 @@ grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) if (err) return err; } + grub_bsd_get_device (&freebsd_biosdev, &unit, &slice, &part); + freebsd_bootdev = (FREEBSD_B_DEVMAGIC + ((slice + 1) << FREEBSD_B_SLICESHIFT) + + (unit << FREEBSD_B_UNITSHIFT) + (part << FREEBSD_B_PARTSHIFT)); + grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 0); } @@ -1597,6 +1699,8 @@ grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &cons, sizeof (cons)); } + grub_netbsd_add_boot_disk_and_wedge (); + grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 0); } @@ -1611,7 +1715,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), char *buf = 0, *curr, *next; int len; - if (kernel_type == KERNEL_TYPE_NONE) + if (! grub_loader_is_loaded ()) return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); @@ -1708,7 +1812,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; int modargc; char **modargv; - char *type; + const char *type; grub_err_t err; void *src; @@ -1844,7 +1948,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; grub_err_t err; - if (kernel_type == KERNEL_TYPE_NONE) + if (! grub_loader_is_loaded ()) return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); @@ -1901,8 +2005,7 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)), file = grub_file_open (args[0]); if (! file) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, - "couldn't load ramdisk"); + return grub_errno; size = grub_file_size (file); @@ -1918,8 +2021,9 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)), != (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]); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]); + return grub_errno; } grub_memset (openbsd_ramdisk.target + size, 0, openbsd_ramdisk.max_size - size); @@ -1965,7 +2069,7 @@ GRUB_MOD_INIT (bsd) cmd_openbsd_ramdisk = grub_register_command ("kopenbsd_ramdisk", grub_cmd_openbsd_ramdisk, 0, - "Load kOpenBSD ramdisk. "); + N_("Load kOpenBSD ramdisk.")); my_mod = mod; } diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index 073f01da2..7cec7a8ef 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -195,6 +195,11 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, chunk_size = s->sh_addr + s->sh_size; } + if (chunk_size < sizeof (e)) + chunk_size = sizeof (e); + chunk_size += e.e_phnum * e.e_phentsize; + chunk_size += e.e_shnum * e.e_shentsize; + { grub_relocator_chunk_t ch; @@ -239,16 +244,16 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, curload = module + s->sh_addr + s->sh_size; } - load (file, UINT_TO_PTR (module), 0, sizeof (e)); + load (file, (grub_uint8_t *) chunk_src + module - *kern_end, 0, sizeof (e)); if (curload < module + sizeof (e)) curload = module + sizeof (e); - load (file, UINT_TO_PTR (curload), e.e_shoff, + load (file, (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_shoff, e.e_shnum * e.e_shentsize); e.e_shoff = curload - module; curload += e.e_shnum * e.e_shentsize; - load (file, UINT_TO_PTR (curload), e.e_phoff, + load (file, (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_phoff, e.e_phnum * e.e_phentsize); e.e_phoff = curload - module; curload += e.e_phnum * e.e_phentsize; @@ -394,12 +399,10 @@ SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, grub_err_t err; Elf_Ehdr e; Elf_Shdr *s, *symsh, *strsh; - char *shdr; + char *shdr = NULL; 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; @@ -473,7 +476,6 @@ SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, 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) @@ -484,7 +486,6 @@ SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, 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) @@ -515,7 +516,7 @@ SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file, grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; - char *shdr; + char *shdr = NULL; err = read_headers (file, &e, &shdr); if (err) diff --git a/grub-core/loader/i386/bsd_pagetable.c b/grub-core/loader/i386/bsd_pagetable.c index 13348cc83..9ec5abffc 100644 --- a/grub-core/loader/i386/bsd_pagetable.c +++ b/grub-core/loader/i386/bsd_pagetable.c @@ -53,7 +53,7 @@ static void fill_bsd64_pagetable (grub_uint8_t *src, grub_addr_t target) { grub_uint64_t *pt2, *pt3, *pt4; - grub_addr_t pt2t, pt3t, pt4t; + grub_addr_t pt2t, pt3t; int i; #define PG_V 0x001 @@ -65,7 +65,6 @@ fill_bsd64_pagetable (grub_uint8_t *src, grub_addr_t target) pt3 = (grub_uint64_t *) (src + 4096); pt2 = (grub_uint64_t *) (src + 8192); - pt4t = target; pt3t = target + 4096; pt2t = target + 8192; diff --git a/grub-core/loader/i386/coreboot/chainloader.c b/grub-core/loader/i386/coreboot/chainloader.c new file mode 100644 index 000000000..3f85aa3a9 --- /dev/null +++ b/grub-core/loader/i386/coreboot/chainloader.c @@ -0,0 +1,145 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_addr_t entry; +static struct grub_relocator *relocator = NULL; + +static grub_err_t +grub_chain_boot (void) +{ + struct grub_relocator32_state state; + + grub_video_set_mode ("text", 0, 0); + + state.eip = entry; + return grub_relocator32_boot (relocator, state); +} + +static grub_err_t +grub_chain_unload (void) +{ + grub_relocator_unload (relocator); + relocator = NULL; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_chain_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load) +{ + grub_err_t err; + grub_relocator_chunk_t ch; + + if (phdr->p_type != PT_LOAD) + { + *do_load = 0; + return 0; + } + + *do_load = 1; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + phdr->p_paddr, phdr->p_memsz); + if (err) + return err; + + *addr = (grub_addr_t) get_virtual_current_address (ch); + + return GRUB_ERR_NONE; +} + + +static grub_err_t +grub_cmd_chain (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_err_t err; + grub_file_t file; + grub_elf_t elf; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "filename expected"); + + grub_loader_unset (); + + file = grub_file_open (argv[0]); + if (!file) + return grub_errno; + + relocator = grub_relocator_new (); + if (!relocator) + { + grub_file_close (file); + return grub_errno; + } + + elf = grub_elf_file (file); + if (!elf) + { + grub_relocator_unload (relocator); + relocator = 0; + grub_file_close (file); + } + + if (!grub_elf_is_elf32 (elf)) + { + grub_relocator_unload (relocator); + relocator = 0; + grub_elf_close (elf); + } + + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; + + err = grub_elf32_load (elf, grub_chain_elf32_hook, 0, 0); + + grub_elf_close (elf); + if (err) + return err; + + grub_loader_set (grub_chain_boot, grub_chain_unload, 0); + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_chain; + +GRUB_MOD_INIT (chain) +{ + cmd_chain = grub_register_command ("chainloader", grub_cmd_chain, + N_("FILE"), N_("Load another payload")); +} + +GRUB_MOD_FINI (chain) +{ + grub_unregister_command (cmd_chain); + grub_chain_unload (); +} diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index d7622dabd..a5bcb24b2 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -33,6 +33,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #ifdef GRUB_MACHINE_PCBIOS #include @@ -42,19 +45,21 @@ #include #define HAS_VGA_TEXT 0 #define DEFAULT_VIDEO_MODE "auto" +#define ACCEPTS_PURE_TEXT 0 #elif defined (GRUB_MACHINE_IEEE1275) #include #define HAS_VGA_TEXT 0 #define DEFAULT_VIDEO_MODE "text" +#define ACCEPTS_PURE_TEXT 1 #else #include #include #define HAS_VGA_TEXT 1 #define DEFAULT_VIDEO_MODE "text" +#define ACCEPTS_PURE_TEXT 1 #endif #define GRUB_LINUX_CL_OFFSET 0x1000 -#define GRUB_LINUX_CL_END_OFFSET 0x2000 static grub_dl_t my_mod; @@ -71,6 +76,7 @@ static grub_uint32_t prot_mode_pages; static grub_uint32_t initrd_pages; static struct grub_relocator *relocator = NULL; static void *efi_mmap_buf; +static grub_size_t maximal_cmdline_size; #ifdef GRUB_MACHINE_EFI static grub_efi_uintn_t efi_mmap_size; #else @@ -124,7 +130,10 @@ find_efi_mmap_size (void) grub_free (mmap); if (ret < 0) - grub_fatal ("cannot get memory map"); + { + grub_error (GRUB_ERR_IO, "cannot get memory map"); + return 0; + } else if (ret > 0) break; @@ -135,7 +144,8 @@ find_efi_mmap_size (void) later, and EFI itself may allocate more. */ mmap_size += (1 << 12); - return page_align (mmap_size); + mmap_size = page_align (mmap_size); + return mmap_size; } #endif @@ -185,12 +195,14 @@ allocate_pages (grub_size_t prot_size) grub_err_t err; /* Make sure that each size is aligned to a page boundary. */ - real_size = GRUB_LINUX_CL_END_OFFSET; + real_size = GRUB_LINUX_CL_OFFSET + maximal_cmdline_size; prot_size = page_align (prot_size); mmap_size = find_mmap_size (); #ifdef GRUB_MACHINE_EFI efi_mmap_size = find_efi_mmap_size (); + if (efi_mmap_size == 0) + return grub_errno; #endif grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", @@ -284,7 +296,7 @@ allocate_pages (grub_size_t prot_size) return err; } -static void +static grub_err_t 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) @@ -292,7 +304,10 @@ grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, int n = *e820_num; if (n >= GRUB_E820_MAX_ENTRY) - grub_fatal ("Too many e820 memory map entries"); + { + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "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)) @@ -304,6 +319,7 @@ grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, e820_map[n].type = type; (*e820_num)++; } + return GRUB_ERR_NONE; } static grub_err_t @@ -312,6 +328,13 @@ grub_linux_setup_video (struct linux_kernel_params *params) struct grub_video_mode_info mode_info; void *framebuffer; grub_err_t err; + grub_video_driver_id_t driver_id; + const char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb"); + + driver_id = grub_video_get_driver_id (); + + if (driver_id == GRUB_VIDEO_DRIVER_NONE) + return 1; err = grub_video_get_info_and_fini (&mode_info, &framebuffer); @@ -338,12 +361,42 @@ grub_linux_setup_video (struct linux_kernel_params *params) params->reserved_mask_size = mode_info.reserved_mask_size; params->reserved_field_pos = mode_info.reserved_field_pos; + if (gfxlfbvar && (gfxlfbvar[0] == '1' || gfxlfbvar[0] == 'y')) + params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + else + { + switch (driver_id) + { + case GRUB_VIDEO_DRIVER_VBE: + params->lfb_size >>= 16; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; + break; + + case GRUB_VIDEO_DRIVER_EFI_UGA: + case GRUB_VIDEO_DRIVER_EFI_GOP: + params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFIFB; + break; + + /* FIXME: check if better id is available. */ + case GRUB_VIDEO_DRIVER_SM712: + case GRUB_VIDEO_DRIVER_SIS315PRO: + case GRUB_VIDEO_DRIVER_VGA: + case GRUB_VIDEO_DRIVER_CIRRUS: + case GRUB_VIDEO_DRIVER_BOCHS: + case GRUB_VIDEO_DRIVER_RADEON_FULOONG2E: + /* Make gcc happy. */ + case GRUB_VIDEO_DRIVER_SDL: + case GRUB_VIDEO_DRIVER_NONE: + params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + break; + } + } #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) + if (driver_id == GRUB_VIDEO_DRIVER_VBE && mode_info.bpp <= 8) { struct grub_vbe_info_block controller_info; int status; @@ -374,14 +427,15 @@ grub_linux_boot (void) struct linux_kernel_params *params; int e820_num; grub_err_t err = 0; - char *modevar, *tmp; + const char *modevar; + char *tmp; struct grub_relocator32_state state; params = real_mode_mem; #ifdef GRUB_MACHINE_IEEE1275 { - char *bootpath; + const char *bootpath; grub_ssize_t len; bootpath = grub_env_get ("root"); @@ -401,37 +455,38 @@ grub_linux_boot (void) int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type) { + grub_uint32_t e820_type; switch (type) { case GRUB_MEMORY_AVAILABLE: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_RAM); + e820_type = GRUB_E820_RAM; break; case GRUB_MEMORY_ACPI: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_ACPI); + e820_type = GRUB_E820_ACPI; break; case GRUB_MEMORY_NVS: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_NVS); + e820_type = GRUB_E820_NVS; break; - case GRUB_MEMORY_CODE: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_EXEC_CODE); + case GRUB_MEMORY_BADRAM: + e820_type = GRUB_E820_BADRAM; break; default: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_RESERVED); + e820_type = GRUB_E820_RESERVED; } + if (grub_e820_add_region (params->e820_map, &e820_num, + addr, size, e820_type)) + return 1; + return 0; } e820_num = 0; - grub_mmap_iterate (hook); + if (grub_mmap_iterate (hook)) + return grub_errno; params->mmap_size = e820_num; modevar = grub_env_get ("gfxpayload"); @@ -443,28 +498,30 @@ grub_linux_boot (void) tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) return grub_errno; +#if ACCEPTS_PURE_TEXT err = grub_video_set_mode (tmp, 0, 0); +#else + err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +#endif grub_free (tmp); } else - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); - + { +#if ACCEPTS_PURE_TEXT + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); +#else + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +#endif + } if (err) { grub_print_error (); - grub_printf ("Booting however\n"); + grub_puts_ (N_("Booting in blind mode")); grub_errno = GRUB_ERR_NONE; } - if (! grub_linux_setup_video (params)) - { - /* Use generic framebuffer unless VESA is known to be supported. */ - if (params->have_vga != GRUB_VIDEO_LINUX_TYPE_VESA) - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; - else - params->lfb_size >>= 16; - } - else + if (grub_linux_setup_video (params)) { #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; @@ -518,6 +575,7 @@ grub_linux_boot (void) #ifdef GRUB_MACHINE_EFI { grub_efi_uintn_t efi_desc_size; + grub_size_t efi_mmap_target; 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); @@ -525,23 +583,24 @@ grub_linux_boot (void) return err; /* Note that no boot services are available from here. */ - + efi_mmap_target = real_mode_target + + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem); /* 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 = efi_mmap_target; 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); + params->v0206.efi_mmap_hi = (efi_mmap_target >> 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 = efi_mmap_target; params->v0204.efi_mmap_size = efi_mmap_size; } } @@ -575,7 +634,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_size_t real_size, prot_size; grub_ssize_t len; int i; - char *dest; grub_dl_ref (my_mod); @@ -591,7 +649,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"), + argv[0]); goto fail; } @@ -630,6 +690,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } + if (grub_le_to_cpu16 (lh.version) >= 0x0206) + maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1; + else + maximal_cmdline_size = 256; + + if (maximal_cmdline_size < 128) + maximal_cmdline_size = 128; + setup_sects = lh.setup_sects; /* If SETUP_SECTS is not set, set it to the default (4). */ @@ -643,7 +711,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; params = (struct linux_kernel_params *) real_mode_mem; - grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET); + grub_memset (params, 0, GRUB_LINUX_CL_OFFSET + maximal_cmdline_size); grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1); params->ps_mouse = params->padding10 = 0; @@ -651,11 +719,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), 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"); + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); goto fail; } - params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4); + params->type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; /* These two are used (instead of cmd_line_ptr) by older versions of Linux, and otherwise ignored. */ @@ -719,13 +789,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_err_t err; char *buf; + grub_dl_load ("vbe"); + if (grub_strcmp (val, "normal") == 0) vid_mode = GRUB_LINUX_VID_MODE_NORMAL; else if (grub_strcmp (val, "ext") == 0) vid_mode = GRUB_LINUX_VID_MODE_EXTENDED; else if (grub_strcmp (val, "ask") == 0) { - grub_printf ("Legacy `ask' parameter no longer supported.\n"); + grub_puts_ (N_("Legacy `ask' parameter no longer supported.")); /* We usually would never do this in a loader, but "vga=ask" means user requested interaction, so it can't hurt to request keyboard input. */ @@ -741,9 +813,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), case 0: case GRUB_LINUX_VID_MODE_NORMAL: grub_env_set ("gfxpayload", "text"); - grub_printf ("%s is deprecated. " - "Use set gfxpayload=text before " - "linux command instead.\n", + grub_printf_ (N_("%s is deprecated. " + "Use set gfxpayload=text before " + "linux command instead.\n"), argv[i]); break; @@ -751,9 +823,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), case GRUB_LINUX_VID_MODE_EXTENDED: /* FIXME: support 80x50 text. */ grub_env_set ("gfxpayload", "text"); - grub_printf ("%s is deprecated. " - "Use set gfxpayload=text before " - "linux command instead.\n", + grub_printf_ (N_("%s is deprecated. " + "Use set gfxpayload=text before " + "linux command instead.\n"), argv[i]); break; default: @@ -762,17 +834,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), vid_mode > GRUB_VESA_MODE_TABLE_END) { grub_env_set ("gfxpayload", "text"); - grub_printf ("%s is deprecated. Mode %d isn't recognized. " - "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] before " - "linux command instead.\n", + grub_printf_ (N_("%s is deprecated. Mode %d isn't recognized. " + "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] " + "before linux command instead.\n"), argv[i], vid_mode); break; } - /* We can't detect VESA, but user is implicitly telling us that it - is built-in because `vga=' parameter was used. */ - params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; - linux_mode = &grub_vesa_mode_table[vid_mode - GRUB_VESA_MODE_TABLE_START]; @@ -783,9 +851,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! buf) goto fail; - grub_printf ("%s is deprecated. " - "Use set gfxpayload=%s before " - "linux command instead.\n", + grub_printf_ (N_("%s is deprecated. " + "Use set gfxpayload=%s before " + "linux command instead.\n"), argv[i], buf); err = grub_env_set ("gfxpayload", buf); grub_free (buf); @@ -834,26 +902,19 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), params->loadflags |= GRUB_LINUX_FLAG_QUIET; } - - /* 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]); - } + /* Create kernel command line. */ + grub_memcpy ((char *)real_mode_mem + GRUB_LINUX_CL_OFFSET, LINUX_IMAGE, + sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, + (char *)real_mode_mem + GRUB_LINUX_CL_OFFSET + + sizeof (LINUX_IMAGE) - 1, + maximal_cmdline_size + - (sizeof (LINUX_IMAGE) - 1)); len = prot_size; - if (grub_file_read (file, prot_mode_mem, len) != len) - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); + if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); if (grub_errno == GRUB_ERR_NONE) { @@ -880,12 +941,15 @@ 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_file_t *files = 0; + grub_size_t size = 0; grub_addr_t addr_min, addr_max; grub_addr_t addr; grub_err_t err; struct linux_kernel_header *lh; + int i; + int nfiles = 0; + grub_uint8_t *ptr; if (argc == 0) { @@ -899,12 +963,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - grub_file_filter_disable_compression (); - file = grub_file_open (argv[0]); - if (! file) + files = grub_zalloc (argc * sizeof (files[0])); + if (!files) goto fail; - size = grub_file_size (file); + for (i = 0; i < argc; i++) + { + grub_file_filter_disable_compression (); + files[i] = grub_file_open (argv[i]); + if (! files[i]) + goto fail; + nfiles++; + size += grub_file_size (files[i]); + } + initrd_pages = (page_align (size) >> 12); lh = (struct linux_kernel_header *) real_mode_mem; @@ -956,10 +1028,18 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), initrd_mem_target = get_physical_target_address (ch); } - if (grub_file_read (file, initrd_mem, size) != size) + ptr = initrd_mem; + for (i = 0; i < nfiles; i++) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; + grub_ssize_t cursize = grub_file_size (files[i]); + if (grub_file_read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + goto fail; + } + ptr += cursize; } grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", @@ -970,8 +1050,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), lh->root_dev = 0x0100; /* XXX */ fail: - if (file) - grub_file_close (file); + for (i = 0; i < nfiles; i++) + grub_file_close (files[i]); + grub_free (files); return grub_errno; } diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index 79f72ee0f..abd4ae96d 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -33,6 +33,7 @@ #include #include #include +#include /* The bits in the required part of flags field we don't support. */ #define UNSUPPORTED_FLAGS 0x0000fff8 @@ -46,7 +47,7 @@ struct module int cmdline_size; }; -struct module *modules, *modules_last; +static struct module *modules, *modules_last; static grub_size_t cmdline_size; static grub_size_t total_modcmd; static unsigned modcnt; @@ -141,7 +142,7 @@ grub_multiboot_load (grub_file_t file) } if (header->bss_end_addr) - grub_memset ((grub_uint32_t *) source + load_size, 0, + grub_memset ((grub_uint8_t *) source + load_size, 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; @@ -194,7 +195,10 @@ grub_multiboot_load (grub_file_t file) static grub_size_t grub_multiboot_get_mbi_size (void) { - return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + grub_size_t ret; + struct grub_net_network_level_interface *net; + + ret = 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) @@ -205,6 +209,15 @@ grub_multiboot_get_mbi_size (void) + sizeof (struct grub_vbe_mode_info_block) #endif + ALIGN_UP (sizeof (struct multiboot_apm_info), 4); + + FOR_NET_NETWORK_LEVEL_INTERFACES(net) + if (net->dhcp_ack) + { + ret += net->dhcp_acklen; + break; + } + + return ret; } /* Fill previously allocated Multiboot mmap. */ @@ -435,13 +448,13 @@ grub_multiboot_make_mbi (grub_uint32_t *target) bufsize = grub_multiboot_get_mbi_size (); err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, - 0, 0xffffffff - bufsize, + 0x10000, 0x100000 - 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); + ptrdest = get_physical_target_address (ch); *target = ptrdest; @@ -530,6 +543,20 @@ grub_multiboot_make_mbi (grub_uint32_t *target) mbi->flags |= MULTIBOOT_INFO_BOOTDEV; } + { + struct grub_net_network_level_interface *net; + FOR_NET_NETWORK_LEVEL_INTERFACES(net) + if (net->dhcp_ack) + { + grub_memcpy (ptrorig, net->dhcp_ack, net->dhcp_acklen); + mbi->drives_addr = ptrdest; + mbi->drives_length = net->dhcp_acklen; + ptrorig += net->dhcp_acklen; + ptrdest += net->dhcp_acklen; + break; + } + } + if (elf_sec_num) { mbi->u.elf_sec.addr = ptrdest; @@ -539,6 +566,9 @@ grub_multiboot_make_mbi (grub_uint32_t *target) mbi->u.elf_sec.shndx = elf_sec_shstrndx; mbi->flags |= MULTIBOOT_INFO_ELF_SHDR; + + ptrorig += elf_sec_entsize * elf_sec_num; + ptrdest += elf_sec_entsize * elf_sec_num; } err = retrieve_video_parameters (mbi, ptrorig, ptrdest); @@ -547,6 +577,16 @@ grub_multiboot_make_mbi (grub_uint32_t *target) grub_print_error (); grub_errno = GRUB_ERR_NONE; } + + if ((mbi->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) + && mbi->framebuffer_type == MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED) + { + ptrorig += mbi->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + ptrdest += mbi->framebuffer_palette_num_colors + * sizeof (struct multiboot_color); + } + #if GRUB_MACHINE_HAS_VBE ptrorig += sizeof (struct grub_vbe_info_block); ptrdest += sizeof (struct grub_vbe_info_block); @@ -641,6 +681,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size, return grub_errno; newmod->start = start; newmod->size = size; + newmod->next = 0; for (i = 0; i < argc; i++) len += grub_strlen (argv[i]) + 1; diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c index fd99c81d5..30b1e8b09 100644 --- a/grub-core/loader/i386/pc/chainloader.c +++ b/grub-core/loader/i386/pc/chainloader.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -37,28 +36,110 @@ #include #include #include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_dl_t my_mod; static int boot_drive; -static void *boot_part_addr; +static grub_addr_t boot_part_addr; +static struct grub_relocator *rel; + +typedef enum + { + GRUB_CHAINLOADER_FORCE = 0x1, + GRUB_CHAINLOADER_BPB = 0x2, + } grub_chainloader_flags_t; static grub_err_t grub_chainloader_boot (void) { + struct grub_relocator16_state state = { + .edx = boot_drive, + .esi = boot_part_addr, + .ds = 0, + .es = 0, + .fs = 0, + .gs = 0, + .ss = 0, + .cs = 0, + .sp = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR, + .ip = GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR, + .a20 = 0 + }; grub_video_set_mode ("text", 0, 0); - grub_chainloader_real_boot (boot_drive, boot_part_addr); - /* Never reach here. */ - return GRUB_ERR_NONE; + return grub_relocator16_boot (rel, state); } static grub_err_t grub_chainloader_unload (void) { + grub_relocator_unload (rel); + rel = NULL; grub_dl_unref (my_mod); return GRUB_ERR_NONE; } +void +grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl) +{ + grub_uint32_t part_start = 0; + if (dev && dev->disk) + part_start = grub_partition_get_start (dev->disk->partition); + if (grub_memcmp ((char *) &((struct grub_ntfs_bpb *) bs)->oem_name, + "NTFS", 4) == 0) + { + struct grub_ntfs_bpb *bpb = (struct grub_ntfs_bpb *) bs; + bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start); + bpb->bios_drive = dl; + return; + } + + do + { + struct grub_fat_bpb *bpb = (struct grub_fat_bpb *) bs; + if (grub_strncmp((const char *) bpb->version_specific.fat12_or_fat16.fstype, "FAT12", 5) + && grub_strncmp((const char *) bpb->version_specific.fat12_or_fat16.fstype, "FAT16", 5) + && grub_strncmp((const char *) bpb->version_specific.fat32.fstype, "FAT32", 5)) + break; + + if (grub_le_to_cpu16 (bpb->bytes_per_sector) < 512 + || (grub_le_to_cpu16 (bpb->bytes_per_sector) + & (grub_le_to_cpu16 (bpb->bytes_per_sector) - 1))) + break; + + if (bpb->sectors_per_cluster == 0 + || (bpb->sectors_per_cluster & (bpb->sectors_per_cluster - 1))) + break; + + if (bpb->num_reserved_sectors == 0) + break; + if (bpb->num_total_sectors_16 == 0 || bpb->num_total_sectors_32 == 0) + break; + + if (bpb->num_fats == 0) + break; + + if (bpb->sectors_per_fat_16) + { + bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start); + bpb->version_specific.fat12_or_fat16.num_ph_drive = dl; + return; + } + if (bpb->version_specific.fat32.sectors_per_fat_32) + { + bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start); + bpb->version_specific.fat32.num_ph_drive = dl; + return; + } + break; + } + while (0); +} + static void grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) { @@ -66,7 +147,12 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) grub_uint16_t signature; grub_device_t dev; int drive = -1; - void *part_addr = 0; + grub_addr_t part_addr = 0; + grub_uint8_t *bs, *ptable; + + rel = grub_relocator_new (); + if (!rel) + goto fail; grub_dl_ref (my_mod); @@ -75,8 +161,25 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) if (! file) goto fail; + { + grub_relocator_chunk_t ch; + grub_err_t err; + + err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00, + GRUB_DISK_SECTOR_SIZE); + if (err) + goto fail; + bs = get_virtual_current_address (ch); + err = grub_relocator_alloc_chunk_addr (rel, &ch, + GRUB_MEMORY_MACHINE_PART_TABLE_ADDR, + 64); + if (err) + goto fail; + ptable = get_virtual_current_address (ch); + } + /* Read the first block. */ - if (grub_file_read (file, (void *) 0x7C00, GRUB_DISK_SECTOR_SIZE) + if (grub_file_read (file, bs, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE) { if (grub_errno == GRUB_ERR_NONE) @@ -86,7 +189,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) } /* Check the signature. */ - signature = *((grub_uint16_t *) (0x7C00 + GRUB_DISK_SECTOR_SIZE - 2)); + signature = *((grub_uint16_t *) (bs + GRUB_DISK_SECTOR_SIZE - 2)); if (signature != grub_le_to_cpu16 (0xaa55) && ! (flags & GRUB_CHAINLOADER_FORCE)) { @@ -110,15 +213,17 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) if (p && grub_strcmp (p->partmap->name, "msdos") == 0) { disk->partition = p->parent; - grub_disk_read (disk, p->offset, 446, 64, - (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); - part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR - + (p->index << 4)); + grub_disk_read (disk, p->offset, 446, 64, ptable); + part_addr = (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR + + (p->index << 4)); disk->partition = p; } } } + if (flags & GRUB_CHAINLOADER_BPB) + grub_chainloader_patch_bpb ((void *) 0x7C00, dev, drive); + if (dev) grub_device_close (dev); @@ -145,11 +250,23 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), { grub_chainloader_flags_t flags = 0; - if (argc > 0 && grub_strcmp (argv[0], "--force") == 0) + while (argc > 0) { - flags |= GRUB_CHAINLOADER_FORCE; - argc--; - argv++; + if (grub_strcmp (argv[0], "--force") == 0) + { + flags |= GRUB_CHAINLOADER_FORCE; + argc--; + argv++; + continue; + } + if (grub_strcmp (argv[0], "--bpb") == 0) + { + flags |= GRUB_CHAINLOADER_BPB; + argc--; + argv++; + continue; + } + break; } if (argc == 0) @@ -165,7 +282,8 @@ static grub_command_t cmd; GRUB_MOD_INIT(chainloader) { cmd = grub_register_command ("chainloader", grub_cmd_chainloader, - 0, N_("Load another boot loader.")); + N_("[--force|--bpb] FILE"), + N_("Load another boot loader.")); my_mod = mod; } diff --git a/grub-core/loader/i386/pc/freedos.c b/grub-core/loader/i386/pc/freedos.c new file mode 100644 index 000000000..1f088e2b5 --- /dev/null +++ b/grub-core/loader/i386/pc/freedos.c @@ -0,0 +1,139 @@ +/* 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_dl_t my_mod; +static struct grub_relocator *rel; +static grub_uint32_t ebx = 0xffffffff; + +#define GRUB_FREEDOS_SEGMENT 0x60 +#define GRUB_FREEDOS_STACK_SEGMENT 0x1fe0 +#define GRUB_FREEDOS_STACK_POINTER 0x8000 + +static grub_err_t +grub_freedos_boot (void) +{ + struct grub_relocator16_state state = { + .cs = GRUB_FREEDOS_SEGMENT, + .ip = 0, + .ds = 0, + .es = 0, + .fs = 0, + .gs = 0, + .ss = GRUB_FREEDOS_STACK_SEGMENT, + .sp = GRUB_FREEDOS_STACK_POINTER, + .ebx = ebx, + .edx = 0, + .a20 = 1 + }; + grub_video_set_mode ("text", 0, 0); + + return grub_relocator16_boot (rel, state); +} + +static grub_err_t +grub_freedos_unload (void) +{ + grub_relocator_unload (rel); + rel = NULL; + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_freedos (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_err_t err; + void *kernelsys; + grub_size_t kernelsyssize; + + 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; + + ebx = grub_get_root_biosnumber (); + + kernelsyssize = grub_file_size (file); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_FREEDOS_SEGMENT << 4, + kernelsyssize); + if (err) + goto fail; + kernelsys = get_virtual_current_address (ch); + } + + if (grub_file_read (file, kernelsys, kernelsyssize) + != (grub_ssize_t) kernelsyssize) + goto fail; + + grub_loader_set (grub_freedos_boot, grub_freedos_unload, 1); + return GRUB_ERR_NONE; + + fail: + + if (file) + grub_file_close (file); + + grub_freedos_unload (); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(freedos) +{ + cmd = grub_register_command ("freedos", grub_cmd_freedos, + 0, N_("Load FreeDOS kernel.sys.")); + my_mod = mod; +} + +GRUB_MOD_FINI(freedos) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 90de70f66..7c4a4beb6 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -34,9 +33,11 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_LINUX_CL_OFFSET 0x9000 -#define GRUB_LINUX_CL_END_OFFSET 0x90FF static grub_dl_t my_mod; @@ -46,6 +47,7 @@ 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_size_t maximal_cmdline_size; static grub_err_t grub_linux16_boot (void) @@ -58,6 +60,7 @@ grub_linux16_boot (void) state.sp = GRUB_LINUX_SETUP_STACK; state.cs = segment + 0x20; state.ip = 0; + state.a20 = 1; grub_video_set_mode ("text", 0, 0); @@ -86,7 +89,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), 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; @@ -106,7 +108,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"), + argv[0]); goto fail; } @@ -126,15 +130,20 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), setup_sects = lh.setup_sects; linux_mem_size = 0; + maximal_cmdline_size = 256; + if (lh.header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) && grub_le_to_cpu16 (lh.version) >= 0x0200) { grub_linux_is_bzimage = (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL); lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; + if (grub_le_to_cpu16 (lh.version) >= 0x0206) + maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1; + /* Put the real mode part at as a high location as possible. */ grub_linux_real_target = grub_mmap_get_lower () - - GRUB_LINUX_SETUP_MOVE_SIZE; + - (GRUB_LINUX_CL_OFFSET + maximal_cmdline_size); /* But it must not exceed the traditional area. */ if (grub_linux_real_target > GRUB_LINUX_OLD_REAL_MODE_ADDR) grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR; @@ -151,7 +160,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), { lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC); lh.cl_offset = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET); - lh.setup_move_size = grub_cpu_to_le16 (GRUB_LINUX_SETUP_MOVE_SIZE); + lh.setup_move_size = grub_cpu_to_le16 (GRUB_LINUX_CL_OFFSET + + maximal_cmdline_size); } } else @@ -183,12 +193,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto fail; } - if (grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE + if (grub_linux_real_target + GRUB_LINUX_CL_OFFSET + maximal_cmdline_size > grub_mmap_get_lower ()) { grub_error (GRUB_ERR_OUT_OF_RANGE, "too small lower memory (0x%x > 0x%x)", - grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE, + grub_linux_real_target + GRUB_LINUX_CL_OFFSET + + maximal_cmdline_size, (int) grub_mmap_get_lower ()); goto fail; } @@ -261,7 +272,8 @@ 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); + GRUB_LINUX_CL_OFFSET + + maximal_cmdline_size); if (err) return err; grub_linux_real_chunk = get_virtual_current_address (ch); @@ -273,7 +285,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); goto fail; } @@ -286,21 +300,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ((GRUB_LINUX_MAX_SETUP_SECTS - setup_sects - 1) << GRUB_DISK_SECTOR_BITS)); - /* Specify the boot file. */ - 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_real_chunk - + GRUB_LINUX_CL_END_OFFSET); - i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } + /* Create kernel command line. */ + grub_memcpy ((char *)grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET, + LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, + (char *)grub_linux_real_chunk + + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1, + maximal_cmdline_size + - (sizeof (LINUX_IMAGE) - 1)); if (grub_linux_is_bzimage) grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR; @@ -318,8 +325,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), 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"); + != (grub_ssize_t) grub_linux16_prot_size && !grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); if (grub_errno == GRUB_ERR_NONE) { @@ -346,13 +354,15 @@ 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_file_t *files = 0; + grub_size_t size = 0; 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; + int i, nfiles = 0; + grub_uint8_t *ptr; if (argc == 0) { @@ -400,12 +410,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size; - grub_file_filter_disable_compression (); - file = grub_file_open (argv[0]); - if (!file) + files = grub_zalloc (argc * sizeof (files[0])); + if (!files) goto fail; - size = grub_file_size (file); + for (i = 0; i < argc; i++) + { + grub_file_filter_disable_compression (); + files[i] = grub_file_open (argv[i]); + if (! files[i]) + goto fail; + nfiles++; + size += grub_file_size (files[i]); + } { grub_relocator_chunk_t ch; @@ -419,18 +436,28 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), initrd_addr = get_physical_target_address (ch); } - if (grub_file_read (file, initrd_chunk, size) != size) + ptr = initrd_chunk; + + for (i = 0; i < nfiles; i++) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; + grub_ssize_t cursize = grub_file_size (files[i]); + if (grub_file_read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + goto fail; + } + ptr += cursize; } lh->ramdisk_image = initrd_addr; lh->ramdisk_size = size; fail: - if (file) - grub_file_close (file); + for (i = 0; i < nfiles; i++) + grub_file_close (files[i]); + grub_free (files); return grub_errno; } diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c index 0c33a0680..153b605ed 100644 --- a/grub-core/loader/i386/pc/ntldr.c +++ b/grub-core/loader/i386/pc/ntldr.c @@ -32,6 +32,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_dl_t my_mod; static struct grub_relocator *rel; @@ -51,7 +54,8 @@ grub_ntldr_boot (void) .gs = 0, .ss = 0, .sp = 0x7c00, - .edx = edx + .edx = edx, + .a20 = 1 }; grub_video_set_mode ("text", 0, 0); @@ -110,6 +114,7 @@ grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), grub_device_close (dev); goto fail; } + grub_chainloader_patch_bpb (bs, dev, edx); } if (dev) diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c new file mode 100644 index 000000000..169f83a43 --- /dev/null +++ b/grub-core/loader/i386/pc/plan9.c @@ -0,0 +1,514 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_dl_t my_mod; +static struct grub_relocator *rel; +static grub_uint32_t eip = 0xffffffff; + +#define GRUB_PLAN9_TARGET 0x100000 +#define GRUB_PLAN9_ALIGN 4096 +#define GRUB_PLAN9_CONFIG_ADDR 0x001200 +#define GRUB_PLAN9_CONFIG_PATH_SIZE 0x000040 +#define GRUB_PLAN9_CONFIG_MAGIC "ZORT 0\r\n" + +static const struct grub_arg_option options[] = + { + {"map", 'm', GRUB_ARG_OPTION_REPEATABLE, + N_("Override guessed mapping of Plan9 devices."), + N_("GRUBDEVICE=PLAN9DEVICE"), + ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +struct grub_plan9_header +{ + grub_uint32_t magic; +#define GRUB_PLAN9_MAGIC 0x1eb + grub_uint32_t text_size; + grub_uint32_t data_size; + grub_uint32_t bss_size; + grub_uint32_t sectiona; + grub_uint32_t entry_addr; + grub_uint32_t zero; + grub_uint32_t sectionb; +}; + +static grub_err_t +grub_plan9_boot (void) +{ + struct grub_relocator32_state state = { + .eax = 0, + .eip = eip, + .ebx = 0, + .ecx = 0, + .edx = 0, + .edi = 0, + .esp = 0, + .ebp = 0, + .esi = 0 + }; + grub_video_set_mode ("text", 0, 0); + + return grub_relocator32_boot (rel, state); +} + +static grub_err_t +grub_plan9_unload (void) +{ + grub_relocator_unload (rel); + rel = NULL; + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[]) +{ + grub_file_t file = 0; + void *mem; + grub_size_t memsize, padsize; + struct grub_plan9_header hdr; + char *config, *configptr; + grub_size_t configsize; + char *pmap = NULL; + grub_size_t pmapalloc = 256; + grub_size_t pmapptr = 0; + int noslash = 1; + char prefixes[5][10] = {"dos", "plan9", "ntfs", "linux", "linuxswap"}; + int prefixescnt[5]; + char *bootdisk = NULL, *bootpart = NULL, *bootpath = NULL; + + auto int fill_partition (grub_disk_t disk, + const grub_partition_t partition); + int fill_partition (grub_disk_t disk, + const grub_partition_t partition) + { + int file_disk = 0; + int pstart, pend; + if (!noslash) + { + if (grub_extend_alloc (pmapptr + 1, &pmapalloc, (void **) &pmap)) + return 1; + pmap[pmapptr++] = '/'; + } + noslash = 0; + + file_disk = file->device->disk && disk->id == file->device->disk->id + && disk->dev->id == file->device->disk->dev->id; + + pstart = pmapptr; + if (grub_strcmp (partition->partmap->name, "plan") == 0) + { + unsigned ptr = partition->index + sizeof ("part ") - 1; + grub_err_t err; + disk->partition = partition->parent; + do + { + if (grub_extend_alloc (pmapptr + 1, &pmapalloc, (void **) &pmap)) + return 1; + err = grub_disk_read (disk, 1, ptr, 1, pmap + pmapptr); + if (err) + { + disk->partition = 0; + return err; + } + ptr++; + pmapptr++; + } + while (grub_isalpha (pmap[pmapptr - 1]) + || grub_isdigit (pmap[pmapptr - 1])); + pmapptr--; + } + else + { + char name[50]; + int c = 0; + if (grub_strcmp (partition->partmap->name, "msdos") == 0) + { + switch (partition->msdostype) + { + case GRUB_PC_PARTITION_TYPE_PLAN9: + c = 1; + break; + case GRUB_PC_PARTITION_TYPE_NTFS: + c = 2; + break; + case GRUB_PC_PARTITION_TYPE_MINIX: + case GRUB_PC_PARTITION_TYPE_LINUX_MINIX: + case GRUB_PC_PARTITION_TYPE_EXT2FS: + c = 3; + break; + case GRUB_PC_PARTITION_TYPE_LINUX_SWAP: + c = 4; + break; + } + } + + if (prefixescnt[c] == 0) + grub_strcpy (name, prefixes[c]); + else + grub_snprintf (name, sizeof (name), "%s.%d", prefixes[c], + prefixescnt[c]); + prefixescnt[c]++; + if (grub_extend_alloc (pmapptr + grub_strlen (name) + 1, + &pmapalloc, (void **) &pmap)) + return 1; + grub_strcpy (pmap + pmapptr, name); + pmapptr += grub_strlen (name); + } + pend = pmapptr; + if (grub_extend_alloc (pmapptr + 2 + 25 + 5 + 25, &pmapalloc, + (void **) &pmap)) + return 1; + pmap[pmapptr++] = ' '; + grub_snprintf (pmap + pmapptr, 25 + 5 + 25, + "%" PRIuGRUB_UINT64_T " %" PRIuGRUB_UINT64_T, + grub_partition_get_start (partition), + grub_partition_get_start (partition) + + grub_partition_get_len (partition)); + if (file_disk && grub_partition_get_start (partition) + == grub_partition_get_start (file->device->disk->partition) + && grub_partition_get_len (partition) + == grub_partition_get_len (file->device->disk->partition)) + { + grub_free (bootpart); + bootpart = grub_strndup (pmap + pstart, pend - pstart); + } + + pmapptr += grub_strlen (pmap + pmapptr); + return 0; + } + + auto int fill_disk (const char *name); + int fill_disk (const char *name) + { + grub_device_t dev; + char *plan9name = NULL; + unsigned i; + int file_disk = 0; + + dev = grub_device_open (name); + if (!dev) + { + grub_print_error (); + return 0; + } + if (!dev->disk) + { + grub_device_close (dev); + return 0; + } + file_disk = file->device->disk && dev->disk->id == file->device->disk->id + && dev->disk->dev->id == file->device->disk->dev->id; + for (i = 0; ctxt->state[0].args && ctxt->state[0].args[i]; i++) + if (grub_strncmp (name, ctxt->state[0].args[i], grub_strlen (name)) == 0 + && ctxt->state[0].args[i][grub_strlen (name)] == '=') + break; + if (ctxt->state[0].args && ctxt->state[0].args[i]) + plan9name = grub_strdup (ctxt->state[0].args[i] + grub_strlen (name) + 1); + else + switch (dev->disk->dev->id) + { + case GRUB_DISK_DEVICE_BIOSDISK_ID: + if (dev->disk->id & 0x80) + plan9name = grub_xasprintf ("sdB%u", + (unsigned) (dev->disk->id & 0x7f)); + else + plan9name = grub_xasprintf ("fd%u", + (unsigned) (dev->disk->id & 0x7f)); + break; + /* Shouldn't happen as Plan9 doesn't work on these platforms. */ + case GRUB_DISK_DEVICE_OFDISK_ID: + case GRUB_DISK_DEVICE_EFIDISK_ID: + + /* Plan9 doesn't see those. */ + default: + + /* Not sure how to handle those. */ + case GRUB_DISK_DEVICE_NAND_ID: + if (!file_disk) + { + grub_device_close (dev); + return 0; + } + + /* if it's the disk the kernel is loaded from we need to name + it nevertheless. */ + plan9name = grub_strdup ("sdZ0"); + break; + + case GRUB_DISK_DEVICE_ATA_ID: + { + int unit; + if (grub_strlen (dev->disk->name) < sizeof ("ata0") - 1) + unit = 0; + else + unit = grub_strtoul (dev->disk->name + sizeof ("ata0") - 1, 0, 0); + plan9name = grub_xasprintf ("sd%c%d", 'C' + unit / 2, unit % 2); + } + break; + case GRUB_DISK_DEVICE_SCSI_ID: + if (((dev->disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xff) + == GRUB_SCSI_SUBSYSTEM_PATA) + { + int unit; + if (grub_strlen (dev->disk->name) < sizeof ("ata0") - 1) + unit = 0; + else + unit = grub_strtoul (dev->disk->name + sizeof ("ata0") - 1, + 0, 0); + plan9name = grub_xasprintf ("sd%c%d", 'C' + unit / 2, unit % 2); + break; + } + + /* FIXME: how does Plan9 number controllers? + We probably need save the SCSI devices and sort them */ + plan9name + = grub_xasprintf ("sd0%u", (unsigned) + ((dev->disk->id >> GRUB_SCSI_ID_BUS_SHIFT) + & 0xf)); + break; + } + if (!plan9name) + { + grub_print_error (); + return 0; + } + if (grub_extend_alloc (pmapptr + grub_strlen (plan9name) + + sizeof ("part="), &pmapalloc, + (void **) &pmap)) + { + grub_free (plan9name); + return 1; + } + grub_strcpy (pmap + pmapptr, plan9name); + pmapptr += grub_strlen (plan9name); + if (!file_disk) + grub_free (plan9name); + else + { + grub_free (bootdisk); + bootdisk = plan9name; + } + grub_strcpy (pmap + pmapptr, "part="); + pmapptr += sizeof ("part=") - 1; + + noslash = 1; + grub_memset (prefixescnt, 0, sizeof (prefixescnt)); + if (grub_partition_iterate (dev->disk, fill_partition)) + return 1; + if (grub_extend_alloc (pmapptr + 1, &pmapalloc, (void **) &pmap)) + return 1; + pmap[pmapptr++] = '\n'; + + return 0; + } + + 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; + + pmap = grub_malloc (pmapalloc); + if (!pmap) + goto fail; + + if (grub_disk_dev_iterate (fill_disk)) + goto fail; + + if (grub_extend_alloc (pmapptr + 1, &pmapalloc, + (void **) &pmap)) + goto fail; + pmap[pmapptr] = 0; + + { + char *file_name = grub_strchr (argv[0], ')'); + if (file_name) + file_name++; + else + file_name = argv[0]; + if (*file_name) + file_name++; + + if (bootpart) + bootpath = grub_xasprintf ("%s!%s!%s", bootdisk, bootpart, file_name); + else + bootpath = grub_xasprintf ("%s!%s", bootdisk, file_name); + grub_free (bootdisk); + grub_free (bootpart); + } + if (!bootpath) + goto fail; + + if (grub_file_read (file, &hdr, sizeof (hdr)) != (grub_ssize_t) sizeof (hdr)) + goto fail; + + if (grub_be_to_cpu32 (hdr.magic) != GRUB_PLAN9_MAGIC + || hdr.zero) + { + grub_error (GRUB_ERR_BAD_OS, "unsupported Plan9"); + goto fail; + } + + memsize = ALIGN_UP (grub_be_to_cpu32 (hdr.text_size) + sizeof (hdr), + GRUB_PLAN9_ALIGN); + memsize += ALIGN_UP (grub_be_to_cpu32 (hdr.data_size), GRUB_PLAN9_ALIGN); + memsize += ALIGN_UP(grub_be_to_cpu32 (hdr.bss_size), GRUB_PLAN9_ALIGN); + eip = grub_be_to_cpu32 (hdr.entry_addr) & 0xfffffff; + + /* path */ + configsize = GRUB_PLAN9_CONFIG_PATH_SIZE; + /* magic */ + configsize += sizeof (GRUB_PLAN9_CONFIG_MAGIC) - 1; + { + int i; + for (i = 1; i < argc; i++) + configsize += grub_strlen (argv[i]) + 1; + } + configsize += (sizeof ("bootfile=") - 1) + grub_strlen (bootpath) + 1; + configsize += pmapptr; + /* Terminating \0. */ + configsize++; + + { + grub_relocator_chunk_t ch; + grub_err_t err; + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_PLAN9_CONFIG_ADDR, + configsize); + if (err) + goto fail; + config = get_virtual_current_address (ch); + } + + grub_memset (config, 0, GRUB_PLAN9_CONFIG_PATH_SIZE); + grub_strncpy (config, bootpath, GRUB_PLAN9_CONFIG_PATH_SIZE - 1); + + configptr = config + GRUB_PLAN9_CONFIG_PATH_SIZE; + grub_memcpy (configptr, GRUB_PLAN9_CONFIG_MAGIC, + sizeof (GRUB_PLAN9_CONFIG_MAGIC) - 1); + configptr += sizeof (GRUB_PLAN9_CONFIG_MAGIC) - 1; + configptr = grub_stpcpy (configptr, "bootfile="); + configptr = grub_stpcpy (configptr, bootpath); + *configptr++ = '\n'; + { + int i; + for (i = 1; i < argc; i++) + { + configptr = grub_stpcpy (configptr, argv[i]); + *configptr++ = '\n'; + } + } + configptr = grub_stpcpy (configptr, pmap); + + { + grub_relocator_chunk_t ch; + grub_err_t err; + + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_PLAN9_TARGET, + memsize); + if (err) + goto fail; + mem = get_virtual_current_address (ch); + } + + { + grub_uint8_t *ptr; + ptr = mem; + grub_memcpy (ptr, &hdr, sizeof (hdr)); + ptr += sizeof (hdr); + + if (grub_file_read (file, ptr, grub_be_to_cpu32 (hdr.text_size)) + != (grub_ssize_t) grub_be_to_cpu32 (hdr.text_size)) + goto fail; + ptr += grub_be_to_cpu32 (hdr.text_size); + padsize = ALIGN_UP (grub_be_to_cpu32 (hdr.text_size) + sizeof (hdr), + GRUB_PLAN9_ALIGN) - grub_be_to_cpu32 (hdr.text_size) + - sizeof (hdr); + + grub_memset (ptr, 0, padsize); + ptr += padsize; + + if (grub_file_read (file, ptr, grub_be_to_cpu32 (hdr.data_size)) + != (grub_ssize_t) grub_be_to_cpu32 (hdr.data_size)) + goto fail; + ptr += grub_be_to_cpu32 (hdr.data_size); + padsize = ALIGN_UP (grub_be_to_cpu32 (hdr.data_size), GRUB_PLAN9_ALIGN) + - grub_be_to_cpu32 (hdr.data_size); + + grub_memset (ptr, 0, padsize); + ptr += padsize; + grub_memset (ptr, 0, ALIGN_UP(grub_be_to_cpu32 (hdr.bss_size), + GRUB_PLAN9_ALIGN)); + } + grub_loader_set (grub_plan9_boot, grub_plan9_unload, 1); + return GRUB_ERR_NONE; + + fail: + grub_free (pmap); + + if (file) + grub_file_close (file); + + grub_plan9_unload (); + + return grub_errno; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(plan9) +{ + cmd = grub_register_extcmd ("plan9", grub_cmd_plan9, + GRUB_COMMAND_OPTIONS_AT_START, + N_("KERNEL ARGS"), N_("Load Plan9 kernel."), + options); + my_mod = mod; +} + +GRUB_MOD_FINI(plan9) +{ + grub_unregister_extcmd (cmd); +} diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index a9435eff3..ac562a20d 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -46,10 +46,10 @@ grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack; struct tbl_alias { grub_efi_guid_t guid; - char *name; + const char *name; }; -struct tbl_alias table_aliases[] = +static struct tbl_alias table_aliases[] = { {GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI_20"}, {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"}, @@ -58,6 +58,7 @@ struct tbl_alias table_aliases[] = struct grub_xnu_devprop_device_descriptor { struct grub_xnu_devprop_device_descriptor *next; + struct grub_xnu_devprop_device_descriptor **prev; struct property_descriptor *properties; struct grub_efi_device_path *path; int pathlen; @@ -212,6 +213,7 @@ guessfsb (void) struct property_descriptor { struct property_descriptor *next; + struct property_descriptor **prev; grub_uint8_t *name; grub_uint16_t *name16; int name16len; @@ -219,14 +221,14 @@ struct property_descriptor void *data; }; -struct grub_xnu_devprop_device_descriptor *devices = 0; +static struct grub_xnu_devprop_device_descriptor *devices = 0; grub_err_t grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev, char *name) { struct property_descriptor *prop; - prop = grub_named_list_find (GRUB_AS_NAMED_LIST_P (&dev->properties), name); + prop = grub_named_list_find (GRUB_AS_NAMED_LIST (dev->properties), name); if (!prop) return GRUB_ERR_NONE; @@ -234,7 +236,7 @@ grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev grub_free (prop->name16); grub_free (prop->data); - grub_list_remove (GRUB_AS_LIST_P (&dev->properties), GRUB_AS_LIST (prop)); + grub_list_remove (GRUB_AS_LIST (prop)); return GRUB_ERR_NONE; } @@ -245,7 +247,7 @@ grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev) void *t; struct property_descriptor *prop; - grub_list_remove (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (dev)); + grub_list_remove (GRUB_AS_LIST (dev)); for (prop = dev->properties; prop; ) { @@ -452,11 +454,11 @@ grub_cpu_xnu_fill_devprop (void) } devprop = grub_xnu_create_value (&(efikey->first_child), "device-properties"); - if (devprop) - { - devprop->data = grub_malloc (total_length); - devprop->datasize = total_length; - } + if (!devprop) + return grub_errno; + + devprop->data = grub_malloc (total_length); + devprop->datasize = total_length; ptr = devprop->data; head = ptr; @@ -700,7 +702,7 @@ grub_cpu_xnu_fill_devicetree (void) return grub_errno; /* First see if user supplies the value. */ - char *fsbvar = grub_env_get ("fsb"); + const char *fsbvar = grub_env_get ("fsb"); if (! fsbvar) *((grub_uint64_t *) curval->data) = 0; else @@ -734,18 +736,18 @@ grub_cpu_xnu_fill_devicetree (void) #else if (SIZEOF_OF_UINTN == 4) { - ptr = UINT_TO_PTR (((grub_efiemu_configuration_table32_t *) - SYSTEM_TABLE_PTR (configuration_table))[i] - .vendor_table); + ptr = (void *) (grub_addr_t) ((grub_efiemu_configuration_table32_t *) + SYSTEM_TABLE_PTR (configuration_table))[i] + .vendor_table; guid = ((grub_efiemu_configuration_table32_t *) SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid; } else { - ptr = UINT_TO_PTR (((grub_efiemu_configuration_table64_t *) - SYSTEM_TABLE_PTR (configuration_table))[i] - .vendor_table); + ptr = (void *) (grub_addr_t) ((grub_efiemu_configuration_table64_t *) + SYSTEM_TABLE_PTR (configuration_table))[i] + .vendor_table; guid = ((grub_efiemu_configuration_table64_t *) SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid; @@ -786,9 +788,9 @@ grub_cpu_xnu_fill_devicetree (void) if (! curval->data) return grub_errno; if (SIZEOF_OF_UINTN == 4) - *((grub_uint32_t *)curval->data) = PTR_TO_UINT32 (ptr); + *((grub_uint32_t *) curval->data) = (grub_addr_t) ptr; else - *((grub_uint64_t *)curval->data) = PTR_TO_UINT64 (ptr); + *((grub_uint64_t *) curval->data) = (grub_addr_t) ptr; /* Create alias. */ for (j = 0; j < sizeof (table_aliases) / sizeof (table_aliases[0]); j++) @@ -821,10 +823,10 @@ grub_cpu_xnu_fill_devicetree (void) return grub_errno; if (SIZEOF_OF_UINTN == 4) *((grub_uint32_t *) curval->data) - = PTR_TO_UINT32 (SYSTEM_TABLE_PTR (runtime_services)); + = (grub_addr_t) SYSTEM_TABLE_PTR (runtime_services); else *((grub_uint64_t *) curval->data) - = PTR_TO_UINT64 (SYSTEM_TABLE_PTR (runtime_services)); + = (grub_addr_t) SYSTEM_TABLE_PTR (runtime_services); return GRUB_ERR_NONE; } @@ -939,7 +941,7 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) params->lfb_depth = mode_info.bpp; params->lfb_line_len = mode_info.pitch; - params->lfb_base = PTR_TO_UINT32 (framebuffer); + params->lfb_base = (grub_addr_t) framebuffer; params->lfb_mode = bitmap ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; @@ -951,10 +953,11 @@ grub_err_t grub_xnu_boot (void) { struct grub_xnu_boot_params *bootparams; + void *bp_in; grub_addr_t bootparams_target; grub_err_t err; grub_efi_uintn_t memory_map_size = 0; - grub_efi_memory_descriptor_t *memory_map; + void *memory_map; grub_addr_t memory_map_target; grub_efi_uintn_t map_key = 0; grub_efi_uintn_t descriptor_size = 0; @@ -1006,9 +1009,10 @@ grub_xnu_boot (void) /* Relocate the boot parameters to heap. */ err = grub_xnu_heap_malloc (sizeof (*bootparams), - (void **) &bootparams, &bootparams_target); + &bp_in, &bootparams_target); if (err) return err; + bootparams = bp_in; /* Set video. */ err = grub_xnu_set_video (bootparams); @@ -1016,7 +1020,7 @@ grub_xnu_boot (void) { grub_print_error (); grub_errno = GRUB_ERR_NONE; - grub_printf ("Booting in blind mode\n"); + grub_puts_ (N_("Booting in blind mode")); bootparams->lfb_mode = 0; bootparams->lfb_width = 0; @@ -1035,7 +1039,7 @@ grub_xnu_boot (void) memory map growth. */ memory_map_size += 20 * descriptor_size; err = grub_xnu_heap_malloc (memory_map_size, - (void **) &memory_map, &memory_map_target); + &memory_map, &memory_map_target); if (err) return err; @@ -1055,7 +1059,7 @@ grub_xnu_boot (void) if (err) return err; - bootparams->efi_system_table = PTR_TO_UINT32 (grub_autoefi_system_table); + bootparams->efi_system_table = (grub_addr_t) grub_autoefi_system_table; firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1) @@ -1075,11 +1079,11 @@ grub_xnu_boot (void) curdesc->virtual_start = curruntimepage << 12; curruntimepage += curdesc->num_pages; if (curdesc->physical_start - <= PTR_TO_UINT64 (grub_autoefi_system_table) + <= (grub_addr_t) grub_autoefi_system_table && curdesc->physical_start + (curdesc->num_pages << 12) - > PTR_TO_UINT64 (grub_autoefi_system_table)) + > (grub_addr_t) grub_autoefi_system_table) bootparams->efi_system_table - = PTR_TO_UINT64 (grub_autoefi_system_table) + = (grub_addr_t) grub_autoefi_system_table - curdesc->physical_start + curdesc->virtual_start; if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit) curdesc->virtual_start |= 0xffffff8000000000ULL; @@ -1109,7 +1113,7 @@ grub_xnu_boot (void) grub_xnu_arg1 = bootparams_target; grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, - descriptor_version,memory_map); + descriptor_version, memory_map); state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c new file mode 100644 index 000000000..27dadc696 --- /dev/null +++ b/grub-core/loader/ia64/efi/linux.c @@ -0,0 +1,823 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define ALIGN_MIN (256*1024*1024) + +#define GRUB_ELF_SEARCH 1024 + +#define BOOT_PARAM_SIZE 16384 + +struct ia64_boot_param +{ + grub_uint64_t command_line; /* physical address of command line. */ + grub_uint64_t efi_systab; /* physical address of EFI system table */ + grub_uint64_t efi_memmap; /* physical address of EFI memory map */ + grub_uint64_t efi_memmap_size; /* size of EFI memory map */ + grub_uint64_t efi_memdesc_size; /* size of an EFI memory map descriptor */ + grub_uint32_t efi_memdesc_version; /* memory descriptor version */ + struct + { + grub_uint16_t num_cols; /* number of columns on console output dev */ + grub_uint16_t num_rows; /* number of rows on console output device */ + grub_uint16_t orig_x; /* cursor's x position */ + grub_uint16_t orig_y; /* cursor's y position */ + } console_info; + grub_uint64_t fpswa; /* physical address of the fpswa interface */ + grub_uint64_t initrd_start; + grub_uint64_t initrd_size; + grub_uint64_t domain_start; /* boot domain address. */ + grub_uint64_t domain_size; /* how big is the boot domain */ + grub_uint64_t payloads_chain; + grub_uint64_t payloads_nbr; +}; + +struct ia64_boot_payload +{ + grub_uint64_t start; + grub_uint64_t length; + + /* Payload command line */ + grub_uint64_t cmdline; + + grub_uint64_t next; +}; + +typedef struct +{ + grub_uint32_t revision; + grub_uint32_t reserved; + void *fpswa; +} fpswa_interface_t; +static fpswa_interface_t *fpswa; + +#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +static grub_dl_t my_mod; + +static int loaded; + +/* Kernel base and size. */ +static void *kernel_mem; +static grub_efi_uintn_t kernel_pages; +static grub_uint64_t entry; + +/* Initrd base and size. */ +static void *initrd_mem; +static grub_efi_uintn_t initrd_pages; +static grub_efi_uintn_t initrd_size; + +static struct ia64_boot_param *boot_param; +static grub_efi_uintn_t boot_param_pages; +static struct ia64_boot_payload *last_payload = NULL; + +/* Can linux kernel be relocated ? */ +#define RELOCATE_OFF 0 /* No. */ +#define RELOCATE_ON 1 /* Yes. */ +#define RELOCATE_FORCE 2 /* Always - used to debug. */ +static int relocate = RELOCATE_OFF; + +static inline grub_size_t +page_align (grub_size_t size) +{ + return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); +} + +static void +query_fpswa (void) +{ + grub_efi_handle_t fpswa_image; + grub_efi_boot_services_t *bs; + grub_efi_status_t status; + grub_efi_uintn_t size; + static const grub_efi_guid_t fpswa_protocol = + { 0xc41b6531, 0x97b9, 0x11d3, + {0x9a, 0x29, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }; + + if (fpswa != NULL) + return; + + size = sizeof(grub_efi_handle_t); + + bs = grub_efi_system_table->boot_services; + status = bs->locate_handle (GRUB_EFI_BY_PROTOCOL, + (void *)&fpswa_protocol, + NULL, &size, &fpswa_image); + if (status != GRUB_EFI_SUCCESS) + { + grub_printf("Could not locate FPSWA driver\n"); + return; + } + status = bs->handle_protocol (fpswa_image, + (void *)&fpswa_protocol, (void *)&fpswa); + if (status != GRUB_EFI_SUCCESS) + { + grub_printf ("Fpswa protocol not able find the interface\n"); + return; + } +} + +/* 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 (kernel_mem) + { + grub_efi_free_pages ((grub_addr_t) kernel_mem, kernel_pages); + kernel_mem = 0; + } + + if (initrd_mem) + { + grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); + initrd_mem = 0; + } + + if (boot_param) + { + struct ia64_boot_payload *payload; + struct ia64_boot_payload *next_payload; + + /* Free payloads. */ + payload = (struct ia64_boot_payload *)boot_param->payloads_chain; + while (payload != 0) + { + next_payload = (struct ia64_boot_payload *)payload->next; + + grub_efi_free_pages + (payload->start, page_align (payload->length) >> 12); + grub_efi_free_pages ((grub_efi_physical_address_t)payload, 1); + + payload = next_payload; + } + + /* Free bootparam. */ + grub_efi_free_pages ((grub_efi_physical_address_t)boot_param, + boot_param_pages); + boot_param = 0; + } +} + +static void * +allocate_pages (grub_uint64_t align, grub_uint64_t size_pages, + grub_uint64_t nobase) +{ + grub_uint64_t 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; + void *mem = NULL; + + size = size_pages << 12; + + mmap_size = find_mmap_size (); + + /* 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)) + { + grub_uint64_t start, end; + grub_uint64_t aligned_start; + + if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + + start = desc->physical_start; + end = start + (desc->num_pages << 12); + /* Align is a power of 2. */ + aligned_start = (start + align - 1) & ~(align - 1); + if (aligned_start + size > end) + continue; + if (aligned_start == nobase) + aligned_start += align; + if (aligned_start + size > end) + continue; + mem = grub_efi_allocate_pages (aligned_start, size_pages); + if (! mem) + grub_fatal ("cannot allocate pages"); + break; + } + + if (! mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory"); + goto fail; + } + + grub_free (mmap); + return mem; + + fail: + grub_free (mmap); + free_pages (); + return 0; +} + +static void +set_boot_param_console (void) +{ + grub_efi_simple_text_output_interface_t *conout; + grub_efi_uintn_t cols, rows; + + conout = grub_efi_system_table->con_out; + if (conout->query_mode (conout, conout->mode->mode, &cols, &rows) + != GRUB_EFI_SUCCESS) + return; + + grub_dprintf("linux", + "Console info: cols=%lu rows=%lu x=%u y=%u\n", + cols, rows, + conout->mode->cursor_column, conout->mode->cursor_row); + + boot_param->console_info.num_cols = cols; + boot_param->console_info.num_rows = rows; + boot_param->console_info.orig_x = conout->mode->cursor_column; + boot_param->console_info.orig_y = conout->mode->cursor_row; +} + +static grub_err_t +grub_linux_boot (void) +{ + grub_efi_uintn_t mmap_size; + grub_efi_uintn_t map_key; + grub_efi_uintn_t desc_size; + grub_efi_uint32_t desc_version; + grub_efi_memory_descriptor_t *mmap_buf; + grub_err_t err; + + /* FPSWA. */ + query_fpswa (); + boot_param->fpswa = (grub_uint64_t)fpswa; + + /* Initrd. */ + boot_param->initrd_start = (grub_uint64_t)initrd_mem; + boot_param->initrd_size = (grub_uint64_t)initrd_size; + + set_boot_param_console (); + + grub_printf ("Jump to %016lx\n", entry); + + grub_machine_fini (); + + /* MDT. + Must be done after grub_machine_fini because map_key is used by + exit_boot_services. */ + mmap_size = find_mmap_size (); + mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12); + if (! mmap_buf) + grub_fatal ("cannot allocate memory map"); + err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, &map_key, + &desc_size, &desc_version); + if (err) + return err; + + boot_param->efi_memmap = (grub_uint64_t)mmap_buf; + boot_param->efi_memmap_size = mmap_size; + boot_param->efi_memdesc_size = desc_size; + boot_param->efi_memdesc_version = desc_version; + + /* See you next boot. */ + asm volatile ("mov r28=%1; br.sptk.few %0" :: "b"(entry),"r"(boot_param)); + + /* 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_load_elf64 (grub_file_t file, void *buffer, const char *filename) +{ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer; + Elf64_Phdr *phdr; + int i; + grub_uint64_t low_addr; + grub_uint64_t high_addr; + grub_uint64_t align; + grub_uint64_t reloc_offset; + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) + return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); + + if (ehdr->e_ident[EI_MAG0] != ELFMAG0 + || ehdr->e_ident[EI_MAG1] != ELFMAG1 + || ehdr->e_ident[EI_MAG2] != ELFMAG2 + || ehdr->e_ident[EI_MAG3] != ELFMAG3 + || ehdr->e_version != EV_CURRENT + || ehdr->e_ident[EI_DATA] != ELFDATA2LSB + || ehdr->e_machine != EM_IA_64) + return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found"); + + if (ehdr->e_type != ET_EXEC) + return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type"); + + /* FIXME: Should we support program headers at strange locations? */ + if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_ELF_SEARCH) + return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); + + entry = ehdr->e_entry; + + /* Compute low, high and align addresses. */ + low_addr = ~0UL; + high_addr = 0; + align = 0; + for (i = 0; i < ehdr->e_phnum; i++) + { + phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff + + i * ehdr->e_phentsize); + if (phdr->p_type == PT_LOAD) + { + if (phdr->p_paddr < low_addr) + low_addr = phdr->p_paddr; + if (phdr->p_paddr + phdr->p_memsz > high_addr) + high_addr = phdr->p_paddr + phdr->p_memsz; + if (phdr->p_align > align) + align = phdr->p_align; + } + } + + if (align < ALIGN_MIN) + align = ALIGN_MIN; + + if (high_addr == 0) + return grub_error (GRUB_ERR_BAD_OS, "no program entries"); + + kernel_pages = page_align (high_addr - low_addr) >> 12; + + if (relocate != RELOCATE_FORCE) + { + kernel_mem = grub_efi_allocate_pages (low_addr, kernel_pages); + reloc_offset = 0; + } + /* Try to relocate. */ + if (! kernel_mem && relocate != RELOCATE_OFF) + { + kernel_mem = allocate_pages (align, kernel_pages, low_addr); + if (kernel_mem) + { + reloc_offset = (grub_uint64_t)kernel_mem - low_addr; + grub_printf (" Relocated at %p (offset=%016lx)\n", + kernel_mem, reloc_offset); + entry += reloc_offset; + } + } + if (! kernel_mem) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "cannot allocate memory for OS"); + + /* Load every loadable segment in memory. */ + for (i = 0; i < ehdr->e_phnum; i++) + { + phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff + + i * ehdr->e_phentsize); + if (phdr->p_type == PT_LOAD) + { + grub_printf (" [paddr=%lx load=%lx memsz=%08lx " + "off=%lx flags=%x]\n", + phdr->p_paddr, phdr->p_paddr + reloc_offset, + phdr->p_memsz, phdr->p_offset, phdr->p_flags); + + if (grub_file_seek (file, phdr->p_offset) == (grub_off_t)-1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + + if (grub_file_read (file, (void *) (phdr->p_paddr + reloc_offset), + phdr->p_filesz) + != (grub_ssize_t) phdr->p_filesz) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + return grub_errno; + } + + if (phdr->p_filesz < phdr->p_memsz) + grub_memset + ((char *)(phdr->p_paddr + reloc_offset + phdr->p_filesz), + 0, phdr->p_memsz - phdr->p_filesz); + + /* Sync caches if necessary. */ + if (phdr->p_flags & PF_X) + grub_arch_sync_caches + ((void *)(phdr->p_paddr + reloc_offset), phdr->p_memsz); + } + } + loaded = 1; + return 0; +} + +static grub_err_t +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + char buffer[GRUB_ELF_SEARCH]; + char *cmdline, *p; + grub_ssize_t len; + int i; + + grub_dl_ref (my_mod); + + grub_loader_unset (); + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); + goto fail; + } + + file = grub_file_open (argv[0]); + if (! file) + goto fail; + + len = grub_file_read (file, buffer, sizeof (buffer)); + if (len < (grub_ssize_t) sizeof (Elf64_Ehdr)) + { + grub_error (GRUB_ERR_BAD_OS, "File too small"); + goto fail; + } + + grub_printf ("Loading linux: %s\n", argv[0]); + + if (grub_load_elf64 (file, buffer, argv[0])) + goto fail; + + len = sizeof("BOOT_IMAGE=") + 8; + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + len += sizeof (struct ia64_boot_param) + 256; /* Room for extensions. */ + boot_param_pages = page_align (len) >> 12; + boot_param = grub_efi_allocate_pages (0, boot_param_pages); + if (boot_param == 0) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, + "cannot allocate memory for bootparams"); + goto fail; + } + + grub_memset (boot_param, 0, len); + cmdline = ((char *)(boot_param + 1)) + 256; + + /* Build cmdline. */ + p = grub_stpcpy (cmdline, "BOOT_IMAGE"); + for (i = 0; i < argc; i++) + { + *p++ = ' '; + p = grub_stpcpy (p, argv[i]); + } + cmdline[10] = '='; + + boot_param->command_line = (grub_uint64_t) cmdline; + boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table; + + grub_errno = GRUB_ERR_NONE; + + grub_loader_set (grub_linux_boot, grub_linux_unload, 0); + + fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_efi_free_pages ((grub_efi_physical_address_t) boot_param, + boot_param_pages); + 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 *files = 0; + int i; + int nfiles = 0; + grub_uint8_t *ptr; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No filename specified"); + goto fail; + } + + if (! loaded) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first."); + goto fail; + } + + files = grub_zalloc (argc * sizeof (files[0])); + if (!files) + goto fail; + + initrd_size = 0; + grub_printf ("Loading initrd: "); + for (i = 0; i < argc; i++) + { + grub_file_filter_disable_compression (); + files[i] = grub_file_open (argv[i]); + if (! files[i]) + goto fail; + nfiles++; + initrd_size += grub_file_size (files[i]); + grub_printf ("%c%s\n", i == 0 ? ' ' : '+', argv[i]); + } + grub_printf ("\n"); + + initrd_pages = (page_align (initrd_size) >> 12); + initrd_mem = grub_efi_allocate_pages (0, initrd_pages); + if (! initrd_mem) + grub_fatal ("cannot allocate pages"); + + grub_printf (" [addr=0x%lx, size=0x%lx]\n", + (grub_uint64_t)initrd_mem, initrd_size); + + ptr = initrd_mem; + for (i = 0; i < nfiles; i++) + { + grub_ssize_t cursize = grub_file_size (files[i]); + if (grub_file_read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + goto fail; + } + ptr += cursize; + } + fail: + for (i = 0; i < nfiles; i++) + grub_file_close (files[i]); + grub_free (files); + return grub_errno; +} + +static grub_err_t +grub_cmd_payload (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_ssize_t size, len = 0; + char *base = 0, *cmdline = 0, *p; + struct ia64_boot_payload *payload = NULL; + int i; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + goto fail; + } + + if (!boot_param) + { + 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); + base = grub_efi_allocate_pages (0, page_align (size) >> 12); + if (! base) + goto fail; + + grub_printf ("Payload %s [addr=%lx + %lx]\n", + argv[0], (grub_uint64_t)base, size); + + if (grub_file_read (file, base, size) != size) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); + goto fail; + } + + len = sizeof (struct ia64_boot_payload); + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + if (len > 4096) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "payload command line too long"); + goto fail; + } + payload = grub_efi_allocate_pages (0, 1); + if (! payload) + goto fail; + + p = (char *)(payload + 1); + + payload->start = (grub_uint64_t)base; + payload->length = size; + payload->cmdline = (grub_uint64_t)p; + payload->next = 0; + + if (last_payload) + last_payload->next = (grub_uint64_t)payload; + else + { + last_payload = payload; + boot_param->payloads_chain = (grub_uint64_t)payload; + } + boot_param->payloads_nbr++; + + /* Copy command line. */ + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + *(--p) = '\0'; + + + fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_free (base); + grub_free (cmdline); + } + return grub_errno; +} + +static grub_err_t +grub_cmd_relocate (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + static const char * const vals[] = { "off", "on", "force"}; + unsigned int i; + + if (argc == 0) + { + grub_printf ("relocate is %s\n", vals[relocate]); + return GRUB_ERR_NONE; + } + else if (argc == 1) + { + if (kernel_mem != NULL) + grub_printf ("Warning: kernel already loaded!\n"); + for (i = 0; i < sizeof (vals)/sizeof(vals[0]); i++) + if (grub_strcmp (argv[0], vals[i]) == 0) + { + relocate = i; + return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown relocate value"); + } + else + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, "accept 0 or 1 argument"); + } + +} + + +static grub_err_t +grub_cmd_fpswa (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[] __attribute__((unused))) +{ + if (argc != 0) + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Arguments not expected"); + } + query_fpswa (); + if (fpswa == NULL) + grub_printf ("No FPSWA loaded\n"); + else + grub_printf ("FPSWA revision: %x\n", fpswa->revision); + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_linux, cmd_initrd, cmd_payload, cmd_relocate, cmd_fpswa; + +GRUB_MOD_INIT(linux) +{ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + "FILE [ARGS...]", "Load Linux."); + + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, + "FILE", "Load initrd."); + + cmd_payload = grub_register_command ("payload", grub_cmd_payload, + "FILE [ARGS...]", + "Load an additional file."); + + cmd_relocate = grub_register_command ("relocate", grub_cmd_relocate, + "[on|off|force]", + "Set relocate feature."); + + cmd_fpswa = grub_register_command ("fpswa", grub_cmd_fpswa, + "", "Display FPSWA version."); + + my_mod = mod; +} + +GRUB_MOD_FINI(linux) +{ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); + grub_unregister_command (cmd_payload); + grub_unregister_command (cmd_relocate); + grub_unregister_command (cmd_fpswa); +} diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 44ab64eb5..7fda817af 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -27,11 +27,25 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* For frequencies. */ -#include #include +#ifdef GRUB_MACHINE_MIPS_LOONGSON +#include +#include + +const char loongson_machtypes[][60] = + { + [GRUB_ARCH_MACHINE_YEELOONG] = "machtype=lemote-yeeloong-2f-8.9inches", + [GRUB_ARCH_MACHINE_FULOONG2F] = "machtype=lemote-fuloong-2f-box", + [GRUB_ARCH_MACHINE_FULOONG2E] = "machtype=lemote-fuloong-2e-unknown" + }; +#endif + static grub_dl_t my_mod; static int loaded; @@ -41,9 +55,16 @@ static grub_size_t linux_size; static struct grub_relocator *relocator; static grub_uint8_t *playground; static grub_addr_t target_addr, entry_addr; +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS +static char *params; +#else static int linux_argc; -static grub_off_t argv_off, envp_off; +static grub_off_t argv_off; +#ifdef GRUB_MACHINE_MIPS_LOONGSON +static grub_off_t envp_off; +#endif static grub_off_t rd_addr_arg_off, rd_size_arg_off; +#endif static int initrd_loaded = 0; static grub_err_t @@ -51,11 +72,43 @@ grub_linux_boot (void) { struct grub_relocator32_state state; + grub_memset (&state, 0, sizeof (state)); + /* Boot the kernel. */ state.gpr[1] = entry_addr; + +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + { + grub_err_t err; + grub_relocator_chunk_t ch; + grub_uint32_t *memsize; + grub_uint32_t *magic; + char *str; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + ((16 << 20) - 264), + grub_strlen (params) + 1 + 8); + if (err) + return err; + memsize = get_virtual_current_address (ch); + magic = memsize + 1; + *memsize = grub_mmap_get_lower (); + *magic = 0x12345678; + str = (char *) (magic + 1); + grub_strcpy (str, params); + } +#endif + +#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS state.gpr[4] = linux_argc; state.gpr[5] = target_addr + argv_off; +#ifdef GRUB_MACHINE_MIPS_LOONGSON state.gpr[6] = target_addr + envp_off; +#else + state.gpr[6] = 0; +#endif + state.gpr[7] = 0; +#endif state.jumpreg = 1; grub_relocator32_boot (relocator, state); @@ -68,6 +121,11 @@ grub_linux_unload (void) grub_relocator_unload (relocator); grub_dl_unref (my_mod); +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + grub_free (params); + params = 0; +#endif + loaded = 0; return GRUB_ERR_NONE; @@ -83,7 +141,7 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) /* Linux's entry point incorrectly contains a virtual address. */ entry_addr = elf->ehdr.ehdr32.e_entry; - linux_size = grub_elf32_size (elf, &base); + linux_size = grub_elf32_size (elf, &base, 0); if (linux_size == 0) return grub_errno; target_addr = base; @@ -138,7 +196,7 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) /* Linux's entry point incorrectly contains a virtual address. */ entry_addr = elf->ehdr.ehdr64.e_entry; - linux_size = grub_elf64_size (elf, &base); + linux_size = grub_elf64_size (elf, &base, 0); if (linux_size == 0) return grub_errno; target_addr = base; @@ -187,12 +245,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_elf_t elf = 0; - int i; int size; void *extra = NULL; - grub_uint32_t *linux_argv, *linux_envp; - char *linux_args, *linux_envs; +#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS + int i; + grub_uint32_t *linux_argv; + char *linux_args; +#endif grub_err_t err; +#ifdef GRUB_MACHINE_MIPS_LOONGSON + char *linux_envs; + grub_uint32_t *linux_envp; +#endif if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); @@ -212,8 +276,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_loader_unset (); loaded = 0; +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + size = 0; +#else /* For arguments. */ linux_argc = argc; +#ifdef GRUB_MACHINE_MIPS_LOONGSON + linux_argc++; +#endif /* Main arguments. */ size = (linux_argc) * sizeof (grub_uint32_t); /* Initrd address and size. */ @@ -226,7 +296,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Normal arguments. */ for (i = 1; i < argc; i++) size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); - +#ifdef GRUB_MACHINE_MIPS_LOONGSON + size += ALIGN_UP (sizeof (loongson_machtypes[0]), 4); +#endif + /* rd arguments. */ size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); @@ -238,6 +311,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + ALIGN_UP (sizeof ("highmemsize=XXXXXXXXXXXXXXXXXXXX"), 4) + ALIGN_UP (sizeof ("busclock=XXXXXXXXXX"), 4) + ALIGN_UP (sizeof ("cpuclock=XXXXXXXXXX"), 4); +#endif if (grub_elf_is_elf32 (elf)) err = grub_linux_load32 (elf, &extra, size); @@ -252,6 +326,20 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (err) return err; +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + /* Create kernel command line. */ + size = grub_loader_cmdline_size(argc, argv); + params = grub_malloc (size + sizeof (LINUX_IMAGE)); + if (! params) + { + grub_linux_unload (); + return grub_errno; + } + + grub_memcpy (params, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, params + sizeof (LINUX_IMAGE) - 1, + size); +#else linux_argv = extra; argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground; extra = linux_argv + (linux_argc + 1 + 2); @@ -263,6 +351,22 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), linux_argv++; linux_args += ALIGN_UP (sizeof ("a0"), 4); +#ifdef GRUB_MACHINE_MIPS_LOONGSON + { + unsigned mtype = grub_arch_machine; + if (mtype >= ARRAY_SIZE (loongson_machtypes)) + mtype = 0; + /* In Loongson platform, it is the responsibility of the bootloader/firmware + to supply the OS kernel with machine type information. */ + grub_memcpy (linux_args, loongson_machtypes[mtype], + sizeof (loongson_machtypes[mtype])); + *linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground + + target_addr; + linux_argv++; + linux_args += ALIGN_UP (sizeof (loongson_machtypes[mtype]), 4); + } +#endif + for (i = 1; i < argc; i++) { grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); @@ -287,6 +391,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), extra = linux_args; +#ifdef GRUB_MACHINE_MIPS_LOONGSON linux_envp = extra; envp_off = (grub_uint8_t *) linux_envp - (grub_uint8_t *) playground; linux_envs = (char *) (linux_envp + 5); @@ -314,8 +419,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + target_addr; linux_envs += ALIGN_UP (grub_strlen (linux_envs) + 1, 4); - linux_envp[4] = 0; +#endif +#endif grub_loader_set (grub_linux_boot, grub_linux_unload, 1); initrd_loaded = 0; @@ -329,11 +435,14 @@ 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_file_t *files = 0; + grub_size_t size = 0; void *initrd_src; grub_addr_t initrd_dest; grub_err_t err; + int i; + int nfiles = 0; + grub_uint8_t *ptr; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); @@ -342,41 +451,64 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load Linux first."); if (initrd_loaded) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd can be loaded."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued."); - grub_file_filter_disable_compression (); - file = grub_file_open (argv[0]); - if (! file) - return grub_errno; + files = grub_zalloc (argc * sizeof (files[0])); + if (!files) + goto fail; - size = grub_file_size (file); + for (i = 0; i < argc; i++) + { + grub_file_filter_disable_compression (); + files[i] = grub_file_open (argv[i]); + if (! files[i]) + goto fail; + nfiles++; + size += grub_file_size (files[i]); + } { grub_relocator_chunk_t ch; err = grub_relocator_alloc_chunk_align (relocator, &ch, - target_addr + linux_size + 0x10000, - (0xffffffff - size) + 1, + (target_addr & 0x1fffffff) + + linux_size + 0x10000, + (0x10000000 - size), size, 0x10000, GRUB_RELOCATOR_PREFERENCE_NONE); if (err) - { - grub_file_close (file); - return err; - } + goto fail; initrd_src = get_virtual_current_address (ch); initrd_dest = get_physical_target_address (ch) | 0x80000000; } - if (grub_file_read (file, initrd_src, size) != size) + ptr = initrd_src; + for (i = 0; i < nfiles; i++) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - grub_file_close (file); - - return grub_errno; + grub_ssize_t cursize = grub_file_size (files[i]); + if (grub_file_read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + goto fail; + } + ptr += cursize; } +#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS + { + char *tmp; + tmp = grub_xasprintf ("%s rd_start=0x%" PRIxGRUB_ADDR + " rd_size=0x%" PRIxGRUB_ADDR, params, + initrd_dest, size); + if (!tmp) + goto fail; + grub_free (params); + params = tmp; + } +#else grub_snprintf ((char *) playground + rd_addr_arg_off, sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%llx", (unsigned long long) initrd_dest); @@ -390,12 +522,16 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ((grub_uint32_t *) (playground + argv_off))[linux_argc] = target_addr + rd_size_arg_off; linux_argc++; +#endif initrd_loaded = 1; - grub_file_close (file); + fail: + for (i = 0; i < nfiles; i++) + grub_file_close (files[i]); + grub_free (files); - return GRUB_ERR_NONE; + return grub_errno; } static grub_command_t cmd_linux, cmd_initrd; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 4bfc2c191..fec1b5bf6 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -43,6 +43,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #ifdef GRUB_MACHINE_EFI #include #endif @@ -180,7 +182,7 @@ grub_multiboot_set_console (int console_type, int accepted_consoles, if (console_required) return grub_error (GRUB_ERR_BAD_OS, "OS requires a console but none is available"); - grub_printf ("WARNING: no console will be available to OS"); + grub_puts_ (N_("WARNING: no console will be available to OS")); accepts_video = 0; accepts_ega_text = 0; return GRUB_ERR_NONE; @@ -224,7 +226,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), file = grub_file_open (argv[0]); if (! file) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); + return grub_errno; grub_dl_ref (my_mod); @@ -307,7 +309,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), return err; } module = get_virtual_current_address (ch); - target = (grub_addr_t) get_virtual_current_address (ch); + target = get_physical_target_address (ch); } err = grub_multiboot_add_module (target, size, argc - 1, argv + 1); @@ -320,7 +322,10 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, module, size) != size) { grub_file_close (file); - return grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[0]); + return grub_errno; } grub_file_close (file); diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 0c29fe9c2..c6c88f177 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -22,12 +22,14 @@ # define ELFCLASSXX ELFCLASS32 # define Elf_Ehdr Elf32_Ehdr # define Elf_Phdr Elf32_Phdr +# define Elf_Shdr Elf32_Shdr #elif defined(MULTIBOOT_LOAD_ELF64) # define XX 64 # define E_MACHINE MULTIBOOT_ELF64_MACHINE # define ELFCLASSXX ELFCLASS64 # define Elf_Ehdr Elf64_Ehdr # define Elf_Phdr Elf64_Phdr +# define Elf_Shdr Elf64_Shdr #else #error "I'm confused" #endif @@ -223,3 +225,4 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) #undef ELFCLASSXX #undef Elf_Ehdr #undef Elf_Phdr +#undef Elf_Shdr diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 3141f0028..9a81afe8e 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -54,7 +54,7 @@ struct module int cmdline_size; }; -struct module *modules, *modules_last; +static struct module *modules, *modules_last; static grub_size_t cmdline_size; static grub_size_t total_modcmd; static unsigned modcnt; @@ -78,7 +78,7 @@ grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, grub_err_t grub_multiboot_load (grub_file_t file) { - char *buffer; + grub_properly_aligned_t *buffer; grub_ssize_t len; struct multiboot_header *header; grub_err_t err; @@ -101,11 +101,13 @@ grub_multiboot_load (grub_file_t file) return grub_error (GRUB_ERR_BAD_OS, "file too small"); } + COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0); + /* Look for the multiboot header in the buffer. The header should be at least 12 bytes and aligned on a 4-byte boundary. */ for (header = (struct multiboot_header *) buffer; - ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN)) + ((char *) header <= (char *) buffer + len - 12) || (header = 0); + header = (struct multiboot_header *) ((grub_uint32_t *) header + MULTIBOOT_HEADER_ALIGN / 4)) { if (header->magic == MULTIBOOT_HEADER_MAGIC && !(header->magic + header->architecture @@ -120,9 +122,11 @@ grub_multiboot_load (grub_file_t file) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found"); } + COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % 4 == 0); + for (tag = (struct multiboot_header_tag *) (header + 1); tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_header_tag *) ((char *) tag + tag->size)) + tag = (struct multiboot_header_tag *) ((grub_uint32_t *) tag + ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / 4)) switch (tag->type) { case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: @@ -208,7 +212,7 @@ grub_multiboot_load (grub_file_t file) if (addr_tag) { - int offset = ((char *) header - buffer - + int offset = ((char *) header - (char *) buffer - (addr_tag->header_addr - addr_tag->load_addr)); int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : addr_tag->load_end_addr - addr_tag->load_addr); @@ -415,7 +419,7 @@ fill_vbe_tag (struct multiboot_tag_vbe *tag) #endif static grub_err_t -retrieve_video_parameters (grub_uint8_t **ptrorig) +retrieve_video_parameters (grub_properly_aligned_t **ptrorig) { grub_err_t err; struct grub_video_mode_info mode_info; @@ -493,7 +497,8 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->common.framebuffer_type = MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT; tag->common.size = sizeof (tag->common); tag->common.reserved = 0; - *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } return GRUB_ERR_NONE; } @@ -508,7 +513,8 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) fill_vbe_tag (tag_vbe); - *ptrorig += ALIGN_UP (tag_vbe->size, MULTIBOOT_TAG_ALIGN); + *ptrorig += ALIGN_UP (tag_vbe->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } #endif @@ -559,7 +565,8 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) tag->common.size = sizeof (struct multiboot_tag_framebuffer_common) + 6; } - *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN); + *ptrorig += ALIGN_UP (tag->common.size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); return GRUB_ERR_NONE; } @@ -567,14 +574,16 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target) { - grub_uint8_t *ptrorig; - grub_uint8_t *mbistart; + grub_properly_aligned_t *ptrorig; + grub_properly_aligned_t *mbistart; grub_err_t err; grub_size_t bufsize; grub_relocator_chunk_t ch; bufsize = grub_multiboot_get_mbi_size (); + COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0); + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0, 0xffffffff - bufsize, bufsize, MULTIBOOT_TAG_ALIGN, @@ -592,14 +601,19 @@ grub_multiboot_make_mbi (grub_uint32_t *target) #endif mbistart = ptrorig; - ptrorig += 2 * sizeof (grub_uint32_t); + COMPILE_TIME_ASSERT ((2 * sizeof (grub_uint32_t)) + % sizeof (grub_properly_aligned_t) == 0); + COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN + % sizeof (grub_properly_aligned_t) == 0); + ptrorig += (2 * sizeof (grub_uint32_t)) / sizeof (grub_properly_aligned_t); { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_CMDLINE; tag->size = sizeof (struct multiboot_tag_string) + cmdline_size; grub_memcpy (tag->string, cmdline, cmdline_size); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } { @@ -607,7 +621,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; tag->size = sizeof (struct multiboot_tag_string) + sizeof (PACKAGE_STRING); grub_memcpy (tag->string, PACKAGE_STRING, sizeof (PACKAGE_STRING)); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } #ifdef GRUB_MACHINE_PCBIOS @@ -630,7 +645,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->cseg_16_len = info.cseg_16_len; tag->version = info.version; - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } } #endif @@ -648,14 +664,16 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->mod_start = cur->start; tag->mod_end = tag->mod_start + cur->size; grub_memcpy (tag->cmdline, cur->cmdline, cur->cmdline_size); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } } { struct multiboot_tag_mmap *tag = (struct multiboot_tag_mmap *) ptrorig; grub_fill_multiboot_mmap (tag); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } { @@ -668,7 +686,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->num = elf_sec_num; tag->entsize = elf_sec_entsize; tag->shndx = elf_sec_shstrndx; - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } { @@ -680,7 +699,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) /* Convert from bytes to kilobytes. */ tag->mem_lower = grub_mmap_get_lower () / 1024; tag->mem_upper = grub_mmap_get_upper () / 1024; - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } if (bootdev_set) @@ -693,7 +713,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->biosdev = biosdev; tag->slice = slice; tag->part = part; - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } { @@ -711,7 +732,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->type = MULTIBOOT_TAG_TYPE_EFI64; tag->size = sizeof (*tag); tag->pointer = (grub_addr_t) grub_efi_system_table; - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } #endif @@ -721,7 +743,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->type = MULTIBOOT_TAG_TYPE_EFI32; tag->size = sizeof (*tag); tag->pointer = (grub_addr_t) grub_efi_system_table; - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } #endif @@ -735,7 +758,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->type = MULTIBOOT_TAG_TYPE_ACPI_OLD; tag->size = sizeof (*tag) + sizeof (*a); grub_memcpy (tag->rsdp, a, sizeof (*a)); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } } @@ -748,7 +772,8 @@ grub_multiboot_make_mbi (grub_uint32_t *target) tag->type = MULTIBOOT_TAG_TYPE_ACPI_NEW; tag->size = sizeof (*tag) + a->length; grub_memcpy (tag->rsdp, a, a->length); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } } #endif @@ -757,10 +782,11 @@ grub_multiboot_make_mbi (grub_uint32_t *target) struct multiboot_tag *tag = (struct multiboot_tag *) ptrorig; tag->type = MULTIBOOT_TAG_TYPE_END; tag->size = sizeof (struct multiboot_tag); - ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) + / sizeof (grub_properly_aligned_t); } - ((grub_uint32_t *) mbistart)[0] = ptrorig - mbistart; + ((grub_uint32_t *) mbistart)[0] = (char *) ptrorig - (char *) mbistart; ((grub_uint32_t *) mbistart)[1] = 0; return GRUB_ERR_NONE; diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c index 249238d45..b0af5f75d 100644 --- a/grub-core/loader/powerpc/ieee1275/linux.c +++ b/grub-core/loader/powerpc/ieee1275/linux.c @@ -26,6 +26,10 @@ #include #include #include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #define ELF32_LOADMASK (0xc0000000UL) #define ELF64_LOADMASK (0xc000000000000000ULL) @@ -45,6 +49,51 @@ static char *linux_args; typedef void (*kernel_entry_t) (void *, unsigned long, int (void *), unsigned long, unsigned long); +static grub_addr_t +grub_linux_claimmap_iterate (grub_addr_t target, grub_size_t size, + grub_size_t align) +{ + grub_addr_t found_addr = (grub_addr_t) -1; + + auto int NESTED_FUNC_ATTR alloc_mem (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type); + int NESTED_FUNC_ATTR alloc_mem (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type) + { + grub_uint64_t end = addr + len; + addr = ALIGN_UP (addr, align); + target = ALIGN_UP (target, align); + + /* Target above the memory chunk. */ + if (type != GRUB_MEMORY_AVAILABLE || target > end) + return 0; + + /* Target inside the memory chunk. */ + if (target >= addr && target < end && size <= end - target) + { + if (grub_claimmap (target, size) == GRUB_ERR_NONE) + { + found_addr = target; + return 1; + } + } + /* Target below the memory chunk. */ + if (target < addr && addr + size <= end) + { + if (grub_claimmap (addr, size) == GRUB_ERR_NONE) + { + found_addr = addr; + return 1; + } + } + return 0; + } + + grub_machine_mmap_iterate (alloc_mem); + + return found_addr; +} + static grub_err_t grub_linux_boot (void) { @@ -102,34 +151,34 @@ grub_linux_unload (void) static grub_err_t grub_linux_load32 (grub_elf_t elf) { + Elf32_Addr base_addr; + grub_addr_t seg_addr; + grub_uint32_t align; + grub_uint32_t offset; Elf32_Addr entry; - int found_addr = 0; - /* Linux's entry point incorrectly contains a virtual address. */ - entry = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK; - if (entry == 0) - entry = 0x01400000; - - linux_size = grub_elf32_size (elf, 0); + linux_size = grub_elf32_size (elf, &base_addr, &align); if (linux_size == 0) return grub_errno; /* Pad it; the kernel scribbles over memory beyond its load address. */ linux_size += 0x100000; + /* Linux's entry point incorrectly contains a virtual address. */ + entry = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK; + + /* Linux's incorrectly contains a virtual address. */ + base_addr &= ~ELF32_LOADMASK; + offset = entry - base_addr; + /* On some systems, firmware occupies the memory we're trying to use. * Happily, Linux can be loaded anywhere (it relocates itself). Iterate * until we find an open area. */ - for (linux_addr = entry; linux_addr < entry + 200 * 0x100000; linux_addr += 0x100000) - { - grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n", - linux_addr, linux_size); - found_addr = grub_claimmap (linux_addr, linux_size); - if (found_addr != -1) - break; - } - if (found_addr == -1) + seg_addr = grub_linux_claimmap_iterate (base_addr & ~ELF32_LOADMASK, linux_size, align); + if (seg_addr == (grub_addr_t) -1) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory"); + linux_addr = seg_addr + offset; + /* Now load the segments into the area we claimed. */ auto grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load); grub_err_t offset_phdr (Elf32_Phdr *phdr, grub_addr_t *addr, int *do_load) @@ -141,9 +190,7 @@ grub_linux_load32 (grub_elf_t elf) } *do_load = 1; - /* Linux's program headers incorrectly contain virtual addresses. - * Translate those to physical, and offset to the area we claimed. */ - *addr = (phdr->p_paddr & ~ELF32_LOADMASK) + linux_addr; + *addr = (phdr->p_paddr - base_addr) + seg_addr; return 0; } return grub_elf32_load (elf, offset_phdr, 0, 0); @@ -152,34 +199,32 @@ grub_linux_load32 (grub_elf_t elf) static grub_err_t grub_linux_load64 (grub_elf_t elf) { + Elf64_Addr base_addr; + grub_addr_t seg_addr; + grub_uint64_t align; + grub_uint64_t offset; Elf64_Addr entry; - int found_addr = 0; - /* Linux's entry point incorrectly contains a virtual address. */ - entry = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK; - if (entry == 0) - entry = 0x01400000; - - linux_size = grub_elf64_size (elf, 0); + linux_size = grub_elf64_size (elf, &base_addr, &align); if (linux_size == 0) return grub_errno; /* Pad it; the kernel scribbles over memory beyond its load address. */ linux_size += 0x100000; + base_addr &= ~ELF64_LOADMASK; + entry = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK; + offset = entry - base_addr; + /* Linux's incorrectly contains a virtual address. */ + /* On some systems, firmware occupies the memory we're trying to use. * Happily, Linux can be loaded anywhere (it relocates itself). Iterate * until we find an open area. */ - for (linux_addr = entry; linux_addr < entry + 200 * 0x100000; linux_addr += 0x100000) - { - grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n", - linux_addr, linux_size); - found_addr = grub_claimmap (linux_addr, linux_size); - if (found_addr != -1) - break; - } - if (found_addr == -1) + seg_addr = grub_linux_claimmap_iterate (base_addr & ~ELF64_LOADMASK, linux_size, align); + if (seg_addr == (grub_addr_t) -1) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't claim memory"); + linux_addr = seg_addr + offset; + /* Now load the segments into the area we claimed. */ auto grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load); grub_err_t offset_phdr (Elf64_Phdr *phdr, grub_addr_t *addr, int *do_load) @@ -190,9 +235,8 @@ grub_linux_load64 (grub_elf_t elf) return 0; } *do_load = 1; - /* Linux's program headers incorrectly contain virtual addresses. - * Translate those to physical, and offset to the area we claimed. */ - *addr = (phdr->p_paddr & ~ELF64_LOADMASK) + linux_addr; + + *addr = (phdr->p_paddr - base_addr) + seg_addr; return 0; } return grub_elf64_load (elf, offset_phdr, 0, 0); @@ -203,9 +247,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_elf_t elf = 0; - int i; int size; - char *dest; grub_dl_ref (my_mod); @@ -240,23 +282,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto out; } - size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]); - for (i = 0; i < argc; i++) - size += grub_strlen (argv[i]) + 1; - - linux_args = grub_malloc (size); + size = grub_loader_cmdline_size(argc, argv); + linux_args = grub_malloc (size + sizeof (LINUX_IMAGE)); if (! linux_args) goto out; - /* Specify the boot file. */ - dest = grub_stpcpy (linux_args, "BOOT_IMAGE="); - dest = grub_stpcpy (dest, argv[0]); - - for (i = 1; i < argc; i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, + size); out: @@ -283,11 +317,13 @@ 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_file_t *files = 0; + grub_size_t size = 0; grub_addr_t first_addr; grub_addr_t addr; - int found_addr = 0; + int i; + int nfiles = 0; + grub_uint8_t *ptr; if (argc == 0) { @@ -301,46 +337,52 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - grub_file_filter_disable_compression (); - file = grub_file_open (argv[0]); - if (! file) + files = grub_zalloc (argc * sizeof (files[0])); + if (!files) goto fail; + for (i = 0; i < argc; i++) + { + grub_file_filter_disable_compression (); + files[i] = grub_file_open (argv[i]); + if (! files[i]) + goto fail; + nfiles++; + size += grub_file_size (files[i]); + } + first_addr = linux_addr + linux_size; - size = grub_file_size (file); /* Attempt to claim at a series of addresses until successful in the same way that grub_rescue_cmd_linux does. */ - for (addr = first_addr; addr < first_addr + 200 * 0x100000; addr += 0x100000) - { - grub_dprintf ("loader", "Attempting to claim at 0x%x, size 0x%x.\n", - addr, size); - found_addr = grub_claimmap (addr, size); - if (found_addr != -1) - break; - } - - if (found_addr == -1) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot claim memory"); - goto fail; - } + addr = grub_linux_claimmap_iterate (first_addr, size, 0x100000); + if (addr == (grub_addr_t) -1) + goto fail; grub_dprintf ("loader", "Loading initrd at 0x%x, size 0x%x\n", addr, size); - if (grub_file_read (file, (void *) addr, size) != size) + ptr = (void *) addr; + for (i = 0; i < nfiles; i++) { - grub_ieee1275_release (addr, size); - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; + grub_ssize_t cursize = grub_file_size (files[i]); + if (grub_file_read (files[i], ptr, cursize) != cursize) + { + grub_ieee1275_release (addr, size); + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + goto fail; + } + ptr += cursize; } initrd_addr = addr; initrd_size = size; fail: - if (file) - grub_file_close (file); + for (i = 0; i < nfiles; i++) + grub_file_close (files[i]); + grub_free (files); return grub_errno; } diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c index d4b5f2aea..7b68f38b0 100644 --- a/grub-core/loader/sparc64/ieee1275/linux.c +++ b/grub-core/loader/sparc64/ieee1275/linux.c @@ -27,6 +27,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_dl_t my_mod; @@ -247,7 +250,7 @@ grub_linux_load64 (grub_elf_t elf) linux_entry = elf->ehdr.ehdr64.e_entry; linux_addr = 0x40004000; off = 0x4000; - linux_size = grub_elf64_size (elf, 0); + linux_size = grub_elf64_size (elf, 0, 0); if (linux_size == 0) return grub_errno; @@ -295,9 +298,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_elf_t elf = 0; - int i; int size; - char *dest; grub_dl_ref (my_mod); @@ -333,23 +334,16 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto out; } - size = sizeof ("BOOT_IMAGE=") + grub_strlen (argv[0]); - for (i = 0; i < argc; i++) - size += grub_strlen (argv[i]) + 1; + size = grub_loader_cmdline_size(argc, argv); - linux_args = grub_malloc (size); + linux_args = grub_malloc (size + sizeof (LINUX_IMAGE)); if (! linux_args) goto out; - /* Specify the boot file. */ - dest = grub_stpcpy (linux_args, "BOOT_IMAGE="); - dest = grub_stpcpy (dest, argv[0]); - - for (i = 1; i < argc; i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1, + size); out: if (elf) @@ -377,11 +371,14 @@ 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_file_t *files = 0; + grub_size_t size = 0; grub_addr_t paddr; grub_addr_t addr; int ret; + int i; + int nfiles = 0; + grub_uint8_t *ptr; if (argc == 0) { @@ -395,13 +392,21 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - grub_file_filter_disable_compression (); - file = grub_file_open (argv[0]); - if (! file) + files = grub_zalloc (argc * sizeof (files[0])); + if (!files) goto fail; + for (i = 0; i < argc; i++) + { + grub_file_filter_disable_compression (); + files[i] = grub_file_open (argv[i]); + if (! files[i]) + goto fail; + nfiles++; + size += grub_file_size (files[i]); + } + addr = 0x60000000; - size = grub_file_size (file); paddr = alloc_phys (size); if (paddr == (grub_addr_t) -1) @@ -421,10 +426,18 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n", addr, paddr, size); - if (grub_file_read (file, (void *) addr, size) != size) + ptr = (void *) addr; + for (i = 0; i < nfiles; i++) { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; + grub_ssize_t cursize = grub_file_size (files[i]); + if (grub_file_read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + goto fail; + } + ptr += cursize; } initrd_addr = addr; @@ -432,8 +445,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), initrd_size = size; fail: - if (file) - grub_file_close (file); + for (i = 0; i < nfiles; i++) + grub_file_close (files[i]); + grub_free (files); return grub_errno; } diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index d0b32dc6f..7da355183 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -34,6 +34,12 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + +#if defined (__i386) && !defined (GRUB_MACHINE_EFI) +#include +#endif + struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0; static int driverspackagenum = 0; static int driversnum = 0; @@ -44,7 +50,7 @@ grub_size_t grub_xnu_heap_size = 0; struct grub_relocator *grub_xnu_relocator; static grub_err_t -grub_xnu_register_memory (char *prefix, int *suffix, +grub_xnu_register_memory (const char *prefix, int *suffix, grub_addr_t addr, grub_size_t size); grub_err_t grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target) @@ -97,7 +103,8 @@ grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur) /* Compute the size of device tree in xnu format. */ static grub_size_t -grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start, char *name) +grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start, + const char *name) { grub_size_t ret; struct grub_xnu_devtree_key *cur; @@ -128,7 +135,8 @@ grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start, char *name) /* Write devtree in XNU format at curptr assuming the head is named NAME.*/ static void * grub_xnu_writetree_toheap_real (void *curptr, - struct grub_xnu_devtree_key *start, char *name) + struct grub_xnu_devtree_key *start, + const char *name) { struct grub_xnu_devtree_key *cur; int nkeys = 0, nvals = 0; @@ -243,7 +251,7 @@ grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) /* Find a key or value in parent key. */ struct grub_xnu_devtree_key * -grub_xnu_find_key (struct grub_xnu_devtree_key *parent, char *name) +grub_xnu_find_key (struct grub_xnu_devtree_key *parent, const char *name) { struct grub_xnu_devtree_key *cur; for (cur = parent; cur; cur = cur->next) @@ -253,7 +261,7 @@ grub_xnu_find_key (struct grub_xnu_devtree_key *parent, char *name) } struct grub_xnu_devtree_key * -grub_xnu_create_key (struct grub_xnu_devtree_key **parent, char *name) +grub_xnu_create_key (struct grub_xnu_devtree_key **parent, const char *name) { struct grub_xnu_devtree_key *ret; ret = grub_xnu_find_key (*parent, name); @@ -279,7 +287,7 @@ grub_xnu_create_key (struct grub_xnu_devtree_key **parent, char *name) } struct grub_xnu_devtree_key * -grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name) +grub_xnu_create_value (struct grub_xnu_devtree_key **parent, const char *name) { struct grub_xnu_devtree_key *ret; ret = grub_xnu_find_key (*parent, name); @@ -338,7 +346,8 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_macho_t macho; grub_uint32_t startcode, endcode; int i; - char *ptr, *loadaddr; + char *ptr; + void *loadaddr; grub_addr_t loadaddr_target; if (argc < 1) @@ -371,7 +380,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), if (!grub_xnu_relocator) return grub_errno; grub_xnu_heap_target_start = startcode; - err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr, + err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr, &loadaddr_target); if (err) @@ -382,7 +391,8 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), } /* Load kernel. */ - err = grub_macho_load32 (macho, loadaddr - startcode, GRUB_MACHO_NOBSS); + err = grub_macho_load32 (macho, (char *) loadaddr - startcode, + GRUB_MACHO_NOBSS); if (err) { grub_macho_close (macho); @@ -424,6 +434,12 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), if (ptr != grub_xnu_cmdline) *(ptr - 1) = 0; +#if defined (__i386) && !defined (GRUB_MACHINE_EFI) + err = grub_efiemu_autocore (); + if (err) + return err; +#endif + grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0); grub_xnu_lock (); @@ -440,7 +456,8 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_macho_t macho; grub_uint64_t startcode, endcode; int i; - char *ptr, *loadaddr; + char *ptr; + void *loadaddr; grub_addr_t loadaddr_target; if (argc < 1) @@ -476,7 +493,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), if (!grub_xnu_relocator) return grub_errno; grub_xnu_heap_target_start = startcode; - err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr, + err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr, &loadaddr_target); if (err) @@ -487,7 +504,8 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), } /* Load kernel. */ - err = grub_macho_load64 (macho, loadaddr - startcode, GRUB_MACHO_NOBSS); + err = grub_macho_load64 (macho, (char *) loadaddr - startcode, + GRUB_MACHO_NOBSS); if (err) { grub_macho_close (macho); @@ -529,6 +547,12 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), if (ptr != grub_xnu_cmdline) *(ptr - 1) = 0; +#if defined (__i386) && !defined (GRUB_MACHINE_EFI) + err = grub_efiemu_autocore (); + if (err) + return err; +#endif + grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0); grub_xnu_lock (); @@ -540,7 +564,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), /* Register a memory in a memory map under name PREFIXSUFFIX and increment SUFFIX. */ static grub_err_t -grub_xnu_register_memory (char *prefix, int *suffix, +grub_xnu_register_memory (const char *prefix, int *suffix, grub_addr_t addr, grub_size_t size) { struct grub_xnu_devtree_key *chosen; @@ -620,7 +644,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, *buf0; + grub_uint8_t *buf; + void *buf0; grub_addr_t buf_target; grub_size_t infoplistsize = 0, machosize = 0; char *name, *nameend; @@ -676,7 +701,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) return err; - err = grub_xnu_heap_malloc (neededspace, (void **) &buf0, &buf_target); + err = grub_xnu_heap_malloc (neededspace, &buf0, &buf_target); if (err) return err; buf = buf0; @@ -688,7 +713,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the binary. */ if (macho) { - exthead->binaryaddr = buf_target + (buf - buf0); + exthead->binaryaddr = buf_target + (buf - (grub_uint8_t *) buf0); exthead->binarysize = machosize; if (grub_xnu_is_64bit) err = grub_macho_readfile64 (macho, buf); @@ -707,15 +732,16 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the plist. */ if (infoplist) { - exthead->infoplistaddr = buf_target + (buf - buf0); + exthead->infoplistaddr = buf_target + (buf - (grub_uint8_t *) buf0); exthead->infoplistsize = infoplistsize + 1; if (grub_file_read (infoplist, buf, infoplistsize) != (grub_ssize_t) (infoplistsize)) { grub_file_close (infoplist); - grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s: ", - infoplistname); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s: "), + infoplistname); + return grub_errno; } grub_file_close (infoplist); buf[infoplistsize] = 0; @@ -723,7 +749,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) } grub_errno = GRUB_ERR_NONE; - exthead->nameaddr = (buf - buf0) + buf_target; + exthead->nameaddr = (buf - (grub_uint8_t *) buf0) + buf_target; exthead->namesize = namelen + 1; grub_memcpy (buf, name, namelen); buf[namelen] = 0; @@ -757,8 +783,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), file = grub_file_open (args[0]); if (! file) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, - "couldn't load driver package"); + return grub_errno; /* Sometimes caches are fat binary. Errgh. */ if (grub_file_read (file, &head, sizeof (head)) @@ -767,8 +792,9 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), /* I don't know the internal structure of package but can hardly imagine a valid package shorter than 20 bytes. */ grub_file_close (file); - grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]); + return grub_errno; } /* Find the corresponding architecture. */ @@ -779,9 +805,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), if (! archs) { grub_file_close (file); - grub_error_push (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "couldn't read file %s", args[0]); + return grub_errno; } if (grub_file_read (file, archs, @@ -789,8 +813,10 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), != (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs) { grub_free (archs); - grub_error_push (); - return grub_error (GRUB_ERR_READ_ERROR, "cannot read fat header"); + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"), + args[0]); + return grub_errno; } for (i = 0; i < narchs; i++) { @@ -842,8 +868,9 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen)) { grub_file_close (file); - grub_error_push (); - return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]); + return grub_errno; } grub_file_close (file); @@ -870,8 +897,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), file = grub_file_open (args[0]); if (! file) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, - "couldn't load ramdisk"); + return grub_errno; err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) @@ -882,12 +908,12 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), err = grub_xnu_heap_malloc (size, &loadto, &loadto_target); if (err) return err; - if (grub_file_read (file, loadto, size) - != (grub_ssize_t) (size)) + if (grub_file_read (file, loadto, 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]); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]); + return grub_errno; } return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size); } @@ -895,7 +921,8 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), /* Returns true if the kext should be loaded according to plist and osbundlereq. Also fill BINNAME. */ static int -grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, +grub_xnu_check_os_bundle_required (char *plistname, + const char *osbundlereq, char **binname) { grub_file_t file; @@ -910,27 +937,20 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, file = grub_file_open (plistname); if (! file) - { - grub_file_close (file); - grub_error_push (); - grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname); - return 0; - } + return 0; size = grub_file_size (file); buf = grub_malloc (size); if (! buf) { grub_file_close (file); - grub_error_push (); - grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read file %s", plistname); return 0; } if (grub_file_read (file, buf, size) != (grub_ssize_t) (size)) { grub_file_close (file); - grub_error_push (); - grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), plistname); return 0; } grub_file_close (file); @@ -1010,7 +1030,7 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */ grub_err_t -grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, +grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired, int maxrecursion) { grub_device_t dev; @@ -1076,7 +1096,7 @@ grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, /* Load extension DIRNAME. (extensions are directories in xnu) */ grub_err_t -grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, +grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired, int maxrecursion) { grub_device_t dev; @@ -1124,7 +1144,7 @@ grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, newdirname = grub_malloc (grub_strlen (dirname) + 20); if (! newdirname) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate buffer"); + return grub_errno; grub_strcpy (newdirname, dirname); newdirname[grub_strlen (dirname)] = '/'; newdirname[grub_strlen (dirname) + 1] = 0; @@ -1198,6 +1218,10 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)), int argc, char *args[]) { grub_file_t binfile = 0; + + if (! grub_xnu_heap_size) + return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); + if (argc == 2) { /* User explicitly specified plist and binary. */ @@ -1229,6 +1253,9 @@ grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)), if (argc != 1 && argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required"); + if (! grub_xnu_heap_size) + return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); + if (argc == 1) return grub_xnu_scan_dir_for_kexts (args[0], "console,root,local-root,network-root", @@ -1238,8 +1265,7 @@ grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)), char *osbundlerequired = grub_strdup (args[1]), *ptr; grub_err_t err; if (! osbundlerequired) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "couldn't allocate string temporary space"); + return grub_errno; for (ptr = osbundlerequired; *ptr; ptr++) *ptr = grub_tolower (*ptr); err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10); @@ -1370,6 +1396,9 @@ grub_cmd_xnu_splash (grub_extcmd_context_t ctxt, if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + if (! grub_xnu_heap_size) + return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); + if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, "stretch") == 0) @@ -1398,7 +1427,7 @@ grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)), #endif void -grub_xnu_lock () +grub_xnu_lock (void) { if (!locked) grub_dl_ref (my_mod); @@ -1406,7 +1435,7 @@ grub_xnu_lock () } void -grub_xnu_unlock () +grub_xnu_unlock (void) { if (locked) grub_dl_unref (my_mod); diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index 8f0e24483..d7f9adaaf 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -25,6 +25,7 @@ #include #include #include +#include static void *grub_xnu_hibernate_image; @@ -59,11 +60,13 @@ grub_xnu_resume (char *imagename) /* Read the header. */ if (grub_file_read (file, &hibhead, sizeof (hibhead)) - !=sizeof (hibhead)) + != sizeof (hibhead)) { grub_file_close (file); - return grub_error (GRUB_ERR_READ_ERROR, - "cannot read the hibernate header"); + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, + N_("premature end of file %s"), imagename); + return grub_errno; } /* Check the header. */ @@ -138,7 +141,10 @@ grub_xnu_resume (char *imagename) != (grub_ssize_t) codesize) { grub_file_close (file); - return grub_error (GRUB_ERR_READ_ERROR, "cannot read resume image"); + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, + N_("premature end of file %s"), imagename); + return grub_errno; } /* Read image. */ @@ -147,7 +153,10 @@ grub_xnu_resume (char *imagename) != (grub_ssize_t) hibhead.image_size) { grub_file_close (file); - return grub_error (GRUB_ERR_READ_ERROR, "cannot read resume image"); + if (!grub_errno) + grub_error (GRUB_ERR_READ_ERROR, + N_("premature end of file %s"), imagename); + return grub_errno; } grub_file_close (file); diff --git a/grub-core/mmap/efi/mmap.c b/grub-core/mmap/efi/mmap.c index 5b82a8717..b34a3ba30 100644 --- a/grub-core/mmap/efi/mmap.c +++ b/grub-core/mmap/efi/mmap.c @@ -194,7 +194,6 @@ grub_mmap_unregister (int handle) { struct overlay *curover, *prevover; grub_efi_boot_services_t *b; - grub_efi_status_t status; b = grub_efi_system_table->boot_services; @@ -204,7 +203,7 @@ grub_mmap_unregister (int handle) { if (curover->handle == handle) { - status = efi_call_2 (b->free_pages, curover->address, curover->pages); + efi_call_2 (b->free_pages, curover->address, curover->pages); if (prevover != 0) prevover->next = curover->next; else @@ -273,7 +272,7 @@ grub_mmap_malign_and_register (grub_uint64_t align __attribute__ ((unused)), overlays = curover; *handle = curover->handle; - return UINT_TO_PTR (curover->address); + return (void *) (grub_addr_t) curover->address; } void diff --git a/grub-core/mmap/i386/mmap.c b/grub-core/mmap/i386/mmap.c index e9c030b7b..648a7df4b 100644 --- a/grub-core/mmap/i386/mmap.c +++ b/grub-core/mmap/i386/mmap.c @@ -54,7 +54,7 @@ grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size, { /* FIXME: use low-memory mm allocation once it's available. */ grub_mmap_iterate (find_hook); - ret = UINT_TO_PTR (highestlow); + ret = (void *) (grub_addr_t) highestlow; } else ret = grub_memalign (align, size); @@ -65,7 +65,7 @@ grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size, return 0; } - *handle = grub_mmap_register (PTR_TO_UINT64 (ret), size, type); + *handle = grub_mmap_register ((grub_addr_t) ret, size, type); if (! *handle) { grub_free (ret); @@ -93,7 +93,7 @@ grub_mmap_free_and_unregister (int handle) grub_mmap_unregister (handle); if (addr >= 0x100000) - grub_free (UINT_TO_PTR (addr)); + grub_free ((void *) (grub_addr_t) addr); } #endif diff --git a/grub-core/mmap/i386/pc/mmap.c b/grub-core/mmap/i386/pc/mmap.c index 8dec083f8..7f170b65d 100644 --- a/grub-core/mmap/i386/pc/mmap.c +++ b/grub-core/mmap/i386/pc/mmap.c @@ -101,8 +101,8 @@ preboot (int noreturn __attribute__ ((unused))) grub_memcpy (hooktarget, &grub_machine_mmaphook_start, &grub_machine_mmaphook_end - &grub_machine_mmaphook_start); - *((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4; - *((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4; + *((grub_uint16_t *) 0x4a) = ((grub_addr_t) hooktarget) >> 4; + *((grub_uint16_t *) 0x56) = ((grub_addr_t) hooktarget) >> 4; *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12 - &grub_machine_mmaphook_start; *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15 @@ -191,7 +191,7 @@ grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), int handle __attribute__ ((unused))) { grub_err_t err; - static void *preb_handle = 0; + static struct grub_preboot *preb_handle = 0; err = malloc_hook (); if (err) diff --git a/grub-core/mmap/mips/yeeloong/uppermem.c b/grub-core/mmap/mips/uppermem.c similarity index 98% rename from grub-core/mmap/mips/yeeloong/uppermem.c rename to grub-core/mmap/mips/uppermem.c index 723b6a888..832618540 100644 --- a/grub-core/mmap/mips/yeeloong/uppermem.c +++ b/grub-core/mmap/mips/uppermem.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include grub_uint64_t grub_mmap_get_lower (void) diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c index 1c1825490..07a71336b 100644 --- a/grub-core/mmap/mmap.c +++ b/grub-core/mmap/mmap.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE struct grub_mmap_region *grub_mmap_overlays = 0; diff --git a/grub-core/modinfo.sh.in b/grub-core/modinfo.sh.in new file mode 100644 index 000000000..ff31ca816 --- /dev/null +++ b/grub-core/modinfo.sh.in @@ -0,0 +1,4 @@ +#!/bin/sh + +grub_modinfo_target_cpu=@target_cpu@ +grub_modinfo_platform=@platform@ diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c new file mode 100644 index 000000000..c9a7cb21e --- /dev/null +++ b/grub-core/net/arp.c @@ -0,0 +1,178 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +/* ARP header operation codes */ +enum + { + ARP_REQUEST = 1, + ARP_REPLY = 2 + }; + +enum + { + /* IANA ARP constant to define hardware type as ethernet. */ + GRUB_NET_ARPHRD_ETHERNET = 1 + }; + +struct arphdr { + grub_uint16_t hrd; + grub_uint16_t pro; + grub_uint8_t hln; + grub_uint8_t pln; + grub_uint16_t op; +} __attribute__ ((packed)); + + +grub_err_t +grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr) +{ + struct grub_net_buff nb; + struct arphdr *arp_header; + grub_net_link_level_address_t target_hw_addr; + grub_uint8_t *aux, arp_data[128]; + grub_err_t err; + int i; + grub_size_t addrlen; + grub_uint16_t etherpro; + grub_uint8_t *nbd; + + if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + { + addrlen = 4; + etherpro = GRUB_NET_ETHERTYPE_IP; + } + else + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported address family"); + + /* Build a request packet. */ + nb.head = arp_data; + nb.end = arp_data + sizeof (arp_data); + grub_netbuff_clear (&nb); + grub_netbuff_reserve (&nb, 128); + + err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + addrlen)); + if (err) + return err; + + arp_header = (struct arphdr *) nb.data; + arp_header->hrd = grub_cpu_to_be16 (GRUB_NET_ARPHRD_ETHERNET); + arp_header->hln = 6; + arp_header->pro = grub_cpu_to_be16 (etherpro); + arp_header->pln = addrlen; + arp_header->op = grub_cpu_to_be16 (ARP_REQUEST); + aux = (grub_uint8_t *) arp_header + sizeof (*arp_header); + /* Sender hardware address. */ + grub_memcpy (aux, &inf->hwaddress.mac, 6); + + aux += 6; + /* Sender protocol address */ + grub_memcpy (aux, &inf->address.ipv4, 4); + aux += addrlen; + /* Target hardware address */ + for (i = 0; i < 6; i++) + aux[i] = 0x00; + aux += 6; + /* Target protocol address */ + grub_memcpy (aux, &proto_addr->ipv4, 4); + grub_memset (&target_hw_addr.mac, 0xff, 6); + + nbd = nb.data; + send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP); + for (i = 0; i < GRUB_NET_TRIES; i++) + { + if (grub_net_link_layer_resolve_check (inf, proto_addr)) + return GRUB_ERR_NONE; + grub_net_poll_cards (GRUB_NET_INTERVAL); + if (grub_net_link_layer_resolve_check (inf, proto_addr)) + return GRUB_ERR_NONE; + nb.data = nbd; + send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP); + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_net_arp_receive (struct grub_net_buff *nb, + struct grub_net_card *card) +{ + struct arphdr *arp_header = (struct arphdr *) nb->data; + grub_uint8_t *sender_hardware_address; + grub_uint8_t *target_hardware_address; + grub_net_network_level_address_t sender_addr, target_addr; + grub_net_link_level_address_t sender_hw_addr; + struct grub_net_network_level_interface *inf; + grub_uint8_t *sender_protocol_address, *target_protocol_address; + + sender_hardware_address = + (grub_uint8_t *) arp_header + sizeof (*arp_header); + sender_protocol_address = sender_hardware_address + arp_header->hln; + target_hardware_address = sender_protocol_address + arp_header->pln; + target_protocol_address = target_hardware_address + arp_header->hln; + if (grub_be_to_cpu16 (arp_header->pro) == GRUB_NET_ETHERTYPE_IP + && arp_header->pln == 4) + { + sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + grub_memcpy (&sender_addr.ipv4, sender_protocol_address, 4); + grub_memcpy (&target_addr.ipv4, target_protocol_address, 4); + } + else + return GRUB_ERR_NONE; + + sender_hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (sender_hw_addr.mac, sender_hardware_address, + sizeof (sender_hw_addr.mac)); + grub_net_link_layer_add_address (card, &sender_addr, &sender_hw_addr, 1); + + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + /* Am I the protocol address target? */ + if (grub_net_addr_cmp (&inf->address, &target_addr) == 0 + && grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST) + { + grub_net_link_level_address_t target; + /* We've already checked that pln is either 4 or 16. */ + char tmp[arp_header->pln]; + + target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (target.mac, sender_hardware_address, 6); + grub_memcpy (target_hardware_address, target.mac, 6); + grub_memcpy (sender_hardware_address, inf->hwaddress.mac, 6); + + grub_memcpy (tmp, sender_protocol_address, arp_header->pln); + grub_memcpy (sender_protocol_address, target_protocol_address, + arp_header->pln); + grub_memcpy (target_protocol_address, tmp, arp_header->pln); + + /* Change operation to REPLY and send packet */ + arp_header->op = grub_be_to_cpu16 (ARP_REPLY); + send_ethernet_packet (inf, nb, target, GRUB_NET_ETHERTYPE_ARP); + } + } + return GRUB_ERR_NONE; +} diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c new file mode 100644 index 000000000..ea8943a32 --- /dev/null +++ b/grub-core/net/bootp.c @@ -0,0 +1,575 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static char * +grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), + const char *val __attribute__ ((unused))) +{ + return NULL; +} + +static void +set_env_limn_ro (const char *intername, const char *suffix, + char *value, grub_size_t len) +{ + char c; + char varname[sizeof ("net_") + grub_strlen (intername) + sizeof ("_") + + grub_strlen (suffix)]; + grub_snprintf (varname, sizeof (varname), "net_%s_%s", intername, suffix); + c = value[len]; + value[len] = 0; + grub_env_set (varname, value); + value[len] = c; + grub_register_variable_hook (varname, 0, grub_env_write_readonly); +} + +static void +parse_dhcp_vendor (const char *name, void *vend, int limit) +{ + grub_uint8_t *ptr, *ptr0; + + ptr = ptr0 = vend; + + if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0 + || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1 + || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2 + || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3) + return; + ptr = ptr + sizeof (grub_uint32_t); + while (ptr - ptr0 < limit) + { + grub_uint8_t tagtype; + grub_uint8_t taglength; + + tagtype = *ptr++; + + /* Pad tag. */ + if (tagtype == GRUB_NET_BOOTP_PAD) + continue; + + /* End tag. */ + if (tagtype == GRUB_NET_BOOTP_END) + return; + + taglength = *ptr++; + + switch (tagtype) + { + case GRUB_NET_BOOTP_ROUTER: + if (taglength == 4) + { + grub_net_network_level_netaddress_t target; + grub_net_network_level_address_t gw; + char rname[grub_strlen (name) + sizeof (":default")]; + + target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + target.ipv4.base = 0; + target.ipv4.masksize = 0; + gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + grub_memcpy (&gw.ipv4, ptr, sizeof (gw.ipv4)); + grub_snprintf (rname, sizeof (rname), "%s:default", name); + grub_net_add_route_gw (rname, target, gw); + } + break; + case GRUB_NET_BOOTP_DNS: + { + int i; + for (i = 0; i < taglength / 4; i++) + { + struct grub_net_network_level_address s; + s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + s.ipv4 = grub_get_unaligned32 (ptr); + grub_net_add_dns_server (&s); + ptr += 4; + } + } + break; + case GRUB_NET_BOOTP_HOSTNAME: + set_env_limn_ro (name, "hostname", (char *) ptr, taglength); + break; + + case GRUB_NET_BOOTP_DOMAIN: + set_env_limn_ro (name, "domain", (char *) ptr, taglength); + break; + + case GRUB_NET_BOOTP_ROOT_PATH: + set_env_limn_ro (name, "rootpath", (char *) ptr, taglength); + break; + + case GRUB_NET_BOOTP_EXTENSIONS_PATH: + set_env_limn_ro (name, "extensionspath", (char *) ptr, taglength); + break; + + /* If you need any other options please contact GRUB + developpement team. */ + } + + ptr += taglength; + } +} + +#define OFFSET_OF(x, y) ((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y)) + +struct grub_net_network_level_interface * +grub_net_configure_by_dhcp_ack (const char *name, + struct grub_net_card *card, + grub_net_interface_flags_t flags, + const struct grub_net_bootp_packet *bp, + grub_size_t size, + int is_def, char **device, char **path) +{ + grub_net_network_level_address_t addr; + grub_net_link_level_address_t hwaddr; + struct grub_net_network_level_interface *inter; + + addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + addr.ipv4 = bp->your_ip; + + if (device) + *device = 0; + if (path) + *path = 0; + + grub_memcpy (hwaddr.mac, bp->mac_addr, + bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len + : sizeof (hwaddr.mac)); + hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + + inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags); + if (bp->gateway_ip) + { + grub_net_network_level_netaddress_t target; + grub_net_network_level_address_t gw; + char rname[grub_strlen (name) + sizeof (":gw")]; + + target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + target.ipv4.base = bp->server_ip; + target.ipv4.masksize = 32; + gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + gw.ipv4 = bp->gateway_ip; + grub_snprintf (rname, sizeof (rname), "%s:gw", name); + grub_net_add_route_gw (rname, target, gw); + } + if (bp->gateway_ip || bp->server_ip) + { + grub_net_network_level_netaddress_t target; + target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + target.ipv4.base = bp->gateway_ip ? bp->gateway_ip : bp->server_ip; + target.ipv4.masksize = 32; + grub_net_add_route (name, target, inter); + } + + if (size > OFFSET_OF (boot_file, bp)) + set_env_limn_ro (name, "boot_file", (char *) bp->boot_file, + sizeof (bp->boot_file)); + if (is_def) + grub_net_default_server = 0; + if (size > OFFSET_OF (server_name, bp) + && bp->server_name[0]) + { + set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name, + sizeof (bp->server_name)); + if (is_def && !grub_net_default_server) + { + grub_net_default_server = grub_strdup (bp->server_name); + grub_print_error (); + } + if (device && !*device) + { + *device = grub_xasprintf ("tftp,%s", bp->server_name); + grub_print_error (); + } + } + if (is_def && !grub_net_default_server) + { + grub_net_default_server = grub_xasprintf ("%d.%d.%d.%d", + ((grub_uint8_t *) &bp->server_ip)[0], + ((grub_uint8_t *) &bp->server_ip)[1], + ((grub_uint8_t *) &bp->server_ip)[2], + ((grub_uint8_t *) &bp->server_ip)[3]); + grub_print_error (); + } + + if (device && !*device) + { + *device = grub_xasprintf ("tftp,%d.%d.%d.%d", + ((grub_uint8_t *) &bp->server_ip)[0], + ((grub_uint8_t *) &bp->server_ip)[1], + ((grub_uint8_t *) &bp->server_ip)[2], + ((grub_uint8_t *) &bp->server_ip)[3]); + grub_print_error (); + } + if (size > OFFSET_OF (boot_file, bp) && path) + { + *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); + grub_print_error (); + if (*path) + { + char *slash; + slash = grub_strrchr (*path, '/'); + if (slash) + *slash = 0; + else + **path = 0; + } + } + if (size > OFFSET_OF (vendor, bp)) + parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp)); + + inter->dhcp_ack = grub_malloc (size); + if (inter->dhcp_ack) + { + grub_memcpy (inter->dhcp_ack, bp, size); + inter->dhcp_acklen = size; + } + else + grub_errno = GRUB_ERR_NONE; + + return inter; +} + +void +grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_card *card) +{ + char *name; + struct grub_net_network_level_interface *inf; + + name = grub_xasprintf ("%s:dhcp", card->name); + if (!name) + { + grub_print_error (); + return; + } + grub_net_configure_by_dhcp_ack (name, card, + 0, (const struct grub_net_bootp_packet *) nb->data, + (nb->tail - nb->data), 0, 0, 0); + grub_free (name); + if (grub_errno) + grub_print_error (); + else + { + FOR_NET_NETWORK_LEVEL_INTERFACES(inf) + if (grub_memcmp (inf->name, card->name, grub_strlen (card->name)) == 0 + && grub_memcmp (inf->name + grub_strlen (card->name), + ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0) + { + grub_net_network_level_interface_unregister (inf); + break; + } + } +} + +static char +hexdigit (grub_uint8_t val) +{ + if (val < 10) + return val + '0'; + return val + 'a' - 10; +} + +static grub_err_t +grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_network_level_interface *inter; + int num; + grub_uint8_t *ptr; + grub_uint8_t taglength; + + if (argc < 4) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "4 arguments expected"); + + FOR_NET_NETWORK_LEVEL_INTERFACES (inter) + if (grub_strcmp (inter->name, args[1]) == 0) + break; + + if (!inter) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unrecognised interface %s"), args[1]); + + if (!inter->dhcp_ack) + return grub_error (GRUB_ERR_IO, N_("no DHCP info found")); + + if (inter->dhcp_acklen <= OFFSET_OF (vendor, inter->dhcp_ack)) + return grub_error (GRUB_ERR_IO, N_("no DHCP options found")); + + num = grub_strtoul (args[2], 0, 0); + if (grub_errno) + return grub_errno; + + ptr = inter->dhcp_ack->vendor; + + if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0 + || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1 + || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2 + || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3) + return grub_error (GRUB_ERR_IO, N_("no DHCP options found")); + ptr = ptr + sizeof (grub_uint32_t); + while (1) + { + grub_uint8_t tagtype; + + if (ptr >= ((grub_uint8_t *) inter->dhcp_ack) + inter->dhcp_acklen) + return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num); + + tagtype = *ptr++; + + /* Pad tag. */ + if (tagtype == 0) + continue; + + /* End tag. */ + if (tagtype == 0xff) + return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num); + + taglength = *ptr++; + + if (tagtype == num) + break; + ptr += taglength; + } + + if (grub_strcmp (args[3], "string") == 0) + { + char *val = grub_malloc (taglength + 1); + if (!val) + return grub_errno; + grub_memcpy (val, ptr, taglength); + val[taglength] = 0; + if (args[0][0] == '-' && args[0][1] == 0) + grub_printf ("%s\n", val); + else + return grub_env_set (args[0], val); + return GRUB_ERR_NONE; + } + + if (grub_strcmp (args[3], "number") == 0) + { + grub_uint64_t val = 0; + int i; + for (i = 0; i < taglength; i++) + val = (val << 8) | ptr[i]; + if (args[0][0] == '-' && args[0][1] == 0) + grub_printf ("%llu\n", (unsigned long long) val); + else + { + char valn[64]; + grub_printf (valn, sizeof (valn), "%lld\n", (unsigned long long) val); + return grub_env_set (args[0], valn); + } + return GRUB_ERR_NONE; + } + + if (grub_strcmp (args[3], "hex") == 0) + { + char *val = grub_malloc (2 * taglength + 1); + int i; + if (!val) + return grub_errno; + for (i = 0; i < taglength; i++) + { + val[2 * i] = hexdigit (ptr[i] >> 4); + val[2 * i + 1] = hexdigit (ptr[i] & 0xf); + } + val[2 * taglength] = 0; + if (args[0][0] == '-' && args[0][1] == 0) + grub_printf ("%s\n", val); + else + return grub_env_set (args[0], val); + return GRUB_ERR_NONE; + } + + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "unrecognised format specification %s", args[3]); +} + +/* FIXME: allow to specify mac address. */ +static grub_err_t +grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_card *card; + struct grub_net_network_level_interface *ifaces; + grub_size_t ncards = 0; + unsigned j = 0; + int interval; + grub_err_t err; + + FOR_NET_CARDS (card) + { + if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) + continue; + ncards++; + } + + ifaces = grub_zalloc (ncards * sizeof (ifaces[0])); + if (!ifaces) + return grub_errno; + + j = 0; + FOR_NET_CARDS (card) + { + if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) + continue; + ifaces[j].card = card; + ifaces[j].next = &ifaces[j+1]; + if (j) + ifaces[j].prev = &ifaces[j-1].next; + ifaces[j].name = grub_xasprintf ("%s:dhcp_tmp", card->name); + card->num_ifaces++; + if (!ifaces[j].name) + { + unsigned i; + for (i = 0; i < j; i++) + grub_free (ifaces[i].name); + grub_free (ifaces); + return grub_errno; + } + ifaces[j].address.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV; + grub_memcpy (&ifaces[j].hwaddress, &card->default_address, + sizeof (ifaces[j].hwaddress)); + j++; + } + ifaces[ncards - 1].next = grub_net_network_level_interfaces; + if (grub_net_network_level_interfaces) + grub_net_network_level_interfaces->prev = & ifaces[ncards - 1].next; + grub_net_network_level_interfaces = &ifaces[0]; + ifaces[0].prev = &grub_net_network_level_interfaces; + for (interval = 200; interval < 10000; interval *= 2) + { + int done = 0; + for (j = 0; j < ncards; j++) + { + struct grub_net_bootp_packet *pack; + struct grub_datetime date; + grub_int32_t t; + struct grub_net_buff *nb; + struct udphdr *udph; + grub_net_network_level_address_t target; + grub_net_link_level_address_t ll_target; + + if (!ifaces[j].prev) + continue; + nb = grub_netbuff_alloc (sizeof (*pack)); + if (!nb) + { + grub_netbuff_free (nb); + return grub_errno; + } + err = grub_netbuff_reserve (nb, sizeof (*pack) + 64 + 128); + if (err) + { + grub_netbuff_free (nb); + return err; + } + err = grub_netbuff_push (nb, sizeof (*pack) + 64); + if (err) + { + grub_netbuff_free (nb); + return err; + } + pack = (void *) nb->data; + done = 1; + grub_memset (pack, 0, sizeof (*pack) + 64); + pack->opcode = 1; + pack->hw_type = 1; + pack->hw_len = 6; + err = grub_get_datetime (&date); + if (err || !grub_datetime2unixtime (&date, &t)) + { + grub_errno = GRUB_ERR_NONE; + t = 0; + } + pack->ident = grub_cpu_to_be32 (t); + pack->seconds = grub_cpu_to_be16 (t); + + grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6); + + grub_netbuff_push (nb, sizeof (*udph)); + + udph = (struct udphdr *) nb->data; + udph->src = grub_cpu_to_be16 (68); + udph->dst = grub_cpu_to_be16 (67); + udph->chksum = 0; + udph->len = grub_cpu_to_be16 (nb->tail - nb->data); + target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + target.ipv4 = 0xffffffff; + err = grub_net_link_layer_resolve (&ifaces[j], &target, &ll_target); + if (err) + return err; + + udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, + &ifaces[j].address, + &target); + + err = grub_net_send_ip_packet (&ifaces[j], &target, &ll_target, nb, + GRUB_NET_IP_UDP); + grub_netbuff_free (nb); + if (err) + return err; + } + if (!done) + break; + grub_net_poll_cards (interval); + } + + err = GRUB_ERR_NONE; + for (j = 0; j < ncards; j++) + { + grub_free (ifaces[j].name); + if (!ifaces[j].prev) + continue; + grub_error_push (); + grub_net_network_level_interface_unregister (&ifaces[j]); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s", + ifaces[j].card->name); + } + + grub_free (ifaces); + return err; +} + +static grub_command_t cmd_getdhcp, cmd_bootp; + +void +grub_bootp_init (void) +{ + cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp, + N_("[CARD]"), + N_("perform a bootp autoconfiguration")); + cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, + N_("VAR INTERFACE NUMBER DESCRIPTION"), + N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); +} + +void +grub_bootp_fini (void) +{ + grub_unregister_command (cmd_getdhcp); + grub_unregister_command (cmd_bootp); +} diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c new file mode 100644 index 000000000..bad2745a7 --- /dev/null +++ b/grub-core/net/dns.c @@ -0,0 +1,695 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct dns_cache_element +{ + char *name; + grub_size_t naddresses; + struct grub_net_network_level_address *addresses; + grub_uint64_t limit_time; +}; + +#define DNS_CACHE_SIZE 1021 +#define DNS_HASH_BASE 423 + +static struct dns_cache_element dns_cache[DNS_CACHE_SIZE]; +static struct grub_net_network_level_address *dns_servers; +static grub_size_t dns_nservers, dns_servers_alloc; + +grub_err_t +grub_net_add_dns_server (const struct grub_net_network_level_address *s) +{ + if (dns_servers_alloc <= dns_nservers) + { + int na = dns_servers_alloc * 2; + struct grub_net_network_level_address *ns; + if (na < 8) + na = 8; + ns = grub_malloc (na * sizeof (ns[0])); + if (!ns) + return grub_errno; + dns_servers_alloc = na; + dns_servers = ns; + } + dns_servers[dns_nservers++] = *s; + return GRUB_ERR_NONE; +} + +void +grub_net_remove_dns_server (const struct grub_net_network_level_address *s) +{ + grub_size_t i; + for (i = 0; i < dns_nservers; i++) + if (grub_net_addr_cmp (s, &dns_servers[i]) == 0) + break; + if (i < dns_nservers) + { + dns_servers[i] = dns_servers[dns_nservers - 1]; + dns_nservers--; + } +} + +struct dns_header +{ + grub_uint16_t id; + grub_uint8_t flags; + grub_uint8_t ra_z_r_code; + grub_uint16_t qdcount; + grub_uint16_t ancount; + grub_uint16_t nscount; + grub_uint16_t arcount; +} __attribute__ ((packed)); + +enum + { + FLAGS_RESPONSE = 0x80, + FLAGS_OPCODE = 0x78, + FLAGS_RD = 0x01 + }; + +enum + { + ERRCODE_MASK = 0x0f + }; + +enum + { + DNS_PORT = 53 + }; + +struct recv_data +{ + grub_size_t *naddresses; + struct grub_net_network_level_address **addresses; + int cache; + grub_uint16_t id; + int dns_err; + char *name; + const char *oname; +}; + +static inline int +hash (const char *str) +{ + int v = 0, xn = 1; + const char *ptr; + for (ptr = str; *ptr; ) + { + v = (v + xn * *ptr); + xn = (DNS_HASH_BASE * xn) % DNS_CACHE_SIZE; + ptr++; + if (((ptr - str) & 0x3ff) == 0) + v %= DNS_CACHE_SIZE; + } + return v % DNS_CACHE_SIZE; +} + +static int +check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + const grub_uint8_t *tail, const char *check_with, + int *length, char *set) +{ + const char *readable_ptr = check_with; + const grub_uint8_t *ptr; + char *optr = set; + int bytes_processed = 0; + if (length) + *length = 0; + for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) + { + /* End marker. */ + if (!*ptr) + { + if (length && *length) + (*length)--; + if (optr && optr != set) + optr--; + if (optr) + *optr = 0; + return !readable_ptr || (*readable_ptr == 0); + } + if (*ptr & 0xc0) + { + bytes_processed += 2; + if (ptr + 1 >= tail) + return 0; + ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); + continue; + } + if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) + return 0; + if (grub_memchr (ptr + 1, 0, *ptr) + || grub_memchr (ptr + 1, '.', *ptr)) + return 0; + if (readable_ptr) + readable_ptr += *ptr; + if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) + return 0; + bytes_processed += *ptr + 1; + if (length) + *length += *ptr + 1; + if (optr) + { + grub_memcpy (optr, ptr + 1, *ptr); + optr += *ptr; + } + if (optr) + *optr++ = '.'; + if (readable_ptr && *readable_ptr) + readable_ptr++; + ptr += *ptr + 1; + } + return 0; +} + +static int +check_name (const grub_uint8_t *name_at, const grub_uint8_t *head, + const grub_uint8_t *tail, const char *check_with) +{ + return check_name_real (name_at, head, tail, check_with, NULL, NULL); +} + +static char * +get_name (const grub_uint8_t *name_at, const grub_uint8_t *head, + const grub_uint8_t *tail) +{ + int length; + char *ret; + + if (!check_name_real (name_at, head, tail, NULL, &length, NULL)) + return NULL; + ret = grub_malloc (length + 1); + if (!ret) + return NULL; + if (!check_name_real (name_at, head, tail, NULL, NULL, ret)) + { + grub_free (ret); + return NULL; + } + return ret; +} + +enum + { + DNS_CLASS_A = 1, + DNS_CLASS_CNAME = 5, + DNS_CLASS_AAAA = 28 + }; + +static grub_err_t +recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)), + struct grub_net_buff *nb, + void *data_) +{ + struct dns_header *head; + struct recv_data *data = data_; + int i, j; + grub_uint8_t *ptr, *reparse_ptr; + int redirect_cnt = 0; + char *redirect_save = NULL; + grub_uint32_t ttl_all = ~0U; + + head = (struct dns_header *) nb->data; + ptr = (grub_uint8_t *) (head + 1); + if (ptr >= nb->tail) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + if (head->id != data->id) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (!(head->flags & FLAGS_RESPONSE) || (head->flags & FLAGS_OPCODE)) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (head->ra_z_r_code & ERRCODE_MASK) + { + data->dns_err = 1; + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + for (i = 0; i < grub_cpu_to_be16 (head->qdcount); i++) + { + if (ptr >= nb->tail) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0)) + ptr += *ptr + 1; + if (ptr < nb->tail && (*ptr & 0xc0)) + ptr++; + ptr++; + ptr += 4; + } + *data->addresses = grub_malloc (sizeof ((*data->addresses)[0]) + * grub_cpu_to_be16 (head->ancount)); + if (!*data->addresses) + { + grub_errno = GRUB_ERR_NONE; + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + reparse_ptr = ptr; + reparse: + for (i = 0, ptr = reparse_ptr; i < grub_cpu_to_be16 (head->ancount); i++) + { + int ignored = 0; + grub_uint8_t class; + grub_uint32_t ttl = 0; + grub_uint16_t length; + if (ptr >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + return GRUB_ERR_NONE; + } + ignored = !check_name (ptr, nb->data, nb->tail, data->name); + while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0)) + ptr += *ptr + 1; + if (ptr < nb->tail && (*ptr & 0xc0)) + ptr++; + ptr++; + if (ptr + 10 >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (*ptr++ != 0) + ignored = 1; + class = *ptr++; + if (*ptr++ != 0) + ignored = 1; + if (*ptr++ != 1) + ignored = 1; + for (j = 0; j < 4; j++) + { + ttl <<= 8; + ttl |= *ptr++; + } + length = *ptr++ << 8; + length |= *ptr++; + if (ptr + length > nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (!ignored) + { + if (ttl_all > ttl) + ttl_all = ttl; + switch (class) + { + case DNS_CLASS_A: + if (length != 4) + break; + (*data->addresses)[*data->naddresses].type + = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4, + ptr, 4); + (*data->naddresses)++; + break; + case DNS_CLASS_AAAA: + if (length != 16) + break; + (*data->addresses)[*data->naddresses].type + = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6, + ptr, 16); + (*data->naddresses)++; + break; + case DNS_CLASS_CNAME: + if (!(redirect_cnt & (redirect_cnt - 1))) + { + grub_free (redirect_save); + redirect_save = data->name; + } + else + grub_free (data->name); + redirect_cnt++; + data->name = get_name (ptr, nb->data, nb->tail); + if (!data->name) + { + data->dns_err = 1; + grub_errno = 0; + return GRUB_ERR_NONE; + } + grub_dprintf ("dns", "CNAME %s\n", data->name); + if (grub_strcmp (redirect_save, data->name) == 0) + { + data->dns_err = 1; + grub_free (redirect_save); + return GRUB_ERR_NONE; + } + goto reparse; + } + } + ptr += length; + } + if (ttl_all && *data->naddresses && data->cache) + { + int h; + grub_dprintf ("dns", "caching for %d seconds\n", ttl_all); + h = hash (data->oname); + grub_free (dns_cache[h].name); + dns_cache[h].name = 0; + grub_free (dns_cache[h].addresses); + dns_cache[h].addresses = 0; + dns_cache[h].name = grub_strdup (data->oname); + dns_cache[h].naddresses = *data->naddresses; + dns_cache[h].addresses = grub_malloc (*data->naddresses + * sizeof (dns_cache[h].addresses[0])); + dns_cache[h].limit_time = grub_get_time_ms () + 1000 * ttl_all; + if (!dns_cache[h].addresses || !dns_cache[h].name) + { + grub_free (dns_cache[h].name); + dns_cache[h].name = 0; + grub_free (dns_cache[h].addresses); + dns_cache[h].addresses = 0; + } + grub_memcpy (dns_cache[h].addresses, *data->addresses, + *data->naddresses + * sizeof (dns_cache[h].addresses[0])); + } + grub_netbuff_free (nb); + grub_free (redirect_save); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_net_dns_lookup (const char *name, + const struct grub_net_network_level_address *servers, + grub_size_t n_servers, + grub_size_t *naddresses, + struct grub_net_network_level_address **addresses, + int cache) +{ + grub_size_t send_servers = 0; + grub_size_t i, j; + struct grub_net_buff *nb; + grub_net_udp_socket_t sockets[n_servers]; + grub_uint8_t *optr; + const char *iptr; + struct dns_header *head; + static grub_uint16_t id = 1; + grub_err_t err = GRUB_ERR_NONE; + struct recv_data data = {naddresses, addresses, cache, + grub_cpu_to_be16 (id++), 0, 0, name}; + grub_uint8_t *nbd; + int have_server = 0; + + if (!servers) + { + servers = dns_servers; + n_servers = dns_nservers; + } + + if (!n_servers) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no DNS servers"); + + *naddresses = 0; + if (cache) + { + int h; + h = hash (name); + if (dns_cache[h].name && grub_strcmp (dns_cache[h].name, name) == 0 + && grub_get_time_ms () < dns_cache[h].limit_time) + { + grub_dprintf ("dns", "retrieved from cache\n"); + *addresses = grub_malloc (dns_cache[h].naddresses + * sizeof ((*addresses)[0])); + if (!*addresses) + return grub_errno; + *naddresses = dns_cache[h].naddresses; + grub_memcpy (*addresses, dns_cache[h].addresses, + dns_cache[h].naddresses + * sizeof ((*addresses)[0])); + return GRUB_ERR_NONE; + } + } + + data.name = grub_strdup (name); + if (!data.name) + return grub_errno; + + nb = grub_netbuff_alloc (GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE + + GRUB_NET_UDP_HEADER_SIZE + + sizeof (struct dns_header) + + grub_strlen (name) + 2 + 4 + + 2 + 4); + if (!nb) + { + grub_free (data.name); + return grub_errno; + } + grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE + + GRUB_NET_UDP_HEADER_SIZE); + grub_netbuff_put (nb, sizeof (struct dns_header) + + grub_strlen (name) + 2 + 4 + 2 + 4); + head = (struct dns_header *) nb->data; + optr = (grub_uint8_t *) (head + 1); + for (iptr = name; *iptr; ) + { + const char *dot; + dot = grub_strchr (iptr, '.'); + if (!dot) + dot = iptr + grub_strlen (iptr); + if ((dot - iptr) >= 64) + { + grub_free (data.name); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "domain component is too long"); + } + *optr = (dot - iptr); + optr++; + grub_memcpy (optr, iptr, dot - iptr); + optr += dot - iptr; + iptr = dot; + if (*iptr) + iptr++; + } + *optr++ = 0; + + /* Type: A. */ + *optr++ = 0; + *optr++ = 1; + + /* Class. */ + *optr++ = 0; + *optr++ = 1; + + /* Compressed name. */ + *optr++ = 0xc0; + *optr++ = 0x0c; + /* Type: AAAA. */ + *optr++ = 0; + *optr++ = 28; + + /* Class. */ + *optr++ = 0; + *optr++ = 1; + + head->id = data.id; + head->flags = FLAGS_RD; + head->ra_z_r_code = 0; + head->qdcount = grub_cpu_to_be16_compile_time (2); + head->ancount = grub_cpu_to_be16_compile_time (0); + head->nscount = grub_cpu_to_be16_compile_time (0); + head->arcount = grub_cpu_to_be16_compile_time (0); + + nbd = nb->data; + + for (i = 0; i < n_servers * 4; i++) + { + /* Connect to a next server. */ + while (!(i & 1) && send_servers < n_servers) + { + sockets[send_servers] = grub_net_udp_open (servers[send_servers], + DNS_PORT, + recv_hook, + &data); + send_servers++; + if (!sockets[send_servers - 1]) + { + err = grub_errno; + grub_errno = GRUB_ERR_NONE; + } + else + { + have_server = 1; + break; + } + } + if (!have_server) + goto out; + if (*data.naddresses) + goto out; + for (j = 0; j < send_servers; j++) + { + grub_err_t err2; + if (!sockets[j]) + continue; + nb->data = nbd; + err2 = grub_net_send_udp_packet (sockets[j], nb); + if (err2) + { + grub_errno = GRUB_ERR_NONE; + err = err2; + } + if (*data.naddresses) + goto out; + } + grub_net_poll_cards (200); + } + out: + grub_free (data.name); + grub_netbuff_free (nb); + for (j = 0; j < send_servers; j++) + grub_net_udp_close (sockets[j]); + + if (*data.naddresses) + return GRUB_ERR_NONE; + if (data.dns_err) + return grub_error (GRUB_ERR_NET_NO_DOMAIN, "no DNS domain found"); + + if (err) + { + grub_errno = err; + return err; + } + return grub_error (GRUB_ERR_TIMEOUT, "no DNS reply received"); +} + +static grub_err_t +grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + struct grub_net_network_level_address server; + grub_size_t naddresses, i; + struct grub_net_network_level_address *addresses; + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected"); + err = grub_net_resolve_address (args[1], &server); + if (err) + return err; + + err = grub_net_dns_lookup (args[0], &server, 1, &naddresses, &addresses, 0); + if (err) + return err; + for (i = 0; i < naddresses; i++) + { + char buf[GRUB_NET_MAX_STR_ADDR_LEN]; + grub_net_addr_to_str (&addresses[i], buf); + grub_printf ("%s\n", buf); + } + grub_free (addresses); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_list_dns (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_size_t i; + for (i = 0; i < dns_nservers; i++) + { + char buf[GRUB_NET_MAX_STR_ADDR_LEN]; + grub_net_addr_to_str (&dns_servers[i], buf); + grub_printf ("%s\n", buf); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_add_dns (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + struct grub_net_network_level_address server; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "1 argument expected"); + err = grub_net_resolve_address (args[0], &server); + if (err) + return err; + + return grub_net_add_dns_server (&server); +} + +static grub_err_t +grub_cmd_del_dns (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + struct grub_net_network_level_address server; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "1 argument expected"); + err = grub_net_resolve_address (args[1], &server); + if (err) + return err; + + return grub_net_add_dns_server (&server); +} + +static grub_command_t cmd, cmd_add, cmd_del, cmd_list; + +void +grub_dns_init (void) +{ + cmd = grub_register_command ("net_nslookup", grub_cmd_nslookup, + "ADDRESS DNSSERVER", + N_("Perform a DNS lookup")); + cmd_add = grub_register_command ("net_add_dns", grub_cmd_add_dns, + "DNSSERVER", + N_("Add a DNS server")); + cmd_del = grub_register_command ("net_del_dns", grub_cmd_del_dns, + "DNSSERVER", + N_("Remove a DNS server")); + cmd_list = grub_register_command ("net_ls_dns", grub_cmd_list_dns, + NULL, N_("List DNS servers")); +} + +void +grub_dns_fini (void) +{ + grub_unregister_command (cmd); + grub_unregister_command (cmd_add); + grub_unregister_command (cmd_del); + grub_unregister_command (cmd_list); +} diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c new file mode 100644 index 000000000..2a392bc98 --- /dev/null +++ b/grub-core/net/drivers/efi/efinet.c @@ -0,0 +1,235 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* GUID. */ +static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; +static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; + +static grub_err_t +send_card_buffer (const struct grub_net_card *dev, + struct grub_net_buff *pack) +{ + grub_efi_status_t st; + grub_efi_simple_network_t *net = dev->efi_net; + grub_uint64_t limit_time = grub_get_time_ms () + 4000; + st = efi_call_7 (net->transmit, net, 0, (pack->tail - pack->data), + pack->data, NULL, NULL, NULL); + if (st != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_IO, "couldn't send network packet"); + while (1) + { + void *txbuf = NULL; + st = efi_call_3 (net->get_status, net, 0, &txbuf); + if (st != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_IO, "couldn't send network packet"); + if (txbuf) + return GRUB_ERR_NONE; + if (limit_time < grub_get_time_ms ()) + return grub_error (GRUB_ERR_TIMEOUT, "couldn't send network packet"); + } +} + +static struct grub_net_buff * +get_card_packet (const struct grub_net_card *dev) +{ + grub_efi_simple_network_t *net = dev->efi_net; + grub_err_t err; + grub_efi_status_t st; + grub_efi_uintn_t bufsize = 1536; + struct grub_net_buff *nb; + + nb = grub_netbuff_alloc (bufsize); + if (!nb) + return NULL; + + /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible + by 4. So that IP header is aligned on 4 bytes. */ + grub_netbuff_reserve (nb, 2); + if (!nb) + { + grub_netbuff_free (nb); + return NULL; + } + + st = efi_call_7 (net->receive, net, NULL, &bufsize, + nb->data, NULL, NULL, NULL); + if (st == GRUB_EFI_BUFFER_TOO_SMALL) + { + grub_netbuff_free (nb); + + bufsize = ALIGN_UP (bufsize, 32); + + nb = grub_netbuff_alloc (bufsize); + if (!nb) + return NULL; + + /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible + by 4. So that IP header is aligned on 4 bytes. */ + grub_netbuff_reserve (nb, 2); + if (!nb) + { + grub_netbuff_free (nb); + return NULL; + } + + st = efi_call_7 (net->receive, net, NULL, &bufsize, + nb->data, NULL, NULL, NULL); + } + if (st != GRUB_EFI_SUCCESS) + { + grub_netbuff_free (nb); + return NULL; + } + err = grub_netbuff_put (nb, bufsize); + if (err) + { + grub_netbuff_free (nb); + return NULL; + } + + return nb; +} + +static struct grub_net_card_driver efidriver = + { + .name = "efinet", + .send = send_card_buffer, + .recv = get_card_packet + }; + + +static void +grub_efinet_findcards (void) +{ + grub_efi_uintn_t num_handles; + grub_efi_handle_t *handles; + grub_efi_handle_t *handle; + int i = 0; + + /* Find handles which support the disk io interface. */ + handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &net_io_guid, + 0, &num_handles); + if (! handles) + return; + for (handle = handles; num_handles--; handle++) + { + grub_efi_simple_network_t *net; + struct grub_net_card *card; + + net = grub_efi_open_protocol (*handle, &net_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (! net) + /* This should not happen... Why? */ + continue; + + if (net->mode->state == GRUB_EFI_NETWORK_STOPPED + && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS) + continue; + + if (net->mode->state == GRUB_EFI_NETWORK_STOPPED) + continue; + + if (net->mode->state == GRUB_EFI_NETWORK_STARTED + && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS) + continue; + + card = grub_zalloc (sizeof (struct grub_net_card)); + if (!card) + { + grub_print_error (); + grub_free (handles); + return; + } + + card->name = grub_xasprintf ("efinet%d", i++); + card->driver = &efidriver; + card->flags = 0; + card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + card->mtu = net->mode->max_packet_size; + grub_memcpy (card->default_address.mac, + net->mode->current_address, + sizeof (card->default_address.mac)); + card->efi_net = net; + card->efi_handle = *handle; + + grub_net_card_register (card); + } + grub_free (handles); +} + +static void +grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) +{ + struct grub_net_card *card; + grub_efi_device_path_t *dp; + + dp = grub_efi_get_device_path (hnd); + if (! dp) + return; + + FOR_NET_CARDS (card) + { + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; + struct grub_efi_pxe_mode *pxe_mode; + if (card->driver != &efidriver) + continue; + cdp = grub_efi_get_device_path (card->efi_handle); + if (! cdp) + continue; + if (grub_efi_compare_device_paths (dp, cdp) != 0) + continue; + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (! pxe) + continue; + pxe_mode = pxe->mode; + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) + &pxe_mode->dhcp_ack, + sizeof (pxe_mode->dhcp_ack), + 1, device, path); + return; + } +} + +GRUB_MOD_INIT(efinet) +{ + grub_efinet_findcards (); + grub_efi_net_config = grub_efi_net_config_real; +} + +GRUB_MOD_FINI(efinet) +{ + struct grub_net_card *card, *next; + + FOR_NET_CARDS_SAFE (card, next) + if (card->driver == &efidriver) + grub_net_card_unregister (card); +} + diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c new file mode 100644 index 000000000..2aba28d23 --- /dev/null +++ b/grub-core/net/drivers/emu/emunet.c @@ -0,0 +1,121 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int fd; + +static grub_err_t +send_card_buffer (const struct grub_net_card *dev __attribute__ ((unused)), + struct grub_net_buff *pack) +{ + ssize_t actual; + + actual = write (fd, pack->data, pack->tail - pack->data); + if (actual < 0) + return grub_error (GRUB_ERR_IO, "couldn't send packets"); + + return GRUB_ERR_NONE; +} + +static struct grub_net_buff * +get_card_packet (const struct grub_net_card *dev __attribute__ ((unused))) +{ + ssize_t actual; + struct grub_net_buff *nb; + + nb = grub_netbuff_alloc (1536); + if (!nb) + return NULL; + + /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible + by 4. So that IP header is aligned on 4 bytes. */ + grub_netbuff_reserve (nb, 2); + if (!nb) + { + grub_netbuff_free (nb); + return NULL; + } + + actual = read (fd, nb->data, 1536); + if (actual < 0) + { + grub_netbuff_free (nb); + return NULL; + } + grub_netbuff_put (nb, actual); + + return nb; +} + +static struct grub_net_card_driver emudriver = + { + .name = "emu", + .send = send_card_buffer, + .recv = get_card_packet + }; + +static struct grub_net_card emucard = + { + .name = "emu0", + .driver = &emudriver, + .mtu = 1500, + .default_address = { + .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET, + {.mac = {0, 1, 2, 3, 4, 5}} + }, + .flags = 0 + }; + +GRUB_MOD_INIT(emunet) +{ + struct ifreq ifr; + fd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK); + if (fd < 0) + return; + grub_memset (&ifr, 0, sizeof (ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + if (ioctl (fd, TUNSETIFF, &ifr) < 0) + { + close (fd); + fd = -1; + return; + } + grub_net_card_register (&emucard); +} + +GRUB_MOD_FINI(emunet) +{ + if (fd >= 0) + { + close (fd); + grub_net_card_unregister (&emucard); + } +} diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c new file mode 100644 index 000000000..34e43f585 --- /dev/null +++ b/grub-core/net/drivers/i386/pc/pxe.c @@ -0,0 +1,374 @@ +/* pxe.c - Driver to provide access to the pxe filesystem */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define SEGMENT(x) ((x) >> 4) +#define OFFSET(x) ((x) & 0xF) +#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x)) +#define LINEAR(x) (void *) ((((x) >> 16) << 4) + ((x) & 0xFFFF)) + +struct grub_pxe_undi_open +{ + grub_uint16_t status; + grub_uint16_t open_flag; + grub_uint16_t pkt_filter; + grub_uint16_t mcast_count; + grub_uint8_t mcast[8][6]; +} __attribute__ ((packed)); + +struct grub_pxe_undi_info +{ + grub_uint16_t status; + grub_uint16_t base_io; + grub_uint16_t int_number; + grub_uint16_t mtu; + grub_uint16_t hwtype; + grub_uint16_t hwaddrlen; + grub_uint8_t current_addr[16]; + grub_uint8_t permanent_addr[16]; + grub_uint32_t romaddr; + grub_uint16_t rxbufct; + grub_uint16_t txbufct; +} __attribute__ ((packed)); + + +struct grub_pxe_undi_isr +{ + grub_uint16_t status; + grub_uint16_t func_flag; + grub_uint16_t buffer_len; + grub_uint16_t frame_len; + grub_uint16_t frame_hdr_len; + grub_uint32_t buffer; + grub_uint8_t prot_type; + grub_uint8_t pkt_type; +} __attribute__ ((packed)); + +enum + { + GRUB_PXE_ISR_IN_START = 1, + GRUB_PXE_ISR_IN_PROCESS, + GRUB_PXE_ISR_IN_GET_NEXT + }; + +enum + { + GRUB_PXE_ISR_OUT_OURS = 0, + GRUB_PXE_ISR_OUT_NOT_OURS = 1 + }; + +enum + { + GRUB_PXE_ISR_OUT_DONE = 0, + GRUB_PXE_ISR_OUT_TRANSMIT = 2, + GRUB_PXE_ISR_OUT_RECEIVE = 3, + GRUB_PXE_ISR_OUT_BUSY = 4, + }; + +struct grub_pxe_undi_transmit +{ + grub_uint16_t status; + grub_uint8_t protocol; + grub_uint8_t xmitflag; + grub_uint32_t dest; + grub_uint32_t tbd; + grub_uint32_t reserved[2]; +} __attribute__ ((packed)); + +struct grub_pxe_undi_tbd +{ + grub_uint16_t len; + grub_uint32_t buf; + grub_uint16_t blk_count; + struct + { + grub_uint8_t ptr_type; + grub_uint8_t reserved; + grub_uint16_t len; + grub_uint32_t ptr; + } blocks[8]; +} __attribute__ ((packed)); + +struct grub_pxe_bangpxe *grub_pxe_pxenv; +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 struct grub_net_buff * +grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused))) +{ + struct grub_pxe_undi_isr *isr; + static int in_progress = 0; + grub_uint8_t *ptr, *end; + struct grub_net_buff *buf; + + isr = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + if (!in_progress) + { + grub_memset (isr, 0, sizeof (*isr)); + isr->func_flag = GRUB_PXE_ISR_IN_START; + grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry); + /* Normally according to the specification we should also check + that isr->func_flag != GRUB_PXE_ISR_OUT_OURS but unfortunately it + breaks on intel cards. + */ + if (isr->status) + { + in_progress = 0; + return NULL; + } + grub_memset (isr, 0, sizeof (*isr)); + isr->func_flag = GRUB_PXE_ISR_IN_PROCESS; + grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry); + } + else + { + grub_memset (isr, 0, sizeof (*isr)); + isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT; + grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry); + } + + while (isr->func_flag != GRUB_PXE_ISR_OUT_RECEIVE) + { + if (isr->status || isr->func_flag == GRUB_PXE_ISR_OUT_DONE) + { + in_progress = 0; + return NULL; + } + grub_memset (isr, 0, sizeof (*isr)); + isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT; + grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry); + } + + buf = grub_netbuff_alloc (isr->frame_len); + if (!buf) + return NULL; + /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible + by 4. So that IP header is aligned on 4 bytes. */ + grub_netbuff_reserve (buf, 2); + if (!buf) + { + grub_netbuff_free (buf); + return NULL; + } + ptr = buf->data; + end = ptr + isr->frame_len; + grub_netbuff_put (buf, isr->frame_len); + grub_memcpy (ptr, LINEAR (isr->buffer), isr->buffer_len); + ptr += isr->buffer_len; + while (ptr < end) + { + grub_memset (isr, 0, sizeof (*isr)); + isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT; + grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry); + if (isr->status || isr->func_flag != GRUB_PXE_ISR_OUT_RECEIVE) + { + in_progress = 1; + grub_netbuff_free (buf); + return NULL; + } + + grub_memcpy (ptr, LINEAR (isr->buffer), isr->buffer_len); + ptr += isr->buffer_len; + } + in_progress = 1; + + return buf; +} + +static grub_err_t +grub_pxe_send (const struct grub_net_card *dev __attribute__ ((unused)), + struct grub_net_buff *pack) +{ + struct grub_pxe_undi_transmit *trans; + struct grub_pxe_undi_tbd *tbd; + char *buf; + + trans = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_memset (trans, 0, sizeof (*trans)); + tbd = (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 128); + grub_memset (tbd, 0, sizeof (*tbd)); + buf = (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + 256); + grub_memcpy (buf, pack->data, pack->tail - pack->data); + + trans->tbd = SEGOFS ((grub_addr_t) tbd); + trans->protocol = 0; + tbd->len = pack->tail - pack->data; + tbd->buf = SEGOFS ((grub_addr_t) buf); + + grub_pxe_call (GRUB_PXENV_UNDI_TRANSMIT, trans, pxe_rm_entry); + if (trans->status) + return grub_error (GRUB_ERR_IO, "PXE send failed (status 0x%x)", + trans->status); + return 0; +} + +static void +grub_pxe_close (const struct grub_net_card *dev __attribute__ ((unused))) +{ + if (pxe_rm_entry) + grub_pxe_call (GRUB_PXENV_UNDI_CLOSE, + (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, + pxe_rm_entry); +} + +static grub_err_t +grub_pxe_open (const struct grub_net_card *dev __attribute__ ((unused))) +{ + struct grub_pxe_undi_open *ou; + ou = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_memset (ou, 0, sizeof (*ou)); + ou->pkt_filter = 4; + grub_pxe_call (GRUB_PXENV_UNDI_OPEN, ou, pxe_rm_entry); + + if (ou->status) + return grub_error (GRUB_ERR_IO, "can't open UNDI"); + return GRUB_ERR_NONE; +} + +struct grub_net_card_driver grub_pxe_card_driver = +{ + .open = grub_pxe_open, + .close = grub_pxe_close, + .send = grub_pxe_send, + .recv = grub_pxe_recv +}; + +struct grub_net_card grub_pxe_card = +{ + .driver = &grub_pxe_card_driver, + .name = "pxe" +}; + +static void +grub_pc_net_config_real (char **device, char **path) +{ + struct grub_net_bootp_packet *bp; + struct grub_pxenv_get_cached_info ci; + 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, pxe_rm_entry); + if (ci.status) + return; + + bp = LINEAR (ci.buffer); + + grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card, 0, + bp, GRUB_PXE_BOOTP_SIZE, + 1, device, path); + +} + +GRUB_MOD_INIT(pxe) +{ + struct grub_pxe_bangpxe *pxenv; + struct grub_pxe_undi_info *ui; + unsigned i; + + pxenv = grub_pxe_scan (); + if (! pxenv) + return; + + ui = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_memset (ui, 0, sizeof (*ui)); + grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry); + + grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr, + sizeof (grub_pxe_card.default_address.mac)); + for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) + if (grub_pxe_card.default_address.mac[i] != 0) + break; + if (i != sizeof (grub_pxe_card.default_address.mac)) + { + for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) + if (grub_pxe_card.default_address.mac[i] != 0xff) + break; + } + if (i == sizeof (grub_pxe_card.default_address.mac)) + grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr, + sizeof (grub_pxe_card.default_address.mac)); + grub_pxe_card.mtu = ui->mtu; + + grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + + grub_net_card_register (&grub_pxe_card); + grub_pc_net_config = grub_pc_net_config_real; +} + +GRUB_MOD_FINI(pxe) +{ + grub_pc_net_config = 0; + grub_net_card_unregister (&grub_pxe_card); +} diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c new file mode 100644 index 000000000..227b88aa8 --- /dev/null +++ b/grub-core/net/drivers/ieee1275/ofnet.c @@ -0,0 +1,296 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_ofnetcard_data +{ + char *path; + grub_ieee1275_ihandle_t handle; +}; + +static grub_err_t +card_open (const struct grub_net_card *dev) +{ + int status; + struct grub_ofnetcard_data *data = dev->data; + char path[grub_strlen (data->path) + + grub_strlen (":speed=auto,duplex=auto,1.1.1.1,dummy,1.1.1.1,1.1.1.1,5,5,1.1.1.1,512") + 1]; + + /* The full string will prevent a bootp packet to be sent. Just put some valid ip in there. */ + grub_snprintf (path, sizeof (path), "%s%s", data->path, + ":speed=auto,duplex=auto,1.1.1.1,dummy,1.1.1.1,1.1.1.1,5,5,1.1.1.1,512"); + status = grub_ieee1275_open (path, &(data->handle)); + + if (status) + return grub_error (GRUB_ERR_IO, "Couldn't open network card."); + + return GRUB_ERR_NONE; +} + +static void +card_close (const struct grub_net_card *dev) +{ + struct grub_ofnetcard_data *data = dev->data; + + if (data->handle) + grub_ieee1275_close (data->handle); +} + +static grub_err_t +send_card_buffer (const struct grub_net_card *dev, struct grub_net_buff *pack) +{ + grub_ssize_t actual; + int status; + struct grub_ofnetcard_data *data = dev->data; + + status = grub_ieee1275_write (data->handle, pack->data, + pack->tail - pack->data, &actual); + + if (status) + return grub_error (GRUB_ERR_IO, "Couldn't send network packet."); + return GRUB_ERR_NONE; +} + +static struct grub_net_buff * +get_card_packet (const struct grub_net_card *dev) +{ + grub_ssize_t actual; + int rc; + struct grub_ofnetcard_data *data = dev->data; + grub_uint64_t start_time; + struct grub_net_buff *nb; + + nb = grub_netbuff_alloc (dev->mtu + 64); + /* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible + by 4. So that IP header is aligned on 4 bytes. */ + grub_netbuff_reserve (nb, 2); + if (!nb) + { + grub_netbuff_free (nb); + return NULL; + } + start_time = grub_get_time_ms (); + do + rc = grub_ieee1275_read (data->handle, nb->data, dev->mtu + 64, &actual); + while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200)); + if (actual) + { + grub_netbuff_put (nb, actual); + return nb; + } + grub_netbuff_free (nb); + return NULL; +} + +static struct grub_net_card_driver ofdriver = + { + .name = "ofnet", + .open = card_open, + .close = card_close, + .send = send_card_buffer, + .recv = get_card_packet + }; + +static const struct +{ + const char *name; + int offset; +} + +bootp_response_properties[] = + { + { .name = "bootp-response", .offset = 0}, + { .name = "dhcp-response", .offset = 0}, + { .name = "bootpreply-packet", .offset = 0x2a}, + }; + +static void +grub_ieee1275_net_config_real (const char *devpath, char **device, char **path) +{ + struct grub_net_card *card; + + /* FIXME: Check that it's the right card. */ + FOR_NET_CARDS (card) + { + char *bootp_response; + char *cardpath; + char *canon; + + grub_ssize_t size = -1; + unsigned int i; + + if (card->driver != &ofdriver) + continue; + + cardpath = ((struct grub_ofnetcard_data *) card->data)->path; + canon = grub_ieee1275_canonicalise_devname (cardpath); + if (grub_strcmp (devpath, canon) != 0) + { + grub_free (canon); + continue; + } + grub_free (canon); + + for (i = 0; i < ARRAY_SIZE (bootp_response_properties); i++) + if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, + bootp_response_properties[i].name, + &size) >= 0) + break; + + if (size < 0) + return; + + bootp_response = grub_malloc (size); + if (!bootp_response) + { + grub_print_error (); + return; + } + if (grub_ieee1275_get_property (grub_ieee1275_chosen, + bootp_response_properties[i].name, + bootp_response, size, 0) < 0) + return; + + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) + &bootp_response + + bootp_response_properties[i].offset, + size - bootp_response_properties[i].offset, + 1, device, path); + return; + } +} + +static char * +find_alias (const char *fullname) +{ + char *ret = NULL; + auto int find_alias_hook (struct grub_ieee1275_devalias *alias); + + int find_alias_hook (struct grub_ieee1275_devalias *alias) + { + if (grub_strcmp (alias->path, fullname) == 0) + { + ret = grub_strdup (alias->name); + return 1; + } + return 0; + } + + grub_devalias_iterate (find_alias_hook); + grub_errno = GRUB_ERR_NONE; + return ret; +} + +static void +grub_ofnet_findcards (void) +{ + auto int search_net_devices (struct grub_ieee1275_devalias *alias); + + int search_net_devices (struct grub_ieee1275_devalias *alias) + { + if (!grub_strcmp (alias->type, "network")) + { + struct grub_ofnetcard_data *ofdata; + struct grub_net_card *card; + grub_ieee1275_phandle_t devhandle; + grub_net_link_level_address_t lla; + char *shortname; + + ofdata = grub_malloc (sizeof (struct grub_ofnetcard_data)); + if (!ofdata) + { + grub_print_error (); + return 1; + } + card = grub_zalloc (sizeof (struct grub_net_card)); + if (!card) + { + grub_free (ofdata); + grub_print_error (); + return 1; + } + + ofdata->path = grub_strdup (alias->path); + + grub_ieee1275_finddevice (ofdata->path, &devhandle); + + { + grub_uint32_t t; + if (grub_ieee1275_get_integer_property (devhandle, + "max-frame-size", &t, + sizeof (t), 0)) + card->mtu = 1500; + else + card->mtu = t; + } + + if (grub_ieee1275_get_property (devhandle, "mac-address", + &(lla.mac), 6, 0) + && grub_ieee1275_get_property (devhandle, "local-mac-address", + &(lla.mac), 6, 0)) + { + grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address."); + grub_print_error (); + return 0; + } + + lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + card->default_address = lla; + + card->driver = NULL; + card->data = ofdata; + card->flags = 0; + shortname = find_alias (alias->path); + card->name = grub_xasprintf ("ofnet_%s", shortname ? : alias->path); + card->idle_poll_delay_ms = 1; + grub_free (shortname); + + card->driver = &ofdriver; + grub_net_card_register (card); + return 0; + } + return 0; + } + + /* Look at all nodes for devices of the type network. */ + grub_ieee1275_devices_iterate (search_net_devices); +} + +GRUB_MOD_INIT(ofnet) +{ + grub_ofnet_findcards (); + grub_ieee1275_net_config = grub_ieee1275_net_config_real; +} + +GRUB_MOD_FINI(ofnet) +{ + struct grub_net_card *card, *next; + + FOR_NET_CARDS_SAFE (card, next) + if (card->driver && grub_strcmp (card->driver->name, "ofnet") == 0) + grub_net_card_unregister (card); + grub_ieee1275_net_config = 0; +} diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c new file mode 100644 index 000000000..b38e2c83e --- /dev/null +++ b/grub-core/net/ethernet.c @@ -0,0 +1,134 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +#define LLCADDRMASK 0x7f + +struct etherhdr +{ + grub_uint8_t dst[6]; + grub_uint8_t src[6]; + grub_uint16_t type; +} __attribute__ ((packed)); + +struct llchdr +{ + grub_uint8_t dsap; + grub_uint8_t ssap; + grub_uint8_t ctrl; +} __attribute__ ((packed)); + +struct snaphdr +{ + grub_uint8_t oui[3]; + grub_uint16_t type; +} __attribute__ ((packed)); + +grub_err_t +send_ethernet_packet (struct grub_net_network_level_interface *inf, + struct grub_net_buff *nb, + grub_net_link_level_address_t target_addr, + grub_net_ethertype_t ethertype) +{ + struct etherhdr *eth; + grub_err_t err; + + COMPILE_TIME_ASSERT (sizeof (*eth) < GRUB_NET_MAX_LINK_HEADER_SIZE); + + err = grub_netbuff_push (nb, sizeof (*eth)); + if (err) + return err; + eth = (struct etherhdr *) nb->data; + grub_memcpy (eth->dst, target_addr.mac, 6); + grub_memcpy (eth->src, inf->hwaddress.mac, 6); + + eth->type = grub_cpu_to_be16 (ethertype); + if (!inf->card->opened) + { + err = GRUB_ERR_NONE; + if (inf->card->driver->open) + err = inf->card->driver->open (inf->card); + if (err) + return err; + inf->card->opened = 1; + } + return inf->card->driver->send (inf->card, nb); +} + +grub_err_t +grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + struct grub_net_card *card) +{ + struct etherhdr *eth; + struct llchdr *llch; + struct snaphdr *snaph; + grub_net_ethertype_t type; + grub_net_link_level_address_t hwaddress; + grub_net_link_level_address_t src_hwaddress; + grub_err_t err; + + eth = (struct etherhdr *) nb->data; + type = grub_be_to_cpu16 (eth->type); + err = grub_netbuff_pull (nb, sizeof (*eth)); + if (err) + return err; + + if (type <= 1500) + { + llch = (struct llchdr *) nb->data; + type = llch->dsap & LLCADDRMASK; + + if (llch->dsap == 0xaa && llch->ssap == 0xaa && llch->ctrl == 0x3) + { + err = grub_netbuff_pull (nb, sizeof (*llch)); + if (err) + return err; + snaph = (struct snaphdr *) nb->data; + type = snaph->type; + } + } + + hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac)); + src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac)); + + switch (type) + { + /* ARP packet. */ + case GRUB_NET_ETHERTYPE_ARP: + grub_net_arp_receive (nb, card); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + /* IP packet. */ + case GRUB_NET_ETHERTYPE_IP: + case GRUB_NET_ETHERTYPE_IP6: + return grub_net_recv_ip_packets (nb, card, &hwaddress, &src_hwaddress); + } + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} diff --git a/grub-core/net/http.c b/grub-core/net/http.c new file mode 100644 index 000000000..9f6628cb9 --- /dev/null +++ b/grub-core/net/http.c @@ -0,0 +1,510 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +enum + { + HTTP_PORT = 80 + }; + + +typedef struct http_data +{ + char *current_line; + grub_size_t current_line_len; + int headers_recv; + int first_line_recv; + int size_recv; + grub_net_tcp_socket_t sock; + char *filename; + grub_err_t err; + char *errmsg; + int chunked; + grub_size_t chunk_rem; + int in_chunk_len; +} *http_data_t; + +static grub_off_t +have_ahead (struct grub_file *file) +{ + grub_net_t net = file->device->net; + grub_off_t ret = net->offset; + struct grub_net_packet *pack; + for (pack = net->packs.first; pack; pack = pack->next) + ret += pack->nb->tail - pack->nb->data; + return ret; +} + +static grub_err_t +parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) +{ + char *end = ptr + len; + while (end > ptr && *(end - 1) == '\r') + end--; + *end = 0; + /* Trailing CRLF. */ + if (data->in_chunk_len == 1) + { + data->in_chunk_len = 2; + return GRUB_ERR_NONE; + } + if (data->in_chunk_len == 2) + { + data->chunk_rem = grub_strtoul (ptr, 0, 16); + grub_errno = GRUB_ERR_NONE; + if (data->chunk_rem == 0) + { + file->device->net->eof = 1; + if (file->size == GRUB_FILE_SIZE_UNKNOWN) + file->size = have_ahead (file); + } + data->in_chunk_len = 0; + return GRUB_ERR_NONE; + } + if (ptr == end) + { + data->headers_recv = 1; + if (data->chunked) + data->in_chunk_len = 2; + return GRUB_ERR_NONE; + } + + if (!data->first_line_recv) + { + int code; + if (grub_memcmp (ptr, "HTTP/1.1 ", sizeof ("HTTP/1.1 ") - 1) != 0) + return grub_error (GRUB_ERR_NET_INVALID_RESPONSE, + "unsupported HTTP response"); + ptr += sizeof ("HTTP/1.1 ") - 1; + code = grub_strtoul (ptr, &ptr, 10); + if (grub_errno) + return grub_errno; + switch (code) + { + case 200: + break; + case 404: + data->err = GRUB_ERR_FILE_NOT_FOUND; + data->errmsg = grub_xasprintf ("file `%s' not found", data->filename); + return GRUB_ERR_NONE; + default: + data->err = GRUB_ERR_NET_UNKNOWN_ERROR; + data->errmsg = grub_xasprintf ("unsupported HTTP error %d: %s", + code, ptr); + return GRUB_ERR_NONE; + } + data->first_line_recv = 1; + return GRUB_ERR_NONE; + } + if (grub_memcmp (ptr, "Content-Length: ", sizeof ("Content-Length: ") - 1) + == 0 && !data->size_recv) + { + ptr += sizeof ("Content-Length: ") - 1; + file->size = grub_strtoull (ptr, &ptr, 10); + data->size_recv = 1; + return GRUB_ERR_NONE; + } + if (grub_memcmp (ptr, "Transfer-Encoding: chunked", + sizeof ("Transfer-Encoding: chunked") - 1) == 0) + { + data->chunked = 1; + return GRUB_ERR_NONE; + } + + return GRUB_ERR_NONE; +} + +static void +http_err (grub_net_tcp_socket_t sock __attribute__ ((unused)), + void *f) +{ + grub_file_t file = f; + http_data_t data = file->data; + + if (data->sock) + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->current_line) + grub_free (data->current_line); + grub_free (data); + file->device->net->eof = 1; + if (file->size == GRUB_FILE_SIZE_UNKNOWN) + file->size = have_ahead (file); +} + +static grub_err_t +http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + struct grub_net_buff *nb, + void *f) +{ + grub_file_t file = f; + http_data_t data = file->data; + grub_err_t err; + + while (1) + { + char *ptr = (char *) nb->data; + if ((!data->headers_recv || data->in_chunk_len) && data->current_line) + { + int have_line = 1; + char *t; + ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); + if (ptr) + ptr++; + else + { + have_line = 0; + ptr = (char *) nb->tail; + } + t = grub_realloc (data->current_line, + data->current_line_len + (ptr - (char *) nb->data)); + if (!t) + { + grub_netbuff_free (nb); + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + return grub_errno; + } + + data->current_line = t; + grub_memcpy (data->current_line + data->current_line_len, + nb->data, ptr - (char *) nb->data); + data->current_line_len += ptr - (char *) nb->data; + if (!have_line) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + err = parse_line (file, data, data->current_line, + data->current_line_len); + grub_free (data->current_line); + data->current_line = 0; + data->current_line_len = 0; + if (err) + { + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + grub_netbuff_free (nb); + return err; + } + } + + while (ptr < (char *) nb->tail && (!data->headers_recv + || data->in_chunk_len)) + { + char *ptr2; + ptr2 = grub_memchr (ptr, '\n', (char *) nb->tail - ptr); + if (!ptr2) + { + data->current_line = grub_malloc ((char *) nb->tail - ptr); + if (!data->current_line) + { + grub_netbuff_free (nb); + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + return grub_errno; + } + data->current_line_len = (char *) nb->tail - ptr; + grub_memcpy (data->current_line, ptr, data->current_line_len); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + err = parse_line (file, data, ptr, ptr2 - ptr); + if (err) + { + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + grub_netbuff_free (nb); + return err; + } + ptr = ptr2 + 1; + } + + if (((char *) nb->tail - ptr) <= 0) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + err = grub_netbuff_pull (nb, ptr - (char *) nb->data); + if (err) + { + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + grub_netbuff_free (nb); + return err; + } + if (!(data->chunked && (grub_ssize_t) data->chunk_rem + < nb->tail - nb->data)) + { + grub_net_put_packet (&file->device->net->packs, nb); + if (data->chunked) + data->chunk_rem -= nb->tail - nb->data; + return GRUB_ERR_NONE; + } + if (data->chunk_rem) + { + struct grub_net_buff *nb2; + nb2 = grub_netbuff_alloc (data->chunk_rem); + if (!nb2) + return grub_errno; + grub_netbuff_put (nb2, data->chunk_rem); + grub_memcpy (nb2->data, nb->data, data->chunk_rem); + grub_net_put_packet (&file->device->net->packs, nb2); + grub_netbuff_pull (nb, data->chunk_rem); + } + data->in_chunk_len = 1; + } +} + +static grub_err_t +http_establish (struct grub_file *file, grub_off_t offset, int initial) +{ + http_data_t data = file->data; + grub_uint8_t *ptr; + int i; + struct grub_net_buff *nb; + grub_err_t err; + + nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE + + sizeof ("GET ") - 1 + + grub_strlen (data->filename) + + sizeof (" HTTP/1.1\r\nHost: ") - 1 + + grub_strlen (file->device->net->server) + + sizeof ("\r\nUser-Agent: " PACKAGE_STRING + "\r\n") - 1 + + sizeof ("Content-Range: bytes XXXXXXXXXXXXXXXXXXXX" + "-XXXXXXXXXXXXXXXXXXXX/" + "XXXXXXXXXXXXXXXXXXXX\r\n\r\n")); + if (!nb) + return grub_errno; + + grub_netbuff_reserve (nb, GRUB_NET_TCP_RESERVE_SIZE); + ptr = nb->tail; + err = grub_netbuff_put (nb, sizeof ("GET ") - 1); + if (err) + { + grub_netbuff_free (nb); + return err; + } + grub_memcpy (ptr, "GET ", sizeof ("GET ") - 1); + + ptr = nb->tail; + + err = grub_netbuff_put (nb, grub_strlen (data->filename)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + grub_memcpy (ptr, data->filename, grub_strlen (data->filename)); + + ptr = nb->tail; + err = grub_netbuff_put (nb, sizeof (" HTTP/1.1\r\nHost: ") - 1); + if (err) + { + grub_netbuff_free (nb); + return err; + } + grub_memcpy (ptr, " HTTP/1.1\r\nHost: ", + sizeof (" HTTP/1.1\r\nHost: ") - 1); + + ptr = nb->tail; + err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + grub_memcpy (ptr, file->device->net->server, + grub_strlen (file->device->net->server)); + + ptr = nb->tail; + err = grub_netbuff_put (nb, + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") + - 1); + if (err) + { + grub_netbuff_free (nb); + return err; + } + grub_memcpy (ptr, "\r\nUser-Agent: " PACKAGE_STRING "\r\n", + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") - 1); + if (!initial) + { + ptr = nb->tail; + grub_snprintf ((char *) ptr, + sizeof ("Content-Range: bytes XXXXXXXXXXXXXXXXXXXX-" + "XXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXX\r\n" + "\r\n"), + "Content-Range: bytes %" PRIuGRUB_UINT64_T "-%" + PRIuGRUB_UINT64_T "/%" PRIuGRUB_UINT64_T "\r\n\r\n", + offset, file->size - 1, file->size); + grub_netbuff_put (nb, grub_strlen ((char *) ptr)); + } + ptr = nb->tail; + grub_netbuff_put (nb, 2); + grub_memcpy (ptr, "\r\n", 2); + + data->sock = grub_net_tcp_open (file->device->net->server, + HTTP_PORT, http_receive, + http_err, http_err, + file); + if (!data->sock) + { + grub_netbuff_free (nb); + return grub_errno; + } + + // grub_net_poll_cards (5000); + + err = grub_net_send_tcp_packet (data->sock, nb, 1); + if (err) + { + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + return err; + } + + for (i = 0; !data->headers_recv && i < 100; i++) + { + grub_net_tcp_retransmit (); + grub_net_poll_cards (300); + } + + if (!data->headers_recv) + { + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->err) + { + char *str = data->errmsg; + err = grub_error (data->err, "%s", str); + grub_free (str); + return data->err; + } + return grub_error (GRUB_ERR_TIMEOUT, "timeout opening http"); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +http_seek (struct grub_file *file, grub_off_t off) +{ + struct http_data *old_data, *data; + grub_err_t err; + old_data = file->data; + /* FIXME: Reuse socket? */ + grub_net_tcp_close (old_data->sock, GRUB_NET_TCP_ABORT); + + while (file->device->net->packs.first) + { + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } + + file->device->net->offset = off; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return grub_errno; + + data->size_recv = 1; + data->filename = old_data->filename; + if (!data->filename) + { + grub_free (data); + return grub_errno; + } + grub_free (old_data); + + file->data = data; + err = http_establish (file, off, 0); + if (err) + { + grub_free (data->filename); + grub_free (data); + return err; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +http_open (struct grub_file *file, const char *filename) +{ + grub_err_t err; + struct http_data *data; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return grub_errno; + file->size = GRUB_FILE_SIZE_UNKNOWN; + + data->filename = grub_strdup (filename); + if (!data->filename) + { + grub_free (data); + return grub_errno; + } + + file->not_easily_seekable = 0; + file->data = data; + + err = http_establish (file, 0, 1); + if (err) + { + grub_free (data->filename); + grub_free (data); + return err; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +http_close (struct grub_file *file) +{ + http_data_t data = file->data; + + if (data->sock) + grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->current_line) + grub_free (data->current_line); + grub_free (data); + return GRUB_ERR_NONE; +} + +static struct grub_net_app_protocol grub_http_protocol = + { + .name = "http", + .open = http_open, + .close = http_close, + .seek = http_seek + }; + +GRUB_MOD_INIT (http) +{ + grub_net_app_level_register (&grub_http_protocol); +} + +GRUB_MOD_FINI (http) +{ + grub_net_app_level_unregister (&grub_http_protocol); +} diff --git a/grub-core/net/icmp.c b/grub-core/net/icmp.c new file mode 100644 index 000000000..e55a0d86a --- /dev/null +++ b/grub-core/net/icmp.c @@ -0,0 +1,122 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +struct icmp_header +{ + grub_uint8_t type; + grub_uint8_t code; + grub_uint16_t checksum; +} __attribute__ ((packed)); + +struct ping_header +{ + grub_uint16_t id; + grub_uint16_t seq; +} __attribute__ ((packed)); + +enum + { + ICMP_ECHO_REPLY = 0, + ICMP_ECHO = 8, + }; + +grub_err_t +grub_net_recv_icmp_packet (struct grub_net_buff *nb, + struct grub_net_network_level_interface *inf, + const grub_net_link_level_address_t *ll_src, + const grub_net_network_level_address_t *src) +{ + struct icmp_header *icmph; + grub_err_t err; + grub_uint16_t checksum; + + /* Ignore broadcast. */ + if (!inf) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + icmph = (struct icmp_header *) nb->data; + + if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph)) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + checksum = icmph->checksum; + icmph->checksum = 0; + if (checksum != grub_net_ip_chksum (nb->data, nb->tail - nb->data)) + { + icmph->checksum = checksum; + return GRUB_ERR_NONE; + } + icmph->checksum = checksum; + + err = grub_netbuff_pull (nb, sizeof (*icmph)); + if (err) + return err; + + switch (icmph->type) + { + case ICMP_ECHO: + { + struct grub_net_buff *nb_reply; + struct icmp_header *icmphr; + if (icmph->code) + break; + nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512); + if (!nb_reply) + { + grub_netbuff_free (nb); + return grub_errno; + } + err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512); + if (err) + goto ping_fail; + err = grub_netbuff_push (nb_reply, nb->tail - nb->data); + if (err) + goto ping_fail; + grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data); + err = grub_netbuff_push (nb_reply, sizeof (*icmphr)); + if (err) + goto ping_fail; + icmphr = (struct icmp_header *) nb_reply->data; + icmphr->type = ICMP_ECHO_REPLY; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->checksum = grub_net_ip_chksum ((void *) nb_reply->data, + nb_reply->tail - nb_reply->data); + err = grub_net_send_ip_packet (inf, src, ll_src, + nb_reply, GRUB_NET_IP_ICMP); + + ping_fail: + grub_netbuff_free (nb); + grub_netbuff_free (nb_reply); + return err; + } + }; + + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c new file mode 100644 index 000000000..9a5f3cafe --- /dev/null +++ b/grub-core/net/icmp6.c @@ -0,0 +1,529 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +struct icmp_header +{ + grub_uint8_t type; + grub_uint8_t code; + grub_uint16_t checksum; +} __attribute__ ((packed)); + +struct ping_header +{ + grub_uint16_t id; + grub_uint16_t seq; +} __attribute__ ((packed)); + +struct router_adv +{ + grub_uint8_t ttl; + grub_uint8_t flags; + grub_uint16_t router_lifetime; + grub_uint32_t reachable_time; + grub_uint32_t retrans_timer; + grub_uint8_t options[0]; +} __attribute__ ((packed)); + +struct option_header +{ + grub_uint8_t type; + grub_uint8_t len; +} __attribute__ ((packed)); + +struct prefix_option +{ + struct option_header header; + grub_uint8_t prefixlen; + grub_uint8_t flags; + grub_uint32_t valid_lifetime; + grub_uint32_t prefered_lifetime; + grub_uint32_t reserved; + grub_uint64_t prefix[2]; +} __attribute__ ((packed)); + +struct neighbour_solicit +{ + grub_uint32_t reserved; + grub_uint64_t target[2]; +} __attribute__ ((packed)); + +struct neighbour_advertise +{ + grub_uint32_t flags; + grub_uint64_t target[2]; +} __attribute__ ((packed)); + +enum + { + FLAG_SLAAC = 0x40 + }; + +enum + { + ICMP6_ECHO = 128, + ICMP6_ECHO_REPLY = 129, + ICMP6_ROUTER_ADVERTISE = 134, + ICMP6_NEIGHBOUR_SOLICIT = 135, + ICMP6_NEIGHBOUR_ADVERTISE = 136, + }; + +enum + { + OPTION_SOURCE_LINK_LAYER_ADDRESS = 1, + OPTION_TARGET_LINK_LAYER_ADDRESS = 2, + OPTION_PREFIX = 3 + }; + +enum + { + FLAG_SOLICITED = (1 << 30), + FLAG_OVERRIDE = (1 << 29) + }; + +grub_err_t +grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + struct grub_net_card *card, + struct grub_net_network_level_interface *inf, + const grub_net_link_level_address_t *ll_src, + const grub_net_network_level_address_t *source, + const grub_net_network_level_address_t *dest, + grub_uint8_t ttl) +{ + struct icmp_header *icmph; + grub_err_t err; + grub_uint16_t checksum; + + icmph = (struct icmp_header *) nb->data; + + if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph)) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + checksum = icmph->checksum; + icmph->checksum = 0; + if (checksum != grub_net_ip_transport_checksum (nb, + GRUB_NET_IP_ICMPV6, + source, + dest)) + { + grub_dprintf ("net", "invalid ICMPv6 checksum: %04x instead of %04x\n", + checksum, + grub_net_ip_transport_checksum (nb, + GRUB_NET_IP_ICMPV6, + source, + dest)); + icmph->checksum = checksum; + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + icmph->checksum = checksum; + + err = grub_netbuff_pull (nb, sizeof (*icmph)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + + grub_dprintf ("net", "ICMPv6 message: %02x, %02x\n", + icmph->type, icmph->code); + switch (icmph->type) + { + case ICMP6_ECHO: + /* Don't accept multicast pings. */ + if (!inf) + break; + { + struct grub_net_buff *nb_reply; + struct icmp_header *icmphr; + if (icmph->code) + break; + nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512); + if (!nb_reply) + { + grub_netbuff_free (nb); + return grub_errno; + } + err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512); + if (err) + goto ping_fail; + err = grub_netbuff_push (nb_reply, nb->tail - nb->data); + if (err) + goto ping_fail; + grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data); + err = grub_netbuff_push (nb_reply, sizeof (*icmphr)); + if (err) + goto ping_fail; + icmphr = (struct icmp_header *) nb_reply->data; + icmphr->type = ICMP6_ECHO_REPLY; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->checksum = grub_net_ip_transport_checksum (nb_reply, + GRUB_NET_IP_ICMPV6, + &inf->address, + source); + err = grub_net_send_ip_packet (inf, source, ll_src, nb_reply, + GRUB_NET_IP_ICMPV6); + + ping_fail: + grub_netbuff_free (nb); + grub_netbuff_free (nb_reply); + return err; + } + case ICMP6_NEIGHBOUR_SOLICIT: + { + struct neighbour_solicit *nbh; + struct grub_net_buff *nb_reply; + struct option_header *ohdr; + struct neighbour_advertise *adv; + struct icmp_header *icmphr; + grub_uint8_t *ptr; + + if (icmph->code) + break; + if (ttl != 0xff) + break; + nbh = (struct neighbour_solicit *) nb->data; + err = grub_netbuff_pull (nb, sizeof (struct router_adv)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail; + ptr += ohdr->len * 8) + { + ohdr = (struct option_header *) ptr; + if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (ohdr->type == OPTION_SOURCE_LINK_LAYER_ADDRESS + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; + ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + if (inf->card == card + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && grub_memcmp (&inf->address.ipv6, &nbh->target, 16) == 0) + break; + } + if (!inf) + break; + + nb_reply = grub_netbuff_alloc (sizeof (struct neighbour_advertise) + + sizeof (struct option_header) + + 6 + + sizeof (struct icmp_header) + + GRUB_NET_OUR_IPV6_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (!nb_reply) + { + grub_netbuff_free (nb); + return grub_errno; + } + err = grub_netbuff_reserve (nb_reply, + sizeof (struct neighbour_advertise) + + sizeof (struct option_header) + + 6 + + sizeof (struct icmp_header) + + GRUB_NET_OUR_IPV6_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (err) + goto ndp_fail; + + err = grub_netbuff_push (nb_reply, 6); + if (err) + goto ndp_fail; + grub_memcpy (nb_reply->data, inf->hwaddress.mac, 6); + err = grub_netbuff_push (nb_reply, sizeof (*ohdr)); + if (err) + goto ndp_fail; + ohdr = (struct option_header *) nb_reply->data; + ohdr->type = OPTION_TARGET_LINK_LAYER_ADDRESS; + ohdr->len = 1; + err = grub_netbuff_push (nb_reply, sizeof (*adv)); + if (err) + goto ndp_fail; + adv = (struct neighbour_advertise *) nb_reply->data; + adv->flags = grub_cpu_to_be32_compile_time (FLAG_SOLICITED + | FLAG_OVERRIDE); + grub_memcpy (&adv->target, &nbh->target, 16); + + err = grub_netbuff_push (nb_reply, sizeof (*icmphr)); + if (err) + goto ndp_fail; + icmphr = (struct icmp_header *) nb_reply->data; + icmphr->type = ICMP6_NEIGHBOUR_ADVERTISE; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->checksum = grub_net_ip_transport_checksum (nb_reply, + GRUB_NET_IP_ICMPV6, + &inf->address, + source); + err = grub_net_send_ip_packet (inf, source, ll_src, nb_reply, + GRUB_NET_IP_ICMPV6); + + ndp_fail: + grub_netbuff_free (nb); + grub_netbuff_free (nb_reply); + return err; + } + case ICMP6_NEIGHBOUR_ADVERTISE: + { + struct neighbour_advertise *nbh; + grub_uint8_t *ptr; + struct option_header *ohdr; + + if (icmph->code) + break; + if (ttl != 0xff) + break; + nbh = (struct neighbour_advertise *) nb->data; + err = grub_netbuff_pull (nb, sizeof (*nbh)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + + for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail; + ptr += ohdr->len * 8) + { + ohdr = (struct option_header *) ptr; + if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (ohdr->type == OPTION_TARGET_LINK_LAYER_ADDRESS + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; + ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } + break; + } + case ICMP6_ROUTER_ADVERTISE: + { + grub_uint8_t *ptr; + struct option_header *ohdr; + if (icmph->code) + break; + err = grub_netbuff_pull (nb, sizeof (struct router_adv)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail; + ptr += ohdr->len * 8) + { + ohdr = (struct option_header *) ptr; + if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (ohdr->type == OPTION_SOURCE_LINK_LAYER_ADDRESS + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; + ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + if (ohdr->type == OPTION_PREFIX && ohdr->len == 4) + { + struct prefix_option *opt = (struct prefix_option *) ptr; + struct grub_net_slaac_mac_list *slaac; + if (!(opt->flags & FLAG_SLAAC) + || (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80 + || (grub_be_to_cpu32 (opt->prefered_lifetime) + > grub_be_to_cpu32 (opt->valid_lifetime)) + || opt->prefixlen != 64) + { + grub_dprintf ("net", "discarded prefix: %d, %d, %d, %d\n", + !(opt->flags & FLAG_SLAAC), + (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80, + (grub_be_to_cpu32 (opt->prefered_lifetime) + > grub_be_to_cpu32 (opt->valid_lifetime)), + opt->prefixlen != 64); + continue; + } + for (slaac = card->slaac_list; slaac; slaac = slaac->next) + { + grub_net_network_level_address_t addr; + grub_net_network_level_netaddress_t netaddr; + + if (slaac->address.type + != GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET) + continue; + addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + addr.ipv6[0] = opt->prefix[0]; + addr.ipv6[1] = grub_net_ipv6_get_id (&slaac->address); + netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + netaddr.ipv6.base[0] = opt->prefix[0]; + netaddr.ipv6.base[1] = 0; + netaddr.ipv6.masksize = 64; + + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + if (inf->card == card + && grub_net_addr_cmp (&inf->address, &addr) == 0) + break; + } + /* Update lease time if needed here once we have + lease times. */ + if (inf) + continue; + + grub_dprintf ("net", "creating slaac\n"); + + { + char name[grub_strlen (slaac->name) + + sizeof (":XXXXXXXXXXXXXXXXXXXX")]; + grub_snprintf (name, sizeof (name), "%s:%d", + slaac->name, slaac->slaac_counter++); + inf = grub_net_add_addr (name, + card, &addr, + &slaac->address, 0); + grub_net_add_route (name, netaddr, inf); + } + } + } + } + if (ptr != nb->tail) + break; + } + }; + + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr) +{ + struct grub_net_buff *nb; + grub_err_t err = GRUB_ERR_NONE; + int i; + struct option_header *ohdr; + struct neighbour_solicit *sol; + struct icmp_header *icmphr; + grub_net_network_level_address_t multicast; + grub_net_link_level_address_t ll_multicast; + grub_uint8_t *nbd; + multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + multicast.ipv6[0] = grub_be_to_cpu64_compile_time (0xff02ULL << 48); + multicast.ipv6[1] = (grub_be_to_cpu64_compile_time (0x01ff000000ULL) + | (proto_addr->ipv6[1] + & grub_be_to_cpu64_compile_time (0xffffff))); + + err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); + if (err) + return err; + + nb = grub_netbuff_alloc (sizeof (struct neighbour_solicit) + + sizeof (struct option_header) + + 6 + + sizeof (struct icmp_header) + + GRUB_NET_OUR_IPV6_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (!nb) + return grub_errno; + err = grub_netbuff_reserve (nb, + sizeof (struct neighbour_solicit) + + sizeof (struct option_header) + + 6 + + sizeof (struct icmp_header) + + GRUB_NET_OUR_IPV6_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + err = grub_netbuff_push (nb, 6); + if (err) + goto fail; + + grub_memcpy (nb->data, inf->hwaddress.mac, 6); + err = grub_netbuff_push (nb, sizeof (*ohdr)); + if (err) + goto fail; + + ohdr = (struct option_header *) nb->data; + ohdr->type = OPTION_SOURCE_LINK_LAYER_ADDRESS; + ohdr->len = 1; + err = grub_netbuff_push (nb, sizeof (*sol)); + if (err) + goto fail; + + sol = (struct neighbour_solicit *) nb->data; + sol->reserved = 0; + grub_memcpy (&sol->target, &proto_addr->ipv6, 16); + + err = grub_netbuff_push (nb, sizeof (*icmphr)); + if (err) + goto fail; + + icmphr = (struct icmp_header *) nb->data; + icmphr->type = ICMP6_NEIGHBOUR_SOLICIT; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->checksum = grub_net_ip_transport_checksum (nb, + GRUB_NET_IP_ICMPV6, + &inf->address, + &multicast); + nbd = nb->data; + err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, + GRUB_NET_IP_ICMPV6); + if (err) + goto fail; + + for (i = 0; i < GRUB_NET_TRIES; i++) + { + if (grub_net_link_layer_resolve_check (inf, proto_addr)) + break; + grub_net_poll_cards (GRUB_NET_INTERVAL); + if (grub_net_link_layer_resolve_check (inf, proto_addr)) + break; + nb->data = nbd; + err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, + GRUB_NET_IP_ICMPV6); + if (err) + break; + } + + fail: + grub_netbuff_free (nb); + return err; +} diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c new file mode 100644 index 000000000..f3ec74d57 --- /dev/null +++ b/grub-core/net/ip.c @@ -0,0 +1,700 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +struct iphdr { + grub_uint8_t verhdrlen; + grub_uint8_t service; + grub_uint16_t len; + grub_uint16_t ident; + grub_uint16_t frags; + grub_uint8_t ttl; + grub_uint8_t protocol; + grub_uint16_t chksum; + grub_uint32_t src; + grub_uint32_t dest; +} __attribute__ ((packed)) ; + +enum +{ + DONT_FRAGMENT = 0x4000, + MORE_FRAGMENTS = 0x2000, + OFFSET_MASK = 0x1fff +}; + +typedef grub_uint64_t ip6addr[2]; + +struct ip6hdr { + grub_uint32_t version_class_flow; + grub_uint16_t len; + grub_uint8_t protocol; + grub_uint8_t ttl; + ip6addr src; + ip6addr dest; +} __attribute__ ((packed)) ; + +static int +cmp (const void *a__, const void *b__) +{ + struct grub_net_buff *a_ = *(struct grub_net_buff **) a__; + struct grub_net_buff *b_ = *(struct grub_net_buff **) b__; + struct iphdr *a = (struct iphdr *) a_->data; + struct iphdr *b = (struct iphdr *) b_->data; + /* We want the first elements to be on top. */ + if ((grub_be_to_cpu16 (a->frags) & OFFSET_MASK) + < (grub_be_to_cpu16 (b->frags) & OFFSET_MASK)) + return +1; + if ((grub_be_to_cpu16 (a->frags) & OFFSET_MASK) + > (grub_be_to_cpu16 (b->frags) & OFFSET_MASK)) + return -1; + return 0; +} + +struct reassemble +{ + struct reassemble *next; + grub_uint32_t source; + grub_uint32_t dest; + grub_uint16_t id; + grub_uint8_t proto; + grub_uint64_t last_time; + grub_priority_queue_t pq; + grub_uint8_t *asm_buffer; + grub_size_t total_len; + grub_size_t cur_ptr; + grub_uint8_t ttl; +}; + +static struct reassemble *reassembles; + +grub_uint16_t +grub_net_ip_chksum (void *ipv, grub_size_t len) +{ + grub_uint16_t *ip = (grub_uint16_t *) ipv; + grub_uint32_t sum = 0; + + for (; len >= 2; len -= 2) + { + sum += grub_be_to_cpu16 (grub_get_unaligned16 (ip++)); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + if (len) + { + sum += *((grub_uint8_t *) ip) << 8; + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + + if (sum >= 0xFFFF) + sum -= 0xFFFF; + + return grub_cpu_to_be16 ((~sum) & 0x0000FFFF); +} + +static int id = 0x2400; + +static grub_err_t +send_fragmented (struct grub_net_network_level_interface * inf, + const grub_net_network_level_address_t * target, + struct grub_net_buff * nb, + grub_net_ip_protocol_t proto, + grub_net_link_level_address_t ll_target_addr) +{ + grub_size_t off = 0; + grub_size_t fraglen; + grub_err_t err; + + fraglen = (inf->card->mtu - sizeof (struct iphdr)) & ~7; + id++; + + while (nb->tail - nb->data) + { + grub_size_t len = fraglen; + struct grub_net_buff *nb2; + struct iphdr *iph; + + if ((grub_ssize_t) len > nb->tail - nb->data) + len = nb->tail - nb->data; + nb2 = grub_netbuff_alloc (fraglen + sizeof (struct iphdr) + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (!nb2) + return grub_errno; + err = grub_netbuff_reserve (nb2, GRUB_NET_MAX_LINK_HEADER_SIZE); + if (err) + return err; + err = grub_netbuff_put (nb2, sizeof (struct iphdr)); + if (err) + return err; + + iph = (struct iphdr *) nb2->data; + iph->verhdrlen = ((4 << 4) | 5); + iph->service = 0; + iph->len = grub_cpu_to_be16 (len + sizeof (struct iphdr)); + iph->ident = grub_cpu_to_be16 (id); + iph->frags = grub_cpu_to_be16 (off | (((grub_ssize_t) len + == nb->tail - nb->data) + ? 0 : MORE_FRAGMENTS)); + iph->ttl = 0xff; + iph->protocol = proto; + iph->src = inf->address.ipv4; + iph->dest = target->ipv4; + off += len / 8; + + iph->chksum = 0; + iph->chksum = grub_net_ip_chksum ((void *) nb2->data, sizeof (*iph)); + err = grub_netbuff_put (nb2, len); + if (err) + return err; + grub_memcpy (iph + 1, nb->data, len); + err = grub_netbuff_pull (nb, len); + if (err) + return err; + err = send_ethernet_packet (inf, nb2, ll_target_addr, + GRUB_NET_ETHERTYPE_IP); + if (err) + return err; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_net_send_ip4_packet (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *target, + const grub_net_link_level_address_t *ll_target_addr, + struct grub_net_buff *nb, + grub_net_ip_protocol_t proto) +{ + struct iphdr *iph; + + COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV4_HEADER_SIZE == sizeof (*iph)); + + if (nb->tail - nb->data + sizeof (struct iphdr) > inf->card->mtu) + return send_fragmented (inf, target, nb, proto, *ll_target_addr); + + grub_netbuff_push (nb, sizeof (*iph)); + iph = (struct iphdr *) nb->data; + + iph->verhdrlen = ((4 << 4) | 5); + iph->service = 0; + iph->len = grub_cpu_to_be16 (nb->tail - nb->data); + iph->ident = grub_cpu_to_be16 (++id); + iph->frags = 0; + iph->ttl = 0xff; + iph->protocol = proto; + iph->src = inf->address.ipv4; + iph->dest = target->ipv4; + + iph->chksum = 0; + iph->chksum = grub_net_ip_chksum ((void *) nb->data, sizeof (*iph)); + + return send_ethernet_packet (inf, nb, *ll_target_addr, + GRUB_NET_ETHERTYPE_IP); +} + +static grub_err_t +handle_dgram (struct grub_net_buff *nb, + struct grub_net_card *card, + const grub_net_link_level_address_t *source_hwaddress, + const grub_net_link_level_address_t *hwaddress, + grub_net_ip_protocol_t proto, + const grub_net_network_level_address_t *source, + const grub_net_network_level_address_t *dest, + grub_uint8_t ttl) +{ + struct grub_net_network_level_interface *inf = NULL; + grub_err_t err; + int multicast = 0; + + /* DHCP needs special treatment since we don't know IP yet. */ + { + struct udphdr *udph; + udph = (struct udphdr *) nb->data; + if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) + { + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + if (inf->card == card + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV + && grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0) + { + if (udph->chksum) + { + grub_uint16_t chk, expected; + chk = udph->chksum; + udph->chksum = 0; + expected = grub_net_ip_transport_checksum (nb, + GRUB_NET_IP_UDP, + source, + dest); + if (expected != chk) + { + grub_dprintf ("net", "Invalid UDP checksum. " + "Expected %x, got %x\n", + grub_be_to_cpu16 (expected), + grub_be_to_cpu16 (chk)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + udph->chksum = chk; + } + + err = grub_netbuff_pull (nb, sizeof (*udph)); + if (err) + return err; + grub_net_process_dhcp (nb, inf->card); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + } + + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + if (inf->card == card + && grub_net_addr_cmp (&inf->address, dest) == 0 + && grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0) + break; + /* Solicited node multicast. */ + if (inf->card == card + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && dest->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && dest->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL << 48) + && dest->ipv6[1] == (grub_be_to_cpu64_compile_time (0x01ff000000ULL) + | (inf->address.ipv6[1] + & grub_be_to_cpu64_compile_time (0xffffff))) + && hwaddress->type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET + && hwaddress->mac[0] == 0x33 && hwaddress->mac[1] == 0x33 + && hwaddress->mac[2] == 0xff + && hwaddress->mac[3] == ((grub_be_to_cpu64 (inf->address.ipv6[1]) + >> 16) & 0xff) + && hwaddress->mac[4] == ((grub_be_to_cpu64 (inf->address.ipv6[1]) + >> 8) & 0xff) + && hwaddress->mac[5] == ((grub_be_to_cpu64 (inf->address.ipv6[1]) + >> 0) & 0xff)) + { + multicast = 1; + break; + } + } + + if (!inf && !(dest->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && dest->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL + << 48) + && dest->ipv6[1] == grub_be_to_cpu64_compile_time (1))) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (multicast) + inf = NULL; + + switch (proto) + { + case GRUB_NET_IP_UDP: + return grub_net_recv_udp_packet (nb, inf, source); + case GRUB_NET_IP_TCP: + return grub_net_recv_tcp_packet (nb, inf, source); + case GRUB_NET_IP_ICMP: + return grub_net_recv_icmp_packet (nb, inf, source_hwaddress, source); + case GRUB_NET_IP_ICMPV6: + return grub_net_recv_icmp6_packet (nb, card, inf, source_hwaddress, + source, dest, ttl); + default: + grub_netbuff_free (nb); + break; + } + return GRUB_ERR_NONE; +} + +static void +free_rsm (struct reassemble *rsm) +{ + struct grub_net_buff **nb; + while ((nb = grub_priority_queue_top (rsm->pq))) + { + grub_netbuff_free (*nb); + grub_priority_queue_pop (rsm->pq); + } + grub_free (rsm->asm_buffer); + grub_priority_queue_destroy (rsm->pq); +} + +static void +free_old_fragments (void) +{ + struct reassemble *rsm, **prev; + grub_uint64_t limit_time = grub_get_time_ms () - 90000; + + for (prev = &reassembles, rsm = *prev; rsm; prev = &rsm->next, rsm = *prev) + if (rsm->last_time < limit_time) + { + *prev = rsm->next; + free_rsm (rsm); + } +} + +static grub_err_t +grub_net_recv_ip4_packets (struct grub_net_buff *nb, + struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddress, + const grub_net_link_level_address_t *src_hwaddress) +{ + struct iphdr *iph = (struct iphdr *) nb->data; + grub_err_t err; + struct reassemble *rsm, **prev; + + if ((iph->verhdrlen >> 4) != 4) + { + grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + if ((iph->verhdrlen & 0xf) < 5) + { + grub_dprintf ("net", "IP header too short: %d\n", + (iph->verhdrlen & 0xf)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + if (nb->tail - nb->data < (grub_ssize_t) ((iph->verhdrlen & 0xf) + * sizeof (grub_uint32_t))) + { + grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE "\n", + (nb->tail - nb->data)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + /* Check size. */ + { + grub_size_t expected_size = grub_be_to_cpu16 (iph->len); + grub_size_t actual_size = (nb->tail - nb->data); + if (actual_size > expected_size) + { + err = grub_netbuff_unput (nb, actual_size - expected_size); + if (err) + { + grub_netbuff_free (nb); + return err; + } + } + if (actual_size < expected_size) + { + grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE + ", expected %" PRIuGRUB_SIZE "\n", actual_size, + expected_size); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + } + + /* Unfragmented packet. Good. */ + if (((grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS) == 0) + && (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) == 0) + { + grub_net_network_level_address_t source; + grub_net_network_level_address_t dest; + + err = grub_netbuff_pull (nb, ((iph->verhdrlen & 0xf) + * sizeof (grub_uint32_t))); + if (err) + { + grub_netbuff_free (nb); + return err; + } + + source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + source.ipv4 = iph->src; + + dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + dest.ipv4 = iph->dest; + + return handle_dgram (nb, card, src_hwaddress, hwaddress, iph->protocol, + &source, &dest, iph->ttl); + } + + for (prev = &reassembles, rsm = *prev; rsm; prev = &rsm->next, rsm = *prev) + if (rsm->source == iph->src && rsm->dest == iph->dest + && rsm->id == iph->ident && rsm->proto == iph->protocol) + break; + if (!rsm) + { + rsm = grub_malloc (sizeof (*rsm)); + if (!rsm) + return grub_errno; + rsm->source = iph->src; + rsm->dest = iph->dest; + rsm->id = iph->ident; + rsm->proto = iph->protocol; + rsm->next = reassembles; + reassembles = rsm; + prev = &reassembles; + rsm->pq = grub_priority_queue_new (sizeof (struct grub_net_buff **), cmp); + if (!rsm->pq) + { + grub_free (rsm); + return grub_errno; + } + rsm->asm_buffer = 0; + rsm->total_len = 0; + rsm->cur_ptr = 0; + rsm->ttl = 0xff; + } + if (rsm->ttl > iph->ttl) + rsm->ttl = iph->ttl; + rsm->last_time = grub_get_time_ms (); + free_old_fragments (); + + err = grub_priority_queue_push (rsm->pq, &nb); + if (err) + return err; + + if (!(grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS)) + { + rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb->tail - nb->data)); + rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); + rsm->asm_buffer = grub_zalloc (rsm->total_len); + if (!rsm->asm_buffer) + { + *prev = rsm->next; + free_rsm (rsm); + return grub_errno; + } + } + if (!rsm->asm_buffer) + return GRUB_ERR_NONE; + + while (1) + { + struct grub_net_buff **nb_top_p, *nb_top; + grub_size_t copy; + grub_uint8_t *res; + grub_size_t res_len; + struct grub_net_buff *ret; + grub_net_ip_protocol_t proto; + grub_uint32_t src; + grub_uint32_t dst; + grub_net_network_level_address_t source; + grub_net_network_level_address_t dest; + grub_uint8_t ttl; + + nb_top_p = grub_priority_queue_top (rsm->pq); + if (!nb_top_p) + return GRUB_ERR_NONE; + nb_top = *nb_top_p; + grub_priority_queue_pop (rsm->pq); + iph = (struct iphdr *) nb_top->data; + err = grub_netbuff_pull (nb_top, ((iph->verhdrlen & 0xf) + * sizeof (grub_uint32_t))); + if (err) + { + grub_netbuff_free (nb_top); + return err; + } + if (rsm->cur_ptr < (grub_size_t) 8 * (grub_be_to_cpu16 (iph->frags) + & OFFSET_MASK)) + return GRUB_ERR_NONE; + + rsm->cur_ptr = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb_top->tail - nb_top->head)); + if ((grub_size_t) 8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + >= rsm->total_len) + { + grub_netbuff_free (nb_top); + continue; + } + copy = nb_top->tail - nb_top->data; + if (rsm->total_len - 8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + < copy) + copy = rsm->total_len - 8 * (grub_be_to_cpu16 (iph->frags) + & OFFSET_MASK); + grub_memcpy (&rsm->asm_buffer[8 * (grub_be_to_cpu16 (iph->frags) + & OFFSET_MASK)], + nb_top->data, copy); + + if ((grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS)) + continue; + + res = rsm->asm_buffer; + proto = rsm->proto; + src = rsm->source; + dst = rsm->dest; + ttl = rsm->ttl; + + rsm->asm_buffer = 0; + res_len = rsm->total_len; + *prev = rsm->next; + free_rsm (rsm); + ret = grub_malloc (sizeof (*ret)); + if (!ret) + { + grub_free (res); + return grub_errno; + } + ret->data = ret->head = res; + ret->tail = ret->end = res + res_len; + + source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + source.ipv4 = src; + + dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + dest.ipv4 = dst; + + return handle_dgram (ret, card, src_hwaddress, + hwaddress, proto, &source, &dest, + ttl); + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_net_send_ip6_packet (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *target, + const grub_net_link_level_address_t *ll_target_addr, + struct grub_net_buff *nb, + grub_net_ip_protocol_t proto) +{ + struct ip6hdr *iph; + + COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV6_HEADER_SIZE == sizeof (*iph)); + + if (nb->tail - nb->data + sizeof (struct iphdr) > inf->card->mtu) + return grub_error (GRUB_ERR_NET_PACKET_TOO_BIG, "packet too big"); + + grub_netbuff_push (nb, sizeof (*iph)); + iph = (struct ip6hdr *) nb->data; + + iph->version_class_flow = grub_cpu_to_be32 ((6 << 28)); + iph->len = grub_cpu_to_be16 (nb->tail - nb->data - sizeof (*iph)); + iph->protocol = proto; + iph->ttl = 0xff; + grub_memcpy (&iph->src, inf->address.ipv6, sizeof (iph->src)); + grub_memcpy (&iph->dest, target->ipv6, sizeof (iph->dest)); + + return send_ethernet_packet (inf, nb, *ll_target_addr, + GRUB_NET_ETHERTYPE_IP6); +} + +grub_err_t +grub_net_send_ip_packet (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *target, + const grub_net_link_level_address_t *ll_target_addr, + struct grub_net_buff *nb, + grub_net_ip_protocol_t proto) +{ + switch (target->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + return grub_net_send_ip4_packet (inf, target, ll_target_addr, nb, proto); + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + return grub_net_send_ip6_packet (inf, target, ll_target_addr, nb, proto); + default: + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP"); + } +} + +static grub_err_t +grub_net_recv_ip6_packets (struct grub_net_buff *nb, + struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddress, + const grub_net_link_level_address_t *src_hwaddress) +{ + struct ip6hdr *iph = (struct ip6hdr *) nb->data; + grub_err_t err; + grub_net_network_level_address_t source; + grub_net_network_level_address_t dest; + + if (nb->tail - nb->data < (grub_ssize_t) sizeof (*iph)) + { + grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE "\n", + nb->tail - nb->data); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + err = grub_netbuff_pull (nb, sizeof (*iph)); + if (err) + { + grub_netbuff_free (nb); + return err; + } + + /* Check size. */ + { + grub_size_t expected_size = grub_be_to_cpu16 (iph->len); + grub_size_t actual_size = (nb->tail - nb->data); + if (actual_size > expected_size) + { + err = grub_netbuff_unput (nb, actual_size - expected_size); + if (err) + { + grub_netbuff_free (nb); + return err; + } + } + if (actual_size < expected_size) + { + grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE + ", expected %" PRIuGRUB_SIZE "\n", actual_size, + expected_size); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + } + + source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + grub_memcpy (source.ipv6, &iph->src, sizeof (source.ipv6)); + grub_memcpy (dest.ipv6, &iph->dest, sizeof (dest.ipv6)); + + return handle_dgram (nb, card, src_hwaddress, hwaddress, iph->protocol, + &source, &dest, iph->ttl); +} + +grub_err_t +grub_net_recv_ip_packets (struct grub_net_buff *nb, + struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddress, + const grub_net_link_level_address_t *src_hwaddress) +{ + struct iphdr *iph = (struct iphdr *) nb->data; + + if ((iph->verhdrlen >> 4) == 4) + return grub_net_recv_ip4_packets (nb, card, hwaddress, src_hwaddress); + if ((iph->verhdrlen >> 4) == 6) + return grub_net_recv_ip6_packets (nb, card, hwaddress, src_hwaddress); + grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} diff --git a/grub-core/net/net.c b/grub-core/net/net.c new file mode 100644 index 000000000..25d079b94 --- /dev/null +++ b/grub-core/net/net.c @@ -0,0 +1,1534 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +char *grub_net_default_server; + +struct grub_net_route +{ + struct grub_net_route *next; + struct grub_net_route **prev; + grub_net_network_level_netaddress_t target; + char *name; + struct grub_net_network_level_protocol *prot; + int is_gateway; + union + { + struct grub_net_network_level_interface *interface; + grub_net_network_level_address_t gw; + }; +}; + +struct grub_net_route *grub_net_routes = NULL; +struct grub_net_network_level_interface *grub_net_network_level_interfaces = NULL; +struct grub_net_card *grub_net_cards = NULL; +struct grub_net_network_level_protocol *grub_net_network_level_protocols = NULL; +static struct grub_fs grub_net_fs; + +struct grub_net_link_layer_entry { + int avail; + grub_net_network_level_address_t nl_address; + grub_net_link_level_address_t ll_address; +}; + +#define LINK_LAYER_CACHE_SIZE 256 + +static struct grub_net_link_layer_entry * +link_layer_find_entry (const grub_net_network_level_address_t *proto, + const struct grub_net_card *card) +{ + unsigned i; + if (!card->link_layer_table) + return NULL; + for (i = 0; i < LINK_LAYER_CACHE_SIZE; i++) + { + if (card->link_layer_table[i].avail == 1 + && grub_net_addr_cmp (&card->link_layer_table[i].nl_address, + proto) == 0) + return &card->link_layer_table[i]; + } + return NULL; +} + +void +grub_net_link_layer_add_address (struct grub_net_card *card, + const grub_net_network_level_address_t *nl, + const grub_net_link_level_address_t *ll, + int override) +{ + struct grub_net_link_layer_entry *entry; + + /* Check if the sender is in the cache table. */ + entry = link_layer_find_entry (nl, card); + /* Update sender hardware address. */ + if (entry && override) + grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address)); + if (entry) + return; + + /* Add sender to cache table. */ + if (card->link_layer_table == NULL) + card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE + * sizeof (card->link_layer_table[0])); + entry = &(card->link_layer_table[card->new_ll_entry]); + entry->avail = 1; + grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address)); + grub_memcpy (&entry->nl_address, nl, sizeof (entry->nl_address)); + card->new_ll_entry++; + if (card->new_ll_entry == LINK_LAYER_CACHE_SIZE) + card->new_ll_entry = 0; +} + +int +grub_net_link_layer_resolve_check (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr) +{ + struct grub_net_link_layer_entry *entry; + + if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4 + && proto_addr->ipv4 == 0xffffffff) + return 1; + entry = link_layer_find_entry (proto_addr, inf->card); + if (entry) + return 1; + return 0; +} + +grub_err_t +grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr, + grub_net_link_level_address_t *hw_addr) +{ + struct grub_net_link_layer_entry *entry; + grub_err_t err; + + if ((proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4 + && proto_addr->ipv4 == 0xffffffff) + || proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV + || (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && proto_addr->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL + << 48) + && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) + { + hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + grub_memset (hw_addr->mac, -1, 6); + return GRUB_ERR_NONE; + } + + if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 + && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) + { + hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; + hw_addr->mac[0] = 0x33; + hw_addr->mac[1] = 0x33; + hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); + hw_addr->mac[3] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 16) & 0xff); + hw_addr->mac[4] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 8) & 0xff); + hw_addr->mac[5] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 0) & 0xff); + return GRUB_ERR_NONE; + } + + /* Check cache table. */ + entry = link_layer_find_entry (proto_addr, inf->card); + if (entry) + { + *hw_addr = entry->ll_address; + return GRUB_ERR_NONE; + } + switch (proto_addr->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + err = grub_net_arp_send_request (inf, proto_addr); + break; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + err = grub_net_icmp6_send_request (inf, proto_addr); + break; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + return grub_error (GRUB_ERR_BUG, "shouldn't reach here"); + default: + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported address type %d", proto_addr->type); + } + if (err) + return err; + entry = link_layer_find_entry (proto_addr, inf->card); + if (entry) + { + *hw_addr = entry->ll_address; + return GRUB_ERR_NONE; + } + return grub_error (GRUB_ERR_TIMEOUT, + "timeout: could not resolve hardware address"); +} + +void +grub_net_card_unregister (struct grub_net_card *card) +{ + struct grub_net_network_level_interface *inf, *next; + FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(inf, next) + if (inf->card == card) + grub_net_network_level_interface_unregister (inf); + if (card->opened) + { + if (card->driver->close) + card->driver->close (card); + card->opened = 0; + } + grub_list_remove (GRUB_AS_LIST (card)); +} + +static struct grub_net_slaac_mac_list * +grub_net_ipv6_get_slaac (struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddr) +{ + struct grub_net_slaac_mac_list *slaac; + char *ptr; + + for (slaac = card->slaac_list; slaac; slaac = slaac->next) + if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0) + return slaac; + + slaac = grub_zalloc (sizeof (*slaac)); + if (!slaac) + return NULL; + + slaac->name = grub_malloc (grub_strlen (card->name) + + GRUB_NET_MAX_STR_HWADDR_LEN + + sizeof (":slaac")); + ptr = grub_stpcpy (slaac->name, card->name); + if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0) + { + ptr = grub_stpcpy (ptr, ":"); + grub_net_hwaddr_to_str (hwaddr, ptr); + ptr += grub_strlen (ptr); + } + ptr = grub_stpcpy (ptr, ":slaac"); + + grub_memcpy (&slaac->address, hwaddr, sizeof (slaac->address)); + slaac->next = card->slaac_list; + card->slaac_list = slaac; + return slaac; +} + +struct grub_net_network_level_interface * +grub_net_ipv6_get_link_local (struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddr) +{ + struct grub_net_network_level_interface *inf; + char name[grub_strlen (card->name) + + GRUB_NET_MAX_STR_HWADDR_LEN + + sizeof (":link")]; + char *ptr; + grub_net_network_level_address_t addr; + + addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + addr.ipv6[0] = grub_cpu_to_be64 (0xfe80ULL << 48); + addr.ipv6[1] = grub_net_ipv6_get_id (hwaddr); + + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + if (inf->card == card + && grub_net_hwaddr_cmp (&inf->hwaddress, hwaddr) == 0 + && grub_net_addr_cmp (&inf->address, &addr) == 0) + return inf; + } + + ptr = grub_stpcpy (name, card->name); + if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0) + { + ptr = grub_stpcpy (ptr, ":"); + grub_net_hwaddr_to_str (hwaddr, ptr); + ptr += grub_strlen (ptr); + } + ptr = grub_stpcpy (ptr, ":link"); + return grub_net_add_addr (name, card, &addr, hwaddr, 0); +} + +/* FIXME: allow to specify mac address. */ +static grub_err_t +grub_cmd_ipv6_autoconf (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_card *card; + struct grub_net_network_level_interface **ifaces; + grub_size_t ncards = 0; + unsigned j = 0; + int interval; + grub_err_t err; + struct grub_net_slaac_mac_list **slaacs; + + FOR_NET_CARDS (card) + { + if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) + continue; + ncards++; + } + + ifaces = grub_zalloc (ncards * sizeof (ifaces[0])); + slaacs = grub_zalloc (ncards * sizeof (slaacs[0])); + if (!ifaces || !slaacs) + { + grub_free (ifaces); + grub_free (slaacs); + return grub_errno; + } + + FOR_NET_CARDS (card) + { + if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) + continue; + ifaces[j] = grub_net_ipv6_get_link_local (card, &card->default_address); + if (!ifaces[j]) + { + grub_free (ifaces); + grub_free (slaacs); + return grub_errno; + } + slaacs[j] = grub_net_ipv6_get_slaac (card, &card->default_address); + if (!slaacs[j]) + { + grub_free (ifaces); + grub_free (slaacs); + return grub_errno; + } + j++; + } + + for (interval = 200; interval < 10000; interval *= 2) + { + /* FIXME: send router solicitation. */ + int done = 1; + for (j = 0; j < ncards; j++) + { + if (slaacs[j]->slaac_counter) + continue; + done = 0; + } + if (done) + break; + grub_net_poll_cards (interval); + } + + err = GRUB_ERR_NONE; + for (j = 0; j < ncards; j++) + { + if (slaacs[j]->slaac_counter) + continue; + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s", + ifaces[j]->card->name); + } + + grub_free (ifaces); + grub_free (slaacs); + return err; +} + +static inline void +grub_net_route_register (struct grub_net_route *route) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_net_routes), + GRUB_AS_LIST (route)); +} + +static inline void +grub_net_route_unregister (struct grub_net_route *route) +{ + grub_list_remove (GRUB_AS_LIST (route)); +} + +#define FOR_NET_ROUTES(var) for (var = grub_net_routes; var; var = var->next) + +static int +parse_ip (const char *val, grub_uint32_t *ip, const char **rest) +{ + grub_uint32_t newip = 0; + int i; + const char *ptr = val; + + for (i = 0; i < 4; i++) + { + unsigned long t; + t = grub_strtoul (ptr, (char **) &ptr, 0); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (*ptr != '.' && i == 0) + { + newip = t; + break; + } + if (t & ~0xff) + return 0; + newip >>= 8; + newip |= (t << 24); + if (i != 3 && *ptr != '.') + return 0; + ptr++; + } + *ip = grub_cpu_to_le32 (newip); + if (rest) + *rest = (ptr - 1); + return 1; +} + +static int +parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) +{ + grub_uint16_t newip[8]; + const char *ptr = val; + int word, quaddot = -1; + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; + if (ptr[0] == ':') + ptr++; + + for (word = 0; word < 8; word++) + { + unsigned long t; + if (*ptr == ':') + { + quaddot = word; + word--; + ptr++; + continue; + } + t = grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; + break; + } + if (t & ~0xffff) + return 0; + newip[word] = grub_cpu_to_be16 (t); + if (*ptr != ':') + break; + ptr++; + } + if (quaddot == -1 && word < 7) + return 0; + if (quaddot != -1) + { + grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], + (word - quaddot + 1) * sizeof (newip[0])); + grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); + } + grub_memcpy (ip, newip, 16); + if (rest) + *rest = ptr; + return 1; +} + +static int +match_net (const grub_net_network_level_netaddress_t *net, + const grub_net_network_level_address_t *addr) +{ + if (net->type != addr->type) + return 0; + switch (net->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + return 0; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + { + grub_uint32_t mask = (0xffffffffU << (32 - net->ipv4.masksize)); + if (net->ipv4.masksize == 0) + mask = 0; + return ((grub_be_to_cpu32 (net->ipv4.base) & mask) + == (grub_be_to_cpu32 (addr->ipv4) & mask)); + } + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + { + grub_uint64_t mask[2]; + if (net->ipv6.masksize <= 64) + { + mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize); + mask[1] = 0; + } + else + { + mask[0] = 0xffffffffffffffffULL; + mask[1] = 0xffffffffffffffffULL << (128 - net->ipv6.masksize); + } + return (((grub_be_to_cpu64 (net->ipv6.base[0]) & mask[0]) + == (grub_be_to_cpu64 (addr->ipv6[0]) & mask[0])) + && ((grub_be_to_cpu64 (net->ipv6.base[1]) & mask[1]) + == (grub_be_to_cpu64 (addr->ipv6[1]) & mask[1]))); + } + } + return 0; +} + +grub_err_t +grub_net_resolve_address (const char *name, + grub_net_network_level_address_t *addr) +{ + const char *rest; + grub_err_t err; + grub_size_t naddresses; + struct grub_net_network_level_address *addresses; + + if (parse_ip (name, &addr->ipv4, &rest) && *rest == 0) + { + addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + return GRUB_ERR_NONE; + } + if (parse_ip6 (name, addr->ipv6, &rest) && *rest == 0) + { + addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + return GRUB_ERR_NONE; + } + err = grub_net_dns_lookup (name, 0, 0, &naddresses, &addresses, 1); + if (err) + return err; + if (!naddresses) + grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unresolvable address %s"), + name); + /* FIXME: use other results as well. */ + *addr = addresses[0]; + grub_free (addresses); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_net_resolve_net_address (const char *name, + grub_net_network_level_netaddress_t *addr) +{ + const char *rest; + if (parse_ip (name, &addr->ipv4.base, &rest)) + { + addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + if (*rest == '/') + { + addr->ipv4.masksize = grub_strtoul (rest + 1, (char **) &rest, 0); + if (!grub_errno && *rest == 0) + return GRUB_ERR_NONE; + grub_errno = GRUB_ERR_NONE; + } + else if (*rest == 0) + { + addr->ipv4.masksize = 32; + return GRUB_ERR_NONE; + } + } + if (parse_ip6 (name, addr->ipv6.base, &rest)) + { + addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + if (*rest == '/') + { + addr->ipv6.masksize = grub_strtoul (rest + 1, (char **) &rest, 0); + if (!grub_errno && *rest == 0) + return GRUB_ERR_NONE; + grub_errno = GRUB_ERR_NONE; + } + else if (*rest == 0) + { + addr->ipv6.masksize = 128; + return GRUB_ERR_NONE; + } + } + return grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unrecognised address %s"), + name); +} + +static int +route_cmp (const struct grub_net_route *a, const struct grub_net_route *b) +{ + if (a == NULL && b == NULL) + return 0; + if (b == NULL) + return +1; + if (a == NULL) + return -1; + if (a->target.type < b->target.type) + return -1; + if (a->target.type > b->target.type) + return +1; + switch (a->target.type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + break; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + if (a->target.ipv6.masksize > b->target.ipv6.masksize) + return +1; + if (a->target.ipv6.masksize < b->target.ipv6.masksize) + return -1; + break; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + if (a->target.ipv4.masksize > b->target.ipv4.masksize) + return +1; + if (a->target.ipv4.masksize < b->target.ipv4.masksize) + return -1; + break; + } + return 0; +} + +grub_err_t +grub_net_route_address (grub_net_network_level_address_t addr, + grub_net_network_level_address_t *gateway, + struct grub_net_network_level_interface **interf) +{ + struct grub_net_route *route; + int depth = 0; + int routecnt = 0; + struct grub_net_network_level_protocol *prot = NULL; + grub_net_network_level_address_t curtarget = addr; + + *gateway = addr; + + FOR_NET_ROUTES(route) + routecnt++; + + for (depth = 0; depth < routecnt + 2; depth++) + { + struct grub_net_route *bestroute = NULL; + FOR_NET_ROUTES(route) + { + if (depth && prot != route->prot) + continue; + if (!match_net (&route->target, &curtarget)) + continue; + if (route_cmp (route, bestroute) > 0) + bestroute = route; + } + if (bestroute == NULL) + return grub_error (GRUB_ERR_NET_NO_ROUTE, "destination unreachable"); + + if (!bestroute->is_gateway) + { + *interf = bestroute->interface; + return GRUB_ERR_NONE; + } + if (depth == 0) + *gateway = bestroute->gw; + curtarget = bestroute->gw; + } + + return grub_error (GRUB_ERR_NET_ROUTE_LOOP, "route loop detected"); +} + +static grub_err_t +grub_cmd_deladdr (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_network_level_interface *inter; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + FOR_NET_NETWORK_LEVEL_INTERFACES (inter) + if (grub_strcmp (inter->name, args[1]) == 0) + break; + if (inter == NULL) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("address not found")); + + if (inter->flags & GRUB_NET_INTERFACE_PERMANENT) + return grub_error (GRUB_ERR_IO, + N_("you can't delete this address")); + + grub_net_network_level_interface_unregister (inter); + grub_free (inter->name); + grub_free (inter); + + return GRUB_ERR_NONE; +} + +void +grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) +{ + switch (target->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + grub_strcpy (buf, "temporary"); + return; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + { + char *ptr = buf; + grub_uint64_t n = grub_be_to_cpu64 (target->ipv6[0]); + int i; + for (i = 0; i < 4; i++) + { + grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":", + (n >> (48 - 16 * i)) & 0xffff); + ptr += grub_strlen (ptr); + } + n = grub_be_to_cpu64 (target->ipv6[1]); + for (i = 0; i < 3; i++) + { + grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":", + (n >> (48 - 16 * i)) & 0xffff); + ptr += grub_strlen (ptr); + } + grub_snprintf (ptr, 5, "%" PRIxGRUB_UINT64_T, n & 0xffff); + return; + } + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + { + grub_uint32_t n = grub_be_to_cpu32 (target->ipv4); + grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN, "%d.%d.%d.%d", + ((n >> 24) & 0xff), ((n >> 16) & 0xff), + ((n >> 8) & 0xff), ((n >> 0) & 0xff)); + } + return; + } + grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN, + "Unknown address type %d", target->type); +} + + +void +grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) +{ + str[0] = 0; + switch (addr->type) + { + case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: + { + char *ptr; + unsigned i; + for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++) + { + grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), + "%02x:", addr->mac[i] & 0xff); + ptr += (sizeof ("XX:") - 1); + } + return; + } + } + grub_printf ("Unsupported hw address type %d\n", addr->type); +} + +int +grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b) +{ + if (a->type < b->type) + return -1; + if (a->type > b->type) + return +1; + switch (a->type) + { + case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: + return grub_memcmp (a->mac, b->mac, sizeof (a->mac)); + } + grub_printf ("Unsupported hw address type %d\n", a->type); + return 1; +} + +int +grub_net_addr_cmp (const grub_net_network_level_address_t *a, + const grub_net_network_level_address_t *b) +{ + if (a->type < b->type) + return -1; + if (a->type > b->type) + return +1; + switch (a->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + return grub_memcmp (&a->ipv4, &b->ipv4, sizeof (a->ipv4)); + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + return grub_memcmp (&a->ipv6, &b->ipv6, sizeof (a->ipv6)); + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + return 0; + } + grub_printf ("Unsupported address type %d\n", a->type); + return 1; +} + +/* FIXME: implement this. */ +static char * +hwaddr_set_env (struct grub_env_var *var __attribute__ ((unused)), + const char *val __attribute__ ((unused))) +{ + return NULL; +} + +/* FIXME: implement this. */ +static char * +addr_set_env (struct grub_env_var *var __attribute__ ((unused)), + const char *val __attribute__ ((unused))) +{ + return NULL; +} + +static void +grub_net_network_level_interface_register (struct grub_net_network_level_interface *inter) +{ + { + char buf[GRUB_NET_MAX_STR_HWADDR_LEN]; + char name[grub_strlen (inter->name) + sizeof ("net__mac")]; + grub_net_hwaddr_to_str (&inter->hwaddress, buf); + grub_snprintf (name, sizeof (name), "net_%s_mac", inter->name); + grub_env_set (name, buf); + grub_register_variable_hook (name, 0, hwaddr_set_env); + } + + { + char buf[GRUB_NET_MAX_STR_ADDR_LEN]; + char name[grub_strlen (inter->name) + sizeof ("net__ip")]; + grub_net_addr_to_str (&inter->address, buf); + grub_snprintf (name, sizeof (name), "net_%s_ip", inter->name); + grub_env_set (name, buf); + grub_register_variable_hook (name, 0, addr_set_env); + } + + inter->card->num_ifaces++; + inter->prev = &grub_net_network_level_interfaces; + inter->next = grub_net_network_level_interfaces; + if (inter->next) + inter->next->prev = &inter->next; + grub_net_network_level_interfaces = inter; +} + +struct grub_net_network_level_interface * +grub_net_add_addr (const char *name, + struct grub_net_card *card, + const grub_net_network_level_address_t *addr, + const grub_net_link_level_address_t *hwaddress, + grub_net_interface_flags_t flags) +{ + struct grub_net_network_level_interface *inter; + + inter = grub_zalloc (sizeof (*inter)); + if (!inter) + return NULL; + + inter->name = grub_strdup (name); + grub_memcpy (&(inter->address), addr, sizeof (inter->address)); + grub_memcpy (&(inter->hwaddress), hwaddress, sizeof (inter->hwaddress)); + inter->flags = flags; + inter->card = card; + inter->dhcp_ack = NULL; + inter->dhcp_acklen = 0; + + grub_net_network_level_interface_register (inter); + + if (addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + { + int mask = -1; + grub_uint32_t ip_cpu = grub_be_to_cpu32 (addr->ipv4); + if (!(ip_cpu & 0x80000000)) + mask = 8; + else if (!(ip_cpu & 0x40000000)) + mask = 16; + else if (!(ip_cpu & 0x20000000)) + mask = 24; + else + mask = -1; + if (mask != -1) + { + struct grub_net_route *route; + + route = grub_zalloc (sizeof (*route)); + if (!route) + return NULL; + + route->name = grub_xasprintf ("%s:local", name); + if (!route->name) + { + grub_free (route); + return NULL; + } + + route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + route->target.ipv4.base = grub_cpu_to_be32 (ip_cpu & (0xffffffff << (32 - mask))); + route->target.ipv4.masksize = mask; + route->is_gateway = 0; + route->interface = inter; + + grub_net_route_register (route); + } + } + + return inter; +} + +/* FIXME: support MAC specifying. */ +static grub_err_t +grub_cmd_addaddr (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_card *card; + grub_net_network_level_address_t addr; + grub_err_t err; + grub_net_interface_flags_t flags = 0; + + if (argc != 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); + + FOR_NET_CARDS (card) + if (grub_strcmp (card->name, args[1]) == 0) + break; + if (card == NULL) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); + + err = grub_net_resolve_address (args[2], &addr); + if (err) + return err; + + if (card->flags & GRUB_NET_CARD_NO_MANUAL_INTERFACES) + return grub_error (GRUB_ERR_IO, + "this card doesn't support address addition"); + + if (card->flags & GRUB_NET_CARD_HWADDRESS_IMMUTABLE) + flags |= GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE; + + grub_net_add_addr (args[0], card, &addr, &card->default_address, + flags); + return grub_errno; +} + +static grub_err_t +grub_cmd_delroute (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_route *route; + struct grub_net_route **prev; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + for (prev = &grub_net_routes, route = *prev; route; prev = &((*prev)->next), + route = *prev) + if (grub_strcmp (route->name, args[0]) == 0) + { + *prev = route->next; + grub_free (route->name); + grub_free (route); + if (!*prev) + break; + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_net_add_route (const char *name, + grub_net_network_level_netaddress_t target, + struct grub_net_network_level_interface *inter) +{ + struct grub_net_route *route; + + route = grub_zalloc (sizeof (*route)); + if (!route) + return grub_errno; + + route->name = grub_strdup (name); + if (!route->name) + { + grub_free (route); + return grub_errno; + } + + route->target = target; + route->is_gateway = 0; + route->interface = inter; + + grub_net_route_register (route); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_net_add_route_gw (const char *name, + grub_net_network_level_netaddress_t target, + grub_net_network_level_address_t gw) +{ + struct grub_net_route *route; + + route = grub_zalloc (sizeof (*route)); + if (!route) + return grub_errno; + + route->name = grub_strdup (name); + if (!route->name) + { + grub_free (route); + return grub_errno; + } + + route->target = target; + route->is_gateway = 1; + route->gw = gw; + + grub_net_route_register (route); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_addroute (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_net_network_level_netaddress_t target; + if (argc < 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("At least 3 arguments are expected")); + + grub_net_resolve_net_address (args[1], &target); + + if (grub_strcmp (args[2], "gw") == 0 && argc >= 4) + { + grub_err_t err; + grub_net_network_level_address_t gw; + + err = grub_net_resolve_address (args[3], &gw); + if (err) + return err; + return grub_net_add_route_gw (args[0], target, gw); + } + else + { + struct grub_net_network_level_interface *inter; + + FOR_NET_NETWORK_LEVEL_INTERFACES (inter) + if (grub_strcmp (inter->name, args[2]) == 0) + break; + + if (!inter) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unrecognised interface %s"), args[2]); + return grub_net_add_route (args[0], target, inter); + } +} + +static void +print_net_address (const grub_net_network_level_netaddress_t *target) +{ + switch (target->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + grub_printf ("temporary\n"); + return; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + { + grub_uint32_t n = grub_be_to_cpu32 (target->ipv4.base); + grub_printf ("%d.%d.%d.%d/%d ", ((n >> 24) & 0xff), + ((n >> 16) & 0xff), + ((n >> 8) & 0xff), + ((n >> 0) & 0xff), + target->ipv4.masksize); + } + return; + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + { + char buf[GRUB_NET_MAX_STR_ADDR_LEN]; + struct grub_net_network_level_address base; + base.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; + grub_memcpy (&base.ipv6, &target->ipv6, 16); + grub_net_addr_to_str (&base, buf); + grub_printf ("%s/%d ", buf, target->ipv6.masksize); + } + return; + } + grub_printf ("Unknown address type %d\n", target->type); +} + +static void +print_address (const grub_net_network_level_address_t *target) +{ + char buf[GRUB_NET_MAX_STR_ADDR_LEN]; + grub_net_addr_to_str (target, buf); + grub_xputs (buf); +} + +static grub_err_t +grub_cmd_listroutes (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + struct grub_net_route *route; + FOR_NET_ROUTES(route) + { + grub_printf ("%s ", route->name); + print_net_address (&route->target); + if (route->is_gateway) + { + grub_printf ("gw "); + print_address (&route->gw); + } + else + grub_printf ("%s", route->interface->name); + grub_printf ("\n"); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_listcards (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + struct grub_net_card *card; + FOR_NET_CARDS(card) + { + char buf[GRUB_NET_MAX_STR_HWADDR_LEN]; + grub_net_hwaddr_to_str (&card->default_address, buf); + grub_printf ("%s %s\n", card->name, buf); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_listaddrs (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + struct grub_net_network_level_interface *inf; + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + char bufh[GRUB_NET_MAX_STR_HWADDR_LEN]; + char bufn[GRUB_NET_MAX_STR_ADDR_LEN]; + grub_net_hwaddr_to_str (&inf->hwaddress, bufh); + grub_net_addr_to_str (&inf->address, bufn); + grub_printf ("%s %s %s\n", inf->name, bufh, bufn); + } + return GRUB_ERR_NONE; +} + +grub_net_app_level_t grub_net_app_level_list; +struct grub_net_socket *grub_net_sockets; + +static grub_net_t +grub_net_open_real (const char *name) +{ + grub_net_app_level_t proto; + const char *protname, *server; + grub_size_t protnamelen; + + if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) + { + protname = "tftp"; + protnamelen = sizeof ("tftp") - 1; + server = name + sizeof ("pxe:") - 1; + } + else if (grub_strcmp (name, "pxe") == 0) + { + protname = "tftp"; + protnamelen = sizeof ("tftp") - 1; + server = grub_net_default_server; + } + else + { + const char *comma; + comma = grub_strchr (name, ','); + if (comma) + { + protnamelen = comma - name; + server = comma + 1; + protname = name; + } + else + { + protnamelen = grub_strlen (name); + server = grub_net_default_server; + protname = name; + } + } + if (!server) + { + grub_error (GRUB_ERR_NET_BAD_ADDRESS, "no server"); + return NULL; + } + + FOR_NET_APP_LEVEL (proto) + { + if (grub_memcmp (proto->name, protname, protnamelen) == 0 + && proto->name[protnamelen] == 0) + { + grub_net_t ret = grub_zalloc (sizeof (*ret)); + if (!ret) + return NULL; + ret->protocol = proto; + if (server) + { + ret->server = grub_strdup (server); + if (!ret->server) + { + grub_free (ret); + return NULL; + } + } + else + ret->server = NULL; + ret->fs = &grub_net_fs; + ret->offset = 0; + ret->eof = 0; + return ret; + } + } + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device"); + + return NULL; +} + +static grub_err_t +grub_net_fs_dir (grub_device_t device, const char *path __attribute__ ((unused)), + int (*hook) (const char *filename, + const struct grub_dirhook_info *info) __attribute__ ((unused))) +{ + if (!device->net) + return grub_error (GRUB_ERR_BAD_FS, "invalid extent"); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_net_fs_open (struct grub_file *file_out, const char *name) +{ + grub_err_t err; + struct grub_file *file, *bufio; + + file = grub_malloc (sizeof (*file)); + if (!file) + return grub_errno; + + grub_memcpy (file, file_out, sizeof (struct grub_file)); + file->device->net->packs.first = NULL; + file->device->net->packs.last = NULL; + file->device->net->name = grub_strdup (name); + if (!file->device->net->name) + return grub_errno; + + err = file->device->net->protocol->open (file, name); + if (err) + return err; + bufio = grub_bufio_open (file, 32768); + if (! bufio) + { + file->device->net->protocol->close (file); + grub_free (file->device->net->name); + grub_free (file); + return grub_errno; + } + + grub_memcpy (file_out, bufio, sizeof (struct grub_file)); + grub_free (bufio); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_net_fs_close (grub_file_t file) +{ + while (file->device->net->packs.first) + { + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } + file->device->net->protocol->close (file); + grub_free (file->device->net->name); + return GRUB_ERR_NONE; +} + +static void +receive_packets (struct grub_net_card *card) +{ + if (card->num_ifaces == 0) + return; + if (!card->opened) + { + grub_err_t err = GRUB_ERR_NONE; + if (card->driver->open) + err = card->driver->open (card); + if (err) + { + grub_errno = GRUB_ERR_NONE; + return; + } + card->opened = 1; + } + while (1) + { + /* Maybe should be better have a fixed number of packets for each card + and just mark them as used and not used. */ + struct grub_net_buff *nb; + + nb = card->driver->recv (card); + if (!nb) + { + card->last_poll = grub_get_time_ms (); + break; + } + grub_net_recv_ethernet_packet (nb, card); + if (grub_errno) + { + grub_dprintf ("net", "error receiving: %d: %s\n", grub_errno, + grub_errmsg); + grub_errno = GRUB_ERR_NONE; + } + } + grub_print_error (); +} + +void +grub_net_poll_cards (unsigned time) +{ + struct grub_net_card *card; + grub_uint64_t start_time; + FOR_NET_CARDS (card) + { + start_time = grub_get_time_ms (); + while ((grub_get_time_ms () - start_time) < time) + receive_packets (card); + } + grub_net_tcp_retransmit (); +} + +static void +grub_net_poll_cards_idle_real (void) +{ + struct grub_net_card *card; + FOR_NET_CARDS (card) + { + grub_uint64_t ctime = grub_get_time_ms (); + + if (ctime < card->last_poll + || ctime >= card->last_poll + card->idle_poll_delay_ms) + receive_packets (card); + } + grub_net_tcp_retransmit (); +} + +/* Read from the packets list*/ +static grub_ssize_t +grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len) +{ + grub_net_t net = file->device->net; + struct grub_net_buff *nb; + char *ptr = buf; + grub_size_t amount, total = 0; + int try = 0; + + while (try <= GRUB_NET_TRIES) + { + while (net->packs.first) + { + try = 0; + nb = net->packs.first->nb; + amount = nb->tail - nb->data; + if (amount > len) + amount = len; + len -= amount; + total += amount; + file->device->net->offset += amount; + if (buf) + { + grub_memcpy (ptr, nb->data, amount); + ptr += amount; + } + if (amount == (grub_size_t) (nb->tail - nb->data)) + { + grub_netbuff_free (nb); + grub_net_remove_packet (net->packs.first); + } + else + nb->data += amount; + + if (!len) + return total; + } + if (!net->eof) + { + try++; + grub_net_poll_cards (GRUB_NET_INTERVAL); + } + else + return total; + } + grub_error (GRUB_ERR_TIMEOUT, "timeout reading '%s'", net->name); + return -1; +} + +static grub_off_t +have_ahead (struct grub_file *file) +{ + grub_net_t net = file->device->net; + grub_off_t ret = net->offset; + struct grub_net_packet *pack; + for (pack = net->packs.first; pack; pack = pack->next) + ret += pack->nb->tail - pack->nb->data; + return ret; +} + +static grub_err_t +grub_net_seek_real (struct grub_file *file, grub_off_t offset) +{ + if (offset == file->device->net->offset) + return GRUB_ERR_NONE; + + if (offset > file->device->net->offset) + { + if (!file->device->net->protocol->seek || have_ahead (file) >= offset) + { + grub_net_fs_read_real (file, NULL, + offset - file->device->net->offset); + return grub_errno; + } + return file->device->net->protocol->seek (file, offset); + } + + { + grub_err_t err; + if (file->device->net->protocol->seek) + return file->device->net->protocol->seek (file, offset); + while (file->device->net->packs.first) + { + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } + file->device->net->protocol->close (file); + + file->device->net->packs.first = NULL; + file->device->net->packs.last = NULL; + file->device->net->offset = 0; + file->device->net->eof = 0; + err = file->device->net->protocol->open (file, file->device->net->name); + if (err) + return err; + grub_net_fs_read_real (file, NULL, offset); + return grub_errno; + } +} + +static grub_ssize_t +grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) +{ + if (file->offset != file->device->net->offset) + { + grub_err_t err; + err = grub_net_seek_real (file, file->offset); + if (err) + return err; + } + return grub_net_fs_read_real (file, buf, len); +} + +static struct grub_fs grub_net_fs = + { + .name = "netfs", + .dir = grub_net_fs_dir, + .open = grub_net_fs_open, + .read = grub_net_fs_read, + .close = grub_net_fs_close, + .label = NULL, + .uuid = NULL, + .mtime = NULL, + }; + +static grub_err_t +grub_net_fini_hw (int noreturn __attribute__ ((unused))) +{ + struct grub_net_card *card; + FOR_NET_CARDS (card) + if (card->opened) + { + if (card->driver->close) + card->driver->close (card); + card->opened = 0; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_net_restore_hw (void) +{ + return GRUB_ERR_NONE; +} + +static struct grub_preboot *fini_hnd; + +static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; +static grub_command_t cmd_lsroutes, cmd_lscards; +static grub_command_t cmd_lsaddr, cmd_slaac; + +GRUB_MOD_INIT(net) +{ + cmd_addaddr = grub_register_command ("net_add_addr", grub_cmd_addaddr, + N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), + N_("Add a network address.")); + cmd_slaac = grub_register_command ("net_ipv6_autoconf", + grub_cmd_ipv6_autoconf, + "[CARD [HWADDRESS]]", + N_("Perform an IPV6 autoconfiguration")); + + cmd_deladdr = grub_register_command ("net_del_addr", grub_cmd_deladdr, + N_("SHORTNAME"), + N_("Delete a network address.")); + cmd_addroute = grub_register_command ("net_add_route", grub_cmd_addroute, + N_("SHORTNAME NET [INTERFACE| gw GATEWAY]"), + N_("Add a network route.")); + cmd_delroute = grub_register_command ("net_del_route", grub_cmd_delroute, + N_("SHORTNAME"), + N_("Delete a network route.")); + cmd_lsroutes = grub_register_command ("net_ls_routes", grub_cmd_listroutes, + "", N_("list network routes")); + cmd_lscards = grub_register_command ("net_ls_cards", grub_cmd_listcards, + "", N_("list network cards")); + cmd_lsaddr = grub_register_command ("net_ls_addr", grub_cmd_listaddrs, + "", N_("list network addresses")); + grub_bootp_init (); + grub_dns_init (); + + grub_fs_register (&grub_net_fs); + grub_net_open = grub_net_open_real; + fini_hnd = grub_loader_register_preboot_hook (grub_net_fini_hw, + grub_net_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; +} + +GRUB_MOD_FINI(net) +{ + grub_bootp_fini (); + grub_dns_fini (); + grub_unregister_command (cmd_addaddr); + grub_unregister_command (cmd_deladdr); + grub_unregister_command (cmd_addroute); + grub_unregister_command (cmd_delroute); + grub_unregister_command (cmd_lsroutes); + grub_unregister_command (cmd_lscards); + grub_unregister_command (cmd_lsaddr); + grub_unregister_command (cmd_slaac); + grub_fs_unregister (&grub_net_fs); + grub_net_open = NULL; + grub_net_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; +} diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c new file mode 100644 index 000000000..242b154e0 --- /dev/null +++ b/grub-core/net/netbuff.c @@ -0,0 +1,108 @@ +/* + * 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 + +grub_err_t +grub_netbuff_put (struct grub_net_buff *nb, grub_size_t len) +{ + nb->tail += len; + if (nb->tail > nb->end) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "put out of the packet range."); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_netbuff_unput (struct grub_net_buff *nb, grub_size_t len) +{ + nb->tail -= len; + if (nb->tail < nb->head) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "unput out of the packet range."); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_netbuff_push (struct grub_net_buff *nb, grub_size_t len) +{ + nb->data -= len; + if (nb->data < nb->head) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "push out of the packet range."); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_netbuff_pull (struct grub_net_buff *nb, grub_size_t len) +{ + nb->data += len; + if (nb->data > nb->end) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "pull out of the packet range."); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_netbuff_reserve (struct grub_net_buff *nb, grub_size_t len) +{ + nb->data += len; + nb->tail += len; + if ((nb->tail > nb->end) || (nb->data > nb->end)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "reserve out of the packet range."); + return GRUB_ERR_NONE; +} + +struct grub_net_buff * +grub_netbuff_alloc (grub_size_t len) +{ + struct grub_net_buff *nb; + void *data; + + COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); + + if (len < NETBUFFMINLEN) + len = NETBUFFMINLEN; + + len = ALIGN_UP (len, NETBUFF_ALIGN); + data = grub_memalign (NETBUFF_ALIGN, len + sizeof (*nb)); + if (!data) + return NULL; + nb = (struct grub_net_buff *) ((grub_properly_aligned_t *) data + + len / sizeof (grub_properly_aligned_t)); + nb->head = nb->data = nb->tail = data; + nb->end = (grub_uint8_t *) nb; + return nb; +} + +grub_err_t +grub_netbuff_free (struct grub_net_buff *nb) +{ + grub_free (nb->head); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_netbuff_clear (struct grub_net_buff *nb) +{ + nb->data = nb->tail = nb->head; + return GRUB_ERR_NONE; +} diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c new file mode 100644 index 000000000..65c6869c8 --- /dev/null +++ b/grub-core/net/tcp.c @@ -0,0 +1,975 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL +#define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES +#define TCP_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL +#define TCP_RETRANSMISSION_COUNT GRUB_NET_TRIES + +struct unacked +{ + struct unacked *next; + struct unacked **prev; + struct grub_net_buff *nb; + grub_uint64_t last_try; + int try_count; +}; + +enum + { + TCP_FIN = 0x1, + TCP_SYN = 0x2, + TCP_RST = 0x4, + TCP_PUSH = 0x8, + TCP_ACK = 0x10, + TCP_URG = 0x20, + }; + +struct grub_net_tcp_socket +{ + struct grub_net_tcp_socket *next; + struct grub_net_tcp_socket **prev; + + int established; + int i_closed; + int they_closed; + int in_port; + int out_port; + int errors; + int they_reseted; + int i_reseted; + grub_uint32_t my_start_seq; + grub_uint32_t my_cur_seq; + grub_uint32_t their_start_seq; + grub_uint32_t their_cur_seq; + grub_uint16_t my_window; + struct unacked *unack_first; + struct unacked *unack_last; + grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, struct grub_net_buff *nb, + void *recv); + void (*error_hook) (grub_net_tcp_socket_t sock, void *recv); + void (*fin_hook) (grub_net_tcp_socket_t sock, void *recv); + void *hook_data; + grub_net_network_level_address_t out_nla; + grub_net_link_level_address_t ll_target_addr; + struct grub_net_network_level_interface *inf; + grub_net_packets_t packs; + grub_priority_queue_t pq; +}; + +struct grub_net_tcp_listen +{ + struct grub_net_tcp_listen *next; + struct grub_net_tcp_listen **prev; + + grub_uint16_t port; + const struct grub_net_network_level_interface *inf; + + grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen, + grub_net_tcp_socket_t sock, + void *data); + void *hook_data; +}; + +struct tcphdr +{ + grub_uint16_t src; + grub_uint16_t dst; + grub_uint32_t seqnr; + grub_uint32_t ack; + grub_uint16_t flags; + grub_uint16_t window; + grub_uint16_t checksum; + grub_uint16_t urgent; +} __attribute__ ((packed)); + +struct tcp_pseudohdr +{ + grub_uint32_t src; + grub_uint32_t dst; + grub_uint8_t zero; + grub_uint8_t proto; + grub_uint16_t tcp_length; +} __attribute__ ((packed)); + +struct tcp6_pseudohdr +{ + grub_uint64_t src[2]; + grub_uint64_t dst[2]; + grub_uint32_t tcp_length; + grub_uint8_t zero[3]; + grub_uint8_t proto; +} __attribute__ ((packed)); + +static struct grub_net_tcp_socket *tcp_sockets; +static struct grub_net_tcp_listen *tcp_listens; + +#define FOR_TCP_SOCKETS(var) FOR_LIST_ELEMENTS (var, tcp_sockets) +#define FOR_TCP_LISTENS(var) FOR_LIST_ELEMENTS (var, tcp_listens) + +grub_net_tcp_listen_t +grub_net_tcp_listen (grub_uint16_t port, + const struct grub_net_network_level_interface *inf, + grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen, + grub_net_tcp_socket_t sock, + void *data), + void *hook_data) +{ + grub_net_tcp_listen_t ret; + ret = grub_malloc (sizeof (*ret)); + if (!ret) + return NULL; + ret->listen_hook = listen_hook; + ret->hook_data = hook_data; + ret->port = port; + ret->inf = inf; + grub_list_push (GRUB_AS_LIST_P (&tcp_listens), GRUB_AS_LIST (ret)); + return ret; +} + +void +grub_net_tcp_stop_listen (grub_net_tcp_listen_t listen) +{ + grub_list_remove (GRUB_AS_LIST (listen)); +} + +static inline void +tcp_socket_register (grub_net_tcp_socket_t sock) +{ + grub_list_push (GRUB_AS_LIST_P (&tcp_sockets), + GRUB_AS_LIST (sock)); +} + +static void +error (grub_net_tcp_socket_t sock) +{ + struct unacked *unack, *next; + + if (sock->error_hook) + sock->error_hook (sock, sock->hook_data); + + for (unack = sock->unack_first; unack; unack = next) + { + next = unack->next; + grub_netbuff_free (unack->nb); + grub_free (unack); + } + + sock->unack_first = NULL; + sock->unack_last = NULL; +} + +static grub_err_t +tcp_send (struct grub_net_buff *nb, grub_net_tcp_socket_t socket) +{ + grub_err_t err; + grub_uint8_t *nbd; + struct unacked *unack; + struct tcphdr *tcph; + grub_size_t size; + + tcph = (struct tcphdr *) nb->data; + + tcph->seqnr = grub_cpu_to_be32 (socket->my_cur_seq); + size = (nb->tail - nb->data - (grub_be_to_cpu16 (tcph->flags) >> 12) * 4); + if (grub_be_to_cpu16 (tcph->flags) & TCP_FIN) + size++; + socket->my_cur_seq += size; + tcph->src = grub_cpu_to_be16 (socket->in_port); + tcph->dst = grub_cpu_to_be16 (socket->out_port); + tcph->checksum = 0; + tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, + &socket->inf->address, + &socket->out_nla); + nbd = nb->data; + if (size) + { + unack = grub_malloc (sizeof (*unack)); + if (!unack) + return grub_errno; + + unack->next = NULL; + unack->nb = nb; + unack->try_count = 1; + unack->last_try = grub_get_time_ms (); + if (!socket->unack_last) + socket->unack_first = socket->unack_last = unack; + else + socket->unack_last->next = unack; + } + + err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla), + &(socket->ll_target_addr), nb, + GRUB_NET_IP_TCP); + if (err) + return err; + nb->data = nbd; + if (!size) + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} + +void +grub_net_tcp_close (grub_net_tcp_socket_t sock, + int discard_received) +{ + struct grub_net_buff *nb_fin; + struct tcphdr *tcph_fin; + grub_err_t err; + + if (discard_received != GRUB_NET_TCP_CONTINUE_RECEIVING) + { + sock->recv_hook = NULL; + sock->error_hook = NULL; + sock->fin_hook = NULL; + } + + if (discard_received == GRUB_NET_TCP_ABORT) + sock->i_reseted = 1; + + if (sock->i_closed) + return; + + sock->i_closed = 1; + + nb_fin = grub_netbuff_alloc (sizeof (*tcph_fin) + + GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (!nb_fin) + return; + err = grub_netbuff_reserve (nb_fin, GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (err) + { + grub_netbuff_free (nb_fin); + grub_dprintf ("net", "error closing socket\n"); + grub_errno = GRUB_ERR_NONE; + return; + } + + err = grub_netbuff_put (nb_fin, sizeof (*tcph_fin)); + if (err) + { + grub_netbuff_free (nb_fin); + grub_dprintf ("net", "error closing socket\n"); + grub_errno = GRUB_ERR_NONE; + return; + } + tcph_fin = (void *) nb_fin->data; + tcph_fin->ack = grub_cpu_to_be32 (sock->their_cur_seq); + tcph_fin->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_FIN + | TCP_ACK); + tcph_fin->window = grub_cpu_to_be16_compile_time (0); + tcph_fin->urgent = 0; + err = tcp_send (nb_fin, sock); + if (err) + { + grub_netbuff_free (nb_fin); + grub_dprintf ("net", "error closing socket\n"); + grub_errno = GRUB_ERR_NONE; + } + return; +} + +static void +ack_real (grub_net_tcp_socket_t sock, int res) +{ + struct grub_net_buff *nb_ack; + struct tcphdr *tcph_ack; + grub_err_t err; + + nb_ack = grub_netbuff_alloc (sizeof (*tcph_ack) + 128); + if (!nb_ack) + return; + err = grub_netbuff_reserve (nb_ack, 128); + if (err) + { + grub_netbuff_free (nb_ack); + grub_dprintf ("net", "error closing socket\n"); + grub_errno = GRUB_ERR_NONE; + return; + } + + err = grub_netbuff_put (nb_ack, sizeof (*tcph_ack)); + if (err) + { + grub_netbuff_free (nb_ack); + grub_dprintf ("net", "error closing socket\n"); + grub_errno = GRUB_ERR_NONE; + return; + } + tcph_ack = (void *) nb_ack->data; + if (res) + { + tcph_ack->ack = grub_cpu_to_be32_compile_time (0); + tcph_ack->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_RST); + tcph_ack->window = grub_cpu_to_be16_compile_time (0); + } + else + { + tcph_ack->ack = grub_cpu_to_be32 (sock->their_cur_seq); + tcph_ack->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK); + tcph_ack->window = grub_cpu_to_be16 (sock->my_window); + } + tcph_ack->urgent = 0; + tcph_ack->src = grub_cpu_to_be16 (sock->in_port); + tcph_ack->dst = grub_cpu_to_be16 (sock->out_port); + err = tcp_send (nb_ack, sock); + if (err) + { + grub_dprintf ("net", "error acking socket\n"); + grub_errno = GRUB_ERR_NONE; + } +} + +static void +ack (grub_net_tcp_socket_t sock) +{ + ack_real (sock, 0); +} + +static void +reset (grub_net_tcp_socket_t sock) +{ + ack_real (sock, 1); +} + +void +grub_net_tcp_retransmit (void) +{ + grub_net_tcp_socket_t sock; + grub_uint64_t ctime = grub_get_time_ms (); + grub_uint64_t limit_time = ctime - TCP_RETRANSMISSION_TIMEOUT; + + FOR_TCP_SOCKETS (sock) + { + struct unacked *unack; + for (unack = sock->unack_first; unack; unack = unack->next) + { + struct tcphdr *tcph; + grub_uint8_t *nbd; + grub_err_t err; + + if (unack->last_try > limit_time) + continue; + + if (unack->try_count > TCP_RETRANSMISSION_COUNT) + { + error (sock); + break; + } + unack->try_count++; + unack->last_try = ctime; + nbd = unack->nb->data; + tcph = (struct tcphdr *) nbd; + + if ((tcph->flags & grub_cpu_to_be16_compile_time (TCP_ACK)) + && tcph->ack != grub_cpu_to_be32 (sock->their_cur_seq)) + { + tcph->checksum = 0; + tcph->checksum = grub_net_ip_transport_checksum (unack->nb, + GRUB_NET_IP_TCP, + &sock->inf->address, + &sock->out_nla); + } + + err = grub_net_send_ip_packet (sock->inf, &(sock->out_nla), + &(sock->ll_target_addr), unack->nb, + GRUB_NET_IP_TCP); + unack->nb->data = nbd; + if (err) + { + grub_dprintf ("net", "TCP retransmit failed: %s\n", grub_errmsg); + grub_errno = GRUB_ERR_NONE; + } + } + } +} + +grub_uint16_t +grub_net_ip_transport_checksum (struct grub_net_buff *nb, + grub_uint16_t proto, + const grub_net_network_level_address_t *src, + const grub_net_network_level_address_t *dst) +{ + grub_uint16_t a, b = 0; + grub_uint32_t c; + a = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) nb->data, + nb->tail - nb->data)); + + switch (dst->type) + { + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4: + { + struct tcp_pseudohdr ph; + ph.src = src->ipv4; + ph.dst = dst->ipv4; + ph.zero = 0; + ph.tcp_length = grub_cpu_to_be16 (nb->tail - nb->data); + ph.proto = proto; + b = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) &ph, sizeof (ph))); + break; + } + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6: + { + struct tcp6_pseudohdr ph; + grub_memcpy (ph.src, src->ipv6, sizeof (ph.src)); + grub_memcpy (ph.dst, dst->ipv6, sizeof (ph.dst)); + grub_memset (ph.zero, 0, sizeof (ph.zero)); + ph.tcp_length = grub_cpu_to_be32 (nb->tail - nb->data); + ph.proto = proto; + b = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) &ph, sizeof (ph))); + break; + } + case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV: + b = 0; + break; + } + c = (grub_uint32_t) a + (grub_uint32_t) b; + if (c >= 0xffff) + c -= 0xffff; + return grub_cpu_to_be16 (~c); +} + +/* FIXME: overflow. */ +static int +cmp (const void *a__, const void *b__) +{ + struct grub_net_buff *a_ = *(struct grub_net_buff **) a__; + struct grub_net_buff *b_ = *(struct grub_net_buff **) b__; + struct tcphdr *a = (struct tcphdr *) a_->data; + struct tcphdr *b = (struct tcphdr *) b_->data; + /* We want the first elements to be on top. */ + if (grub_be_to_cpu32 (a->seqnr) < grub_be_to_cpu32 (b->seqnr)) + return +1; + if (grub_be_to_cpu32 (a->seqnr) > grub_be_to_cpu32 (b->seqnr)) + return -1; + return 0; +} + +static void +destroy_pq (grub_net_tcp_socket_t sock) +{ + struct grub_net_buff **nb_p; + while ((nb_p = grub_priority_queue_top (sock->pq))) + { + grub_netbuff_free (*nb_p); + grub_priority_queue_pop (sock->pq); + } + + grub_priority_queue_destroy (sock->pq); +} + +grub_err_t +grub_net_tcp_accept (grub_net_tcp_socket_t sock, + grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, + struct grub_net_buff *nb, + void *data), + void (*error_hook) (grub_net_tcp_socket_t sock, + void *data), + void (*fin_hook) (grub_net_tcp_socket_t sock, + void *data), + void *hook_data) +{ + struct grub_net_buff *nb_ack; + struct tcphdr *tcph; + grub_err_t err; + + sock->recv_hook = recv_hook; + sock->error_hook = error_hook; + sock->fin_hook = fin_hook; + sock->hook_data = hook_data; + nb_ack = grub_netbuff_alloc (sizeof (*tcph) + + GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (!nb_ack) + return grub_errno; + err = grub_netbuff_reserve (nb_ack, GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (err) + { + grub_netbuff_free (nb_ack); + return err; + } + + err = grub_netbuff_put (nb_ack, sizeof (*tcph)); + if (err) + { + grub_netbuff_free (nb_ack); + return err; + } + tcph = (void *) nb_ack->data; + tcph->ack = grub_cpu_to_be32 (sock->their_cur_seq); + tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN | TCP_ACK); + tcph->window = grub_cpu_to_be16 (sock->my_window); + tcph->urgent = 0; + sock->established = 1; + tcp_socket_register (sock); + err = tcp_send (nb_ack, sock); + if (err) + return err; + sock->my_cur_seq++; + return GRUB_ERR_NONE; +} + +grub_net_tcp_socket_t +grub_net_tcp_open (char *server, + grub_uint16_t out_port, + grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, + struct grub_net_buff *nb, + void *data), + void (*error_hook) (grub_net_tcp_socket_t sock, + void *data), + void (*fin_hook) (grub_net_tcp_socket_t sock, + void *data), + void *hook_data) +{ + grub_err_t err; + grub_net_network_level_address_t addr; + struct grub_net_network_level_interface *inf; + grub_net_network_level_address_t gateway; + grub_net_tcp_socket_t socket; + static grub_uint16_t in_port = 21550; + struct grub_net_buff *nb; + struct tcphdr *tcph; + int i; + grub_uint8_t *nbd; + grub_net_link_level_address_t ll_target_addr; + + err = grub_net_resolve_address (server, &addr); + if (err) + return NULL; + + if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4 + && addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP address"); + return NULL; + } + + err = grub_net_route_address (addr, &gateway, &inf); + if (err) + return NULL; + + err = grub_net_link_layer_resolve (inf, &gateway, &ll_target_addr); + if (err) + return NULL; + + socket = grub_zalloc (sizeof (*socket)); + if (socket == NULL) + return NULL; + + socket->out_port = out_port; + socket->inf = inf; + socket->out_nla = addr; + socket->ll_target_addr = ll_target_addr; + socket->in_port = in_port++; + socket->recv_hook = recv_hook; + socket->error_hook = error_hook; + socket->fin_hook = fin_hook; + socket->hook_data = hook_data; + + nb = grub_netbuff_alloc (sizeof (*tcph) + 128); + if (!nb) + return NULL; + err = grub_netbuff_reserve (nb, 128); + if (err) + { + grub_netbuff_free (nb); + return NULL; + } + + err = grub_netbuff_put (nb, sizeof (*tcph)); + if (err) + { + grub_netbuff_free (nb); + return NULL; + } + socket->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp); + if (!socket->pq) + { + grub_netbuff_free (nb); + return NULL; + } + + tcph = (void *) nb->data; + socket->my_start_seq = grub_get_time_ms (); + socket->my_cur_seq = socket->my_start_seq + 1; + socket->my_window = 8192; + tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq); + tcph->ack = grub_cpu_to_be32_compile_time (0); + tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN); + tcph->window = grub_cpu_to_be16 (socket->my_window); + tcph->urgent = 0; + tcph->src = grub_cpu_to_be16 (socket->in_port); + tcph->dst = grub_cpu_to_be16 (socket->out_port); + tcph->checksum = 0; + tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, + &socket->inf->address, + &socket->out_nla); + + tcp_socket_register (socket); + + nbd = nb->data; + for (i = 0; i < TCP_SYN_RETRANSMISSION_COUNT; i++) + { + int j; + nb->data = nbd; + err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla), + &(socket->ll_target_addr), nb, + GRUB_NET_IP_TCP); + if (err) + { + grub_list_remove (GRUB_AS_LIST (socket)); + grub_free (socket); + grub_netbuff_free (nb); + return NULL; + } + for (j = 0; (j < TCP_SYN_RETRANSMISSION_TIMEOUT / 50 + && !socket->established); j++) + grub_net_poll_cards (50); + if (socket->established) + break; + } + if (!socket->established) + { + grub_list_remove (GRUB_AS_LIST (socket)); + if (socket->they_reseted) + grub_error (GRUB_ERR_NET_PORT_CLOSED, "port closed"); + else + grub_error (GRUB_ERR_NET_NO_ANSWER, "no answer"); + + grub_netbuff_free (nb); + destroy_pq (socket); + grub_free (socket); + return NULL; + } + + grub_netbuff_free (nb); + return socket; +} + +grub_err_t +grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket, + struct grub_net_buff *nb, int push) +{ + struct tcphdr *tcph; + grub_err_t err; + grub_ssize_t fraglen; + COMPILE_TIME_ASSERT (sizeof (struct tcphdr) == GRUB_NET_TCP_HEADER_SIZE); + if (socket->out_nla.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + fraglen = (socket->inf->card->mtu - GRUB_NET_OUR_IPV4_HEADER_SIZE + - sizeof (*tcph)); + else + fraglen = 1280 - GRUB_NET_OUR_IPV6_HEADER_SIZE; + + while (nb->tail - nb->data > fraglen) + { + struct grub_net_buff *nb2; + + nb2 = grub_netbuff_alloc (fraglen + sizeof (*tcph) + + GRUB_NET_OUR_MAX_IP_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE); + if (!nb2) + return grub_errno; + err = grub_netbuff_reserve (nb2, GRUB_NET_MAX_LINK_HEADER_SIZE + + GRUB_NET_OUR_MAX_IP_HEADER_SIZE); + if (err) + return err; + err = grub_netbuff_put (nb2, sizeof (*tcph)); + if (err) + return err; + + tcph = (struct tcphdr *) nb2->data; + tcph->ack = grub_cpu_to_be32 (socket->their_cur_seq); + tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK); + tcph->window = grub_cpu_to_be16 (socket->my_window); + tcph->urgent = 0; + err = grub_netbuff_put (nb2, fraglen); + if (err) + return err; + grub_memcpy (tcph + 1, nb->data, fraglen); + err = grub_netbuff_pull (nb, fraglen); + if (err) + return err; + + err = tcp_send (nb2, socket); + if (err) + return err; + } + + err = grub_netbuff_push (nb, sizeof (*tcph)); + if (err) + return err; + + tcph = (struct tcphdr *) nb->data; + tcph->ack = grub_cpu_to_be32 (socket->their_cur_seq); + tcph->flags = (grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK) + | (push ? grub_cpu_to_be16_compile_time (TCP_PUSH) : 0)); + tcph->window = grub_cpu_to_be16 (socket->my_window); + tcph->urgent = 0; + return tcp_send (nb, socket); +} + +grub_err_t +grub_net_recv_tcp_packet (struct grub_net_buff *nb, + struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *source) +{ + struct tcphdr *tcph; + grub_net_tcp_socket_t sock; + grub_err_t err; + + /* Ignore broadcast. */ + if (!inf) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + tcph = (struct tcphdr *) nb->data; + if ((grub_be_to_cpu16 (tcph->flags) >> 12) < 5) + { + grub_dprintf ("net", "TCP header too short: %u\n", + grub_be_to_cpu16 (tcph->flags) >> 12); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (nb->tail - nb->data < (grub_ssize_t) ((grub_be_to_cpu16 (tcph->flags) + >> 12) * sizeof (grub_uint32_t))) + { + grub_dprintf ("net", "TCP packet too short: %" PRIuGRUB_SIZE "\n", + nb->tail - nb->data); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + FOR_TCP_SOCKETS (sock) + { + if (!(grub_be_to_cpu16 (tcph->dst) == sock->in_port + && grub_be_to_cpu16 (tcph->src) == sock->out_port + && inf == sock->inf + && grub_net_addr_cmp (source, &sock->out_nla) == 0)) + continue; + if (tcph->checksum) + { + grub_uint16_t chk, expected; + chk = tcph->checksum; + tcph->checksum = 0; + expected = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, + &sock->out_nla, + &sock->inf->address); + if (expected != chk) + { + grub_dprintf ("net", "Invalid TCP checksum. " + "Expected %x, got %x\n", + grub_be_to_cpu16 (expected), + grub_be_to_cpu16 (chk)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + tcph->checksum = chk; + } + + if ((grub_be_to_cpu16 (tcph->flags) & TCP_SYN) + && (grub_be_to_cpu16 (tcph->flags) & TCP_ACK) + && !sock->established) + { + sock->their_start_seq = grub_be_to_cpu32 (tcph->seqnr); + sock->their_cur_seq = sock->their_start_seq + 1; + sock->established = 1; + } + + if (grub_be_to_cpu16 (tcph->flags) & TCP_RST) + { + sock->they_reseted = 1; + + error (sock); + + grub_netbuff_free (nb); + + return GRUB_ERR_NONE; + } + + if (grub_be_to_cpu16 (tcph->flags) & TCP_ACK) + { + struct unacked *unack, *next; + grub_uint32_t acked = grub_be_to_cpu32 (tcph->ack); + for (unack = sock->unack_first; unack; unack = next) + { + grub_uint32_t seqnr; + struct tcphdr *unack_tcph; + next = unack->next; + seqnr = grub_be_to_cpu32 (((struct tcphdr *) unack->nb->data) + ->seqnr); + unack_tcph = (struct tcphdr *) unack->nb->data; + seqnr += (unack->nb->tail - unack->nb->data + - (grub_be_to_cpu16 (unack_tcph->flags) >> 12) * 4); + if (grub_be_to_cpu16 (unack_tcph->flags) & TCP_FIN) + seqnr++; + + if (seqnr > acked) + break; + grub_netbuff_free (unack->nb); + grub_free (unack); + } + sock->unack_first = unack; + if (!sock->unack_first) + sock->unack_last = NULL; + } + + if (grub_be_to_cpu32 (tcph->seqnr) < sock->their_cur_seq) + { + ack (sock); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + if (sock->i_reseted && (nb->tail - nb->data + - (grub_be_to_cpu16 (tcph->flags) + >> 12) * sizeof (grub_uint32_t)) > 0) + { + reset (sock); + } + + err = grub_priority_queue_push (sock->pq, &nb); + if (err) + { + grub_netbuff_free (nb); + return err; + } + + { + struct grub_net_buff **nb_top_p, *nb_top; + int do_ack = 0; + int just_closed = 0; + while (1) + { + nb_top_p = grub_priority_queue_top (sock->pq); + if (!nb_top_p) + return GRUB_ERR_NONE; + nb_top = *nb_top_p; + tcph = (struct tcphdr *) nb_top->data; + if (grub_be_to_cpu32 (tcph->seqnr) >= sock->their_cur_seq) + break; + grub_netbuff_free (nb_top); + grub_priority_queue_pop (sock->pq); + } + if (grub_be_to_cpu32 (tcph->seqnr) != sock->their_cur_seq) + return GRUB_ERR_NONE; + while (1) + { + nb_top_p = grub_priority_queue_top (sock->pq); + if (!nb_top_p) + break; + nb_top = *nb_top_p; + tcph = (struct tcphdr *) nb_top->data; + + if (grub_be_to_cpu32 (tcph->seqnr) != sock->their_cur_seq) + break; + grub_priority_queue_pop (sock->pq); + + err = grub_netbuff_pull (nb_top, (grub_be_to_cpu16 (tcph->flags) + >> 12) * sizeof (grub_uint32_t)); + if (err) + { + grub_netbuff_free (nb_top); + return err; + } + + sock->their_cur_seq += (nb_top->tail - nb_top->data); + if (grub_be_to_cpu16 (tcph->flags) & TCP_FIN) + { + sock->they_closed = 1; + just_closed = 1; + sock->their_cur_seq++; + do_ack = 1; + } + /* If there is data, puts packet in socket list. */ + if ((nb_top->tail - nb_top->data) > 0) + { + grub_net_put_packet (&sock->packs, nb_top); + do_ack = 1; + } + else + grub_netbuff_free (nb); + } + if (do_ack) + ack (sock); + while (sock->packs.first) + { + nb = sock->packs.first->nb; + if (sock->recv_hook) + sock->recv_hook (sock, sock->packs.first->nb, sock->hook_data); + else + grub_netbuff_free (nb); + grub_net_remove_packet (sock->packs.first); + } + + if (sock->fin_hook && just_closed) + sock->fin_hook (sock, sock->hook_data); + } + + return GRUB_ERR_NONE; + } + if (grub_be_to_cpu16 (tcph->flags) & TCP_SYN) + { + grub_net_tcp_listen_t listen; + + FOR_TCP_LISTENS (listen) + { + if (!(grub_be_to_cpu16 (tcph->dst) == listen->port + && (inf == listen->inf || listen->inf == NULL))) + continue; + sock = grub_zalloc (sizeof (*sock)); + if (sock == NULL) + return grub_errno; + + sock->out_port = grub_be_to_cpu16 (tcph->src); + sock->in_port = grub_be_to_cpu16 (tcph->dst); + sock->inf = inf; + sock->out_nla = *source; + sock->their_start_seq = grub_be_to_cpu32 (tcph->seqnr); + sock->their_cur_seq = sock->their_start_seq + 1; + sock->my_cur_seq = sock->my_start_seq = grub_get_time_ms (); + sock->my_window = 8192; + + sock->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), + cmp); + if (!sock->pq) + { + grub_netbuff_free (nb); + return grub_errno; + } + + err = listen->listen_hook (listen, sock, listen->hook_data); + + grub_netbuff_free (nb); + return err; + + } + } + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c new file mode 100644 index 000000000..9704a345b --- /dev/null +++ b/grub-core/net/tftp.c @@ -0,0 +1,434 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* IP port for the MTFTP server used for Intel's PXE */ +enum + { + MTFTP_SERVER_PORT = 75, + MTFTP_CLIENT_PORT = 76, + /* IP port for the TFTP server */ + TFTP_SERVER_PORT = 69 + }; + +enum + { + TFTP_DEFAULTSIZE_PACKET = 512, + }; + +enum + { + TFTP_CODE_EOF = 1, + TFTP_CODE_MORE = 2, + TFTP_CODE_ERROR = 3, + TFTP_CODE_BOOT = 4, + TFTP_CODE_CFG = 5 + }; + +enum + { + TFTP_RRQ = 1, + TFTP_WRQ = 2, + TFTP_DATA = 3, + TFTP_ACK = 4, + TFTP_ERROR = 5, + TFTP_OACK = 6 + }; + +enum + { + TFTP_EUNDEF = 0, /* not defined */ + TFTP_ENOTFOUND = 1, /* file not found */ + TFTP_EACCESS = 2, /* access violation */ + TFTP_ENOSPACE = 3, /* disk full or allocation exceeded */ + TFTP_EBADOP = 4, /* illegal TFTP operation */ + TFTP_EBADID = 5, /* unknown transfer ID */ + TFTP_EEXISTS = 6, /* file already exists */ + TFTP_ENOUSER = 7 /* no such user */ + }; + +struct tftphdr { + grub_uint16_t opcode; + union { + grub_int8_t rrq[TFTP_DEFAULTSIZE_PACKET]; + struct { + grub_uint16_t block; + grub_int8_t download[0]; + } data; + struct { + grub_uint16_t block; + } ack; + struct { + grub_uint16_t errcode; + grub_int8_t errmsg[TFTP_DEFAULTSIZE_PACKET]; + } err; + struct { + grub_int8_t data[TFTP_DEFAULTSIZE_PACKET+2]; + } oack; + } u; +} __attribute__ ((packed)) ; + + +typedef struct tftp_data +{ + grub_uint64_t file_size; + grub_uint64_t block; + grub_uint32_t block_size; + int have_oack; + grub_net_udp_socket_t sock; + grub_priority_queue_t pq; +} *tftp_data_t; + +static int +cmp (const void *a__, const void *b__) +{ + struct grub_net_buff *a_ = *(struct grub_net_buff **) a__; + struct grub_net_buff *b_ = *(struct grub_net_buff **) b__; + struct tftphdr *a = (struct tftphdr *) a_->data; + struct tftphdr *b = (struct tftphdr *) b_->data; + /* We want the first elements to be on top. */ + if (grub_be_to_cpu16 (a->u.data.block) < grub_be_to_cpu16 (b->u.data.block)) + return +1; + if (grub_be_to_cpu16 (a->u.data.block) > grub_be_to_cpu16 (b->u.data.block)) + return -1; + return 0; +} + +static grub_err_t +ack (grub_net_udp_socket_t sock, grub_uint16_t block) +{ + struct tftphdr *tftph_ack; + grub_uint8_t nbdata[512]; + struct grub_net_buff nb_ack; + grub_err_t err; + + nb_ack.head = nbdata; + nb_ack.end = nbdata + sizeof (nbdata); + grub_netbuff_clear (&nb_ack); + grub_netbuff_reserve (&nb_ack, 512); + err = grub_netbuff_push (&nb_ack, sizeof (tftph_ack->opcode) + + sizeof (tftph_ack->u.ack.block)); + if (err) + return err; + + tftph_ack = (struct tftphdr *) nb_ack.data; + tftph_ack->opcode = grub_cpu_to_be16 (TFTP_ACK); + tftph_ack->u.ack.block = block; + + err = grub_net_send_udp_packet (sock, &nb_ack); + return err; +} + +static grub_err_t +tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + struct grub_net_buff *nb, + void *f) +{ + grub_file_t file = f; + struct tftphdr *tftph = (void *) nb->data; + tftp_data_t data = file->data; + grub_err_t err; + grub_uint8_t *ptr; + + if (nb->tail - nb->data < (grub_ssize_t) sizeof (tftph->opcode)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "TFTP packet too small"); + + tftph = (struct tftphdr *) nb->data; + switch (grub_be_to_cpu16 (tftph->opcode)) + { + case TFTP_OACK: + data->block_size = TFTP_DEFAULTSIZE_PACKET; + data->have_oack = 1; + for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail;) + { + if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0) + data->file_size = grub_strtoul ((char *) ptr + sizeof ("tsize\0") + - 1, 0, 0); + if (grub_memcmp (ptr, "blksize\0", sizeof ("blksize\0") - 1) == 0) + data->block_size = grub_strtoul ((char *) ptr + sizeof ("blksize\0") + - 1, 0, 0); + while (ptr < nb->tail && *ptr) + ptr++; + ptr++; + } + data->block = 0; + grub_netbuff_free (nb); + err = ack (data->sock, 0); + if (err) + return err; + return GRUB_ERR_NONE; + case TFTP_DATA: + if (nb->tail - nb->data < (grub_ssize_t) (sizeof (tftph->opcode) + + sizeof (tftph->u.data.block))) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "TFTP packet too small"); + err = ack (data->sock, tftph->u.data.block); + if (err) + return err; + + err = grub_priority_queue_push (data->pq, &nb); + if (err) + return err; + + { + struct grub_net_buff **nb_top_p, *nb_top; + while (1) + { + nb_top_p = grub_priority_queue_top (data->pq); + if (!nb_top_p) + return GRUB_ERR_NONE; + nb_top = *nb_top_p; + tftph = (struct tftphdr *) nb_top->data; + if (grub_be_to_cpu16 (tftph->u.data.block) >= data->block + 1) + break; + grub_priority_queue_pop (data->pq); + } + if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1) + { + unsigned size; + + grub_priority_queue_pop (data->pq); + + err = grub_netbuff_pull (nb_top, sizeof (tftph->opcode) + + sizeof (tftph->u.data.block)); + if (err) + return err; + size = nb_top->tail - nb_top->data; + + data->block++; + if (size < data->block_size) + { + file->device->net->eof = 1; + grub_net_udp_close (data->sock); + data->sock = NULL; + } + /* Prevent garbage in broken cards. Is it still necessary + given that IP implementation has been fixed? + */ + if (size > data->block_size) + { + err = grub_netbuff_unput (nb_top, size - data->block_size); + if (err) + return err; + } + /* If there is data, puts packet in socket list. */ + if ((nb_top->tail - nb_top->data) > 0) + grub_net_put_packet (&file->device->net->packs, nb_top); + else + grub_netbuff_free (nb); + } + } + return GRUB_ERR_NONE; + case TFTP_ERROR: + grub_netbuff_free (nb); + return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg); + default: + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } +} + +static void +destroy_pq (tftp_data_t data) +{ + struct grub_net_buff **nb_p; + while ((nb_p = grub_priority_queue_top (data->pq))) + grub_netbuff_free (*nb_p); + + grub_priority_queue_destroy (data->pq); +} + +static grub_err_t +tftp_open (struct grub_file *file, const char *filename) +{ + struct tftphdr *tftph; + char *rrq; + int i; + int rrqlen; + int hdrlen; + grub_uint8_t open_data[1500]; + struct grub_net_buff nb; + tftp_data_t data; + grub_err_t err; + grub_uint8_t *nbd; + grub_net_network_level_address_t addr; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return grub_errno; + + nb.head = open_data; + nb.end = open_data + sizeof (open_data); + grub_netbuff_clear (&nb); + + grub_netbuff_reserve (&nb, 1500); + err = grub_netbuff_push (&nb, sizeof (*tftph)); + if (err) + return err; + + tftph = (struct tftphdr *) nb.data; + + rrq = (char *) tftph->u.rrq; + rrqlen = 0; + + tftph->opcode = grub_cpu_to_be16 (TFTP_RRQ); + grub_strcpy (rrq, filename); + rrqlen += grub_strlen (filename) + 1; + rrq += grub_strlen (filename) + 1; + + grub_strcpy (rrq, "octet"); + rrqlen += grub_strlen ("octet") + 1; + rrq += grub_strlen ("octet") + 1; + + grub_strcpy (rrq, "blksize"); + rrqlen += grub_strlen ("blksize") + 1; + rrq += grub_strlen ("blksize") + 1; + + grub_strcpy (rrq, "1024"); + rrqlen += grub_strlen ("1024") + 1; + rrq += grub_strlen ("1024") + 1; + + grub_strcpy (rrq, "tsize"); + rrqlen += grub_strlen ("tsize") + 1; + rrq += grub_strlen ("tsize") + 1; + + grub_strcpy (rrq, "0"); + rrqlen += grub_strlen ("0") + 1; + rrq += grub_strlen ("0") + 1; + hdrlen = sizeof (tftph->opcode) + rrqlen; + + err = grub_netbuff_unput (&nb, nb.tail - (nb.data + hdrlen)); + if (err) + return err; + + file->not_easily_seekable = 1; + file->data = data; + + data->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp); + if (!data->pq) + return grub_errno; + + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { + destroy_pq (data); + return err; + } + + data->sock = grub_net_udp_open (addr, + TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { + destroy_pq (data); + return grub_errno; + } + + /* Receive OACK packet. */ + nbd = nb.data; + for (i = 0; i < GRUB_NET_TRIES; i++) + { + nb.data = nbd; + err = grub_net_send_udp_packet (data->sock, &nb); + if (err) + { + grub_net_udp_close (data->sock); + destroy_pq (data); + return err; + } + grub_net_poll_cards (GRUB_NET_INTERVAL); + if (data->have_oack) + break; + } + + if (!data->have_oack) + { + grub_net_udp_close (data->sock); + destroy_pq (data); + return grub_error (GRUB_ERR_TIMEOUT, "Time out opening tftp."); + } + file->size = data->file_size; + + return GRUB_ERR_NONE; +} + +static grub_err_t +tftp_close (struct grub_file *file) +{ + tftp_data_t data = file->data; + + if (data->sock) + { + grub_uint8_t nbdata[512]; + grub_err_t err; + struct grub_net_buff nb_err; + struct tftphdr *tftph; + + nb_err.head = nbdata; + nb_err.end = nbdata + sizeof (nbdata); + + grub_netbuff_clear (&nb_err); + grub_netbuff_reserve (&nb_err, 512); + err = grub_netbuff_push (&nb_err, sizeof (tftph->opcode) + + sizeof (tftph->u.err.errcode) + + sizeof ("closed")); + if (!err) + { + tftph = (struct tftphdr *) nb_err.data; + tftph->opcode = grub_cpu_to_be16 (TFTP_ERROR); + tftph->u.err.errcode = grub_cpu_to_be16 (TFTP_EUNDEF); + grub_memcpy (tftph->u.err.errmsg, "closed", sizeof ("closed")); + + err = grub_net_send_udp_packet (data->sock, &nb_err); + } + if (err) + grub_print_error (); + grub_net_udp_close (data->sock); + } + destroy_pq (data); + grub_free (data); + return GRUB_ERR_NONE; +} + +static struct grub_net_app_protocol grub_tftp_protocol = + { + .name = "tftp", + .open = tftp_open, + .close = tftp_close + }; + +GRUB_MOD_INIT (tftp) +{ + grub_net_app_level_register (&grub_tftp_protocol); +} + +GRUB_MOD_FINI (tftp) +{ + grub_net_app_level_unregister (&grub_tftp_protocol); +} diff --git a/grub-core/net/udp.c b/grub-core/net/udp.c new file mode 100644 index 000000000..afe5de0c9 --- /dev/null +++ b/grub-core/net/udp.c @@ -0,0 +1,211 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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 + +struct grub_net_udp_socket +{ + struct grub_net_udp_socket *next; + struct grub_net_udp_socket **prev; + + enum { GRUB_NET_SOCKET_START, + GRUB_NET_SOCKET_ESTABLISHED, + GRUB_NET_SOCKET_CLOSED } status; + int in_port; + int out_port; + grub_err_t (*recv_hook) (grub_net_udp_socket_t sock, struct grub_net_buff *nb, + void *recv); + void *recv_hook_data; + grub_net_network_level_address_t out_nla; + grub_net_link_level_address_t ll_target_addr; + struct grub_net_network_level_interface *inf; +}; + +static struct grub_net_udp_socket *udp_sockets; + +#define FOR_UDP_SOCKETS(var) for (var = udp_sockets; var; var = var->next) + +static inline void +udp_socket_register (grub_net_udp_socket_t sock) +{ + grub_list_push (GRUB_AS_LIST_P (&udp_sockets), + GRUB_AS_LIST (sock)); +} + +void +grub_net_udp_close (grub_net_udp_socket_t sock) +{ + grub_list_remove (GRUB_AS_LIST (sock)); + grub_free (sock); +} + +grub_net_udp_socket_t +grub_net_udp_open (grub_net_network_level_address_t addr, + grub_uint16_t out_port, + grub_err_t (*recv_hook) (grub_net_udp_socket_t sock, + struct grub_net_buff *nb, + void *data), + void *recv_hook_data) +{ + grub_err_t err; + struct grub_net_network_level_interface *inf; + grub_net_network_level_address_t gateway; + grub_net_udp_socket_t socket; + static int in_port = 25300; + grub_net_link_level_address_t ll_target_addr; + + if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4 + && addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP address"); + return NULL; + } + + err = grub_net_route_address (addr, &gateway, &inf); + if (err) + return NULL; + + err = grub_net_link_layer_resolve (inf, &gateway, &ll_target_addr); + if (err) + return NULL; + + socket = grub_zalloc (sizeof (*socket)); + if (socket == NULL) + return NULL; + + socket->out_port = out_port; + socket->inf = inf; + socket->out_nla = addr; + socket->ll_target_addr = ll_target_addr; + socket->in_port = in_port++; + socket->status = GRUB_NET_SOCKET_START; + socket->recv_hook = recv_hook; + socket->recv_hook_data = recv_hook_data; + + udp_socket_register (socket); + + return socket; +} + +grub_err_t +grub_net_send_udp_packet (const grub_net_udp_socket_t socket, + struct grub_net_buff *nb) +{ + struct udphdr *udph; + grub_err_t err; + + COMPILE_TIME_ASSERT (GRUB_NET_UDP_HEADER_SIZE == sizeof (*udph)); + + err = grub_netbuff_push (nb, sizeof (*udph)); + if (err) + return err; + + udph = (struct udphdr *) nb->data; + udph->src = grub_cpu_to_be16 (socket->in_port); + udph->dst = grub_cpu_to_be16 (socket->out_port); + + udph->chksum = 0; + udph->len = grub_cpu_to_be16 (nb->tail - nb->data); + + udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, + &socket->inf->address, + &socket->out_nla); + + return grub_net_send_ip_packet (socket->inf, &(socket->out_nla), + &(socket->ll_target_addr), nb, + GRUB_NET_IP_UDP); +} + +grub_err_t +grub_net_recv_udp_packet (struct grub_net_buff *nb, + struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *source) +{ + struct udphdr *udph; + grub_net_udp_socket_t sock; + grub_err_t err; + + /* Ignore broadcast. */ + if (!inf) + { + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + udph = (struct udphdr *) nb->data; + if (nb->tail - nb->data < (grub_ssize_t) sizeof (*udph)) + { + grub_dprintf ("net", "UDP packet too short: %" PRIuGRUB_SIZE "\n", + nb->tail - nb->data); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + + FOR_UDP_SOCKETS (sock) + { + if (grub_be_to_cpu16 (udph->dst) == sock->in_port + && inf == sock->inf + && grub_net_addr_cmp (source, &sock->out_nla) == 0 + && (sock->status == GRUB_NET_SOCKET_START + || grub_be_to_cpu16 (udph->src) == sock->out_port)) + { + if (udph->chksum) + { + grub_uint16_t chk, expected; + chk = udph->chksum; + udph->chksum = 0; + expected = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, + &sock->out_nla, + &sock->inf->address); + if (expected != chk) + { + grub_dprintf ("net", "Invalid UDP checksum. " + "Expected %x, got %x\n", + grub_be_to_cpu16 (expected), + grub_be_to_cpu16 (chk)); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + udph->chksum = chk; + } + + if (sock->status == GRUB_NET_SOCKET_START) + { + sock->out_port = grub_be_to_cpu16 (udph->src); + sock->status = GRUB_NET_SOCKET_ESTABLISHED; + } + + err = grub_netbuff_pull (nb, sizeof (*udph)); + if (err) + return err; + + /* App protocol remove its own reader. */ + if (sock->recv_hook) + sock->recv_hook (sock, nb, sock->recv_hook_data); + else + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + } + grub_netbuff_free (nb); + return GRUB_ERR_NONE; +} diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c index 459d4cdbd..499eb6c9d 100644 --- a/grub-core/normal/auth.c +++ b/grub-core/normal/auth.c @@ -28,13 +28,14 @@ struct grub_auth_user { struct grub_auth_user *next; + struct grub_auth_user **prev; char *name; grub_auth_callback_t callback; void *arg; int authenticated; }; -struct grub_auth_user *users = NULL; +static struct grub_auth_user *users = NULL; grub_err_t grub_auth_register_authentication (const char *user, @@ -73,7 +74,7 @@ grub_auth_unregister_authentication (const char *user) if (!cur->authenticated) { grub_free (cur->name); - grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur)); + grub_list_remove (GRUB_AS_LIST (cur)); grub_free (cur); } else @@ -121,7 +122,7 @@ grub_auth_deauthenticate (const char *user) if (!cur->callback) { grub_free (cur->name); - grub_list_remove (GRUB_AS_LIST_P (&users), GRUB_AS_LIST (cur)); + grub_list_remove (GRUB_AS_LIST (cur)); grub_free (cur); } else @@ -201,7 +202,6 @@ grub_auth_check_authentication (const char *userlist) { char login[1024]; struct grub_auth_user *cur = NULL; - grub_err_t err; static unsigned long punishment_delay = 1; char entered[GRUB_AUTH_MAX_PASSLEN]; struct grub_auth_user *user; @@ -233,7 +233,7 @@ grub_auth_check_authentication (const char *userlist) if (!cur || ! cur->callback) goto access_denied; - err = cur->callback (login, entered, cur->arg); + cur->callback (login, entered, cur->arg); if (is_authenticated (userlist)) { punishment_delay = 1; diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c index b7f775c4f..2b8246662 100644 --- a/grub-core/normal/charset.c +++ b/grub-core/normal/charset.c @@ -42,13 +42,6 @@ Most underline diacritics aren't displayed in gfxterm */ -/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE - bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. - Return the number of characters converted. DEST must be able to hold - at least DESTSIZE characters. If an invalid sequence is found, return -1. - If SRCEND is not NULL, then *SRCEND is set to the next byte after the - last byte used in SRC. */ - #include #include #include @@ -60,6 +53,58 @@ #include "widthspec.h" #endif +int +grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count) +{ + if (*count) + { + if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) + { + *count = 0; + /* invalid */ + return 0; + } + else + { + *code <<= 6; + *code |= (c & GRUB_UINT8_6_TRAILINGBITS); + (*count)--; + return 1; + } + } + + if ((c & GRUB_UINT8_1_LEADINGBIT) == 0) + { + *code = c; + return 1; + } + if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS) + { + *count = 1; + *code = c & GRUB_UINT8_5_TRAILINGBITS; + return 1; + } + if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS) + { + *count = 2; + *code = c & GRUB_UINT8_4_TRAILINGBITS; + return 1; + } + if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS) + { + *count = 3; + *code = c & GRUB_UINT8_3_TRAILINGBITS; + return 1; + } + return 0; +} + +/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE + bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. + Return the number of characters converted. DEST must be able to hold + at least DESTSIZE characters. If an invalid sequence is found, return -1. + If SRCEND is not NULL, then *SRCEND is set to the next byte after the + last byte used in SRC. */ grub_ssize_t grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, @@ -74,74 +119,33 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, while (srcsize && destsize) { - grub_uint32_t c = *src++; + int was_count = count; if (srcsize != (grub_size_t)-1) srcsize--; - if (count) + if (!grub_utf8_process (*src++, &code, &count)) { - if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) - { - /* invalid */ - return -1; - } - else - { - code <<= 6; - code |= (c & GRUB_UINT8_6_TRAILINGBITS); - count--; - } + code = '?'; + count = 0; + /* Character c may be valid, don't eat it. */ + if (was_count) + src--; + } + if (count != 0) + continue; + if (code == 0) + break; + if (destsize < 2 && code >= GRUB_UCS2_LIMIT) + break; + if (code >= GRUB_UCS2_LIMIT) + { + *p++ = GRUB_UTF16_UPPER_SURROGATE (code); + *p++ = GRUB_UTF16_LOWER_SURROGATE (code); + destsize -= 2; } else { - if (c == 0) - break; - - if ((c & GRUB_UINT8_1_LEADINGBIT) == 0) - code = c; - else if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS) - { - count = 1; - code = c & GRUB_UINT8_5_TRAILINGBITS; - } - else if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS) - { - count = 2; - code = c & GRUB_UINT8_4_TRAILINGBITS; - } - else if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS) - { - count = 3; - code = c & GRUB_UINT8_3_TRAILINGBITS; - } - else if ((c & GRUB_UINT8_6_LEADINGBITS) == GRUB_UINT8_5_LEADINGBITS) - { - count = 4; - code = c & GRUB_UINT8_2_TRAILINGBITS; - } - else if ((c & GRUB_UINT8_7_LEADINGBITS) == GRUB_UINT8_6_LEADINGBITS) - { - count = 5; - code = c & GRUB_UINT8_1_TRAILINGBIT; - } - else - return -1; - } - - if (count == 0) - { - if (destsize < 2 && code >= GRUB_UCS2_LIMIT) - break; - if (code >= GRUB_UCS2_LIMIT) - { - *p++ = GRUB_UTF16_UPPER_SURROGATE (code); - *p++ = GRUB_UTF16_LOWER_SURROGATE (code); - destsize -= 2; - } - else - { - *p++ = code; - destsize--; - } + *p++ = code; + destsize--; } } @@ -150,9 +154,56 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, return p - dest; } +/* Returns -2 if not enough space, -1 on invalid character. */ +grub_ssize_t +grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend, + grub_uint32_t code) +{ + if (dest >= destend) + return -2; + if (code <= 0x007F) + { + *dest++ = code; + return 1; + } + if (code <= 0x07FF) + { + if (dest + 1 >= destend) + return -2; + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + return 2; + } + if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + { + /* No surrogates in UCS-4... */ + return -1; + } + if (code < 0x10000) + { + if (dest + 2 >= destend) + return -2; + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + return 3; + } + { + if (dest + 3 >= destend) + return -2; + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + return 4; + } + +} + /* Convert UCS-4 to UTF-8. */ void -grub_ucs4_to_utf8 (grub_uint32_t *src, grub_size_t size, +grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size, grub_uint8_t *dest, grub_size_t destsize) { /* Keep last char for \0. */ @@ -161,40 +212,26 @@ grub_ucs4_to_utf8 (grub_uint32_t *src, grub_size_t size, while (size-- && dest < destend) { grub_uint32_t code = *src++; - - if (code <= 0x007F) - *dest++ = code; - else if (code <= 0x07FF) + grub_ssize_t s; + s = grub_encode_utf8_character (dest, destend, code); + if (s == -2) + break; + if (s == -1) { - if (dest + 1 >= destend) - break; - *dest++ = (code >> 6) | 0xC0; - *dest++ = (code & 0x3F) | 0x80; - } - else if ((code >= 0xDC00 && code <= 0xDFFF) - || (code >= 0xD800 && code <= 0xDBFF)) - { - /* No surrogates in UCS-4... */ *dest++ = '?'; + continue; } - else - { - if (dest + 2 >= destend) - break; - *dest++ = (code >> 12) | 0xE0; - *dest++ = ((code >> 6) & 0x3F) | 0x80; - *dest++ = (code & 0x3F) | 0x80; - } + dest += s; } *dest = 0; } /* Convert UCS-4 to UTF-8. */ char * -grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size) +grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size) { grub_size_t remaining; - grub_uint32_t *ptr; + const grub_uint32_t *ptr; grub_size_t cnt = 0; grub_uint8_t *ret; @@ -212,8 +249,10 @@ grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size) || (code >= 0xD800 && code <= 0xDBFF)) /* No surrogates in UCS-4... */ cnt++; - else + else if (code < 0x10000) cnt += 3; + else + cnt += 4; } cnt++; @@ -229,63 +268,21 @@ grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size) int grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize) { - grub_uint32_t code = 0; int count = 0; + grub_uint32_t code = 0; while (srcsize) { - grub_uint32_t c = *src++; if (srcsize != (grub_size_t)-1) srcsize--; - if (count) - { - if ((c & 0xc0) != 0x80) - { - /* invalid */ - return 0; - } - else - { - code <<= 6; - code |= (c & 0x3f); - count--; - } - } - else - { - if (c == 0) - break; - - if ((c & 0x80) == 0x00) - code = c; - else if ((c & 0xe0) == 0xc0) - { - count = 1; - code = c & 0x1f; - } - else if ((c & 0xf0) == 0xe0) - { - count = 2; - code = c & 0x0f; - } - else if ((c & 0xf8) == 0xf0) - { - count = 3; - code = c & 0x07; - } - else if ((c & 0xfc) == 0xf8) - { - count = 4; - code = c & 0x03; - } - else if ((c & 0xfe) == 0xfc) - { - count = 5; - code = c & 0x01; - } - else - return 0; - } + if (!grub_utf8_process (*src++, &code, &count)) + return 0; + if (count != 0) + continue; + if (code == 0) + return 1; + if (code > GRUB_UNICODE_LAST_VALID) + return 0; } return 1; @@ -331,73 +328,23 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, while (srcsize && destsize) { - grub_uint32_t c = *src++; + int was_count = count; if (srcsize != (grub_size_t)-1) srcsize--; - if (count) + if (!grub_utf8_process (*src++, &code, &count)) { - if ((c & 0xc0) != 0x80) - { - /* invalid */ - code = '?'; - /* Character c may be valid, don't eat it. */ - src--; - if (srcsize != (grub_size_t)-1) - srcsize++; - count = 0; - } - else - { - code <<= 6; - code |= (c & 0x3f); - count--; - } - } - else - { - if (c == 0) - break; - - if ((c & 0x80) == 0x00) - code = c; - else if ((c & 0xe0) == 0xc0) - { - count = 1; - code = c & 0x1f; - } - else if ((c & 0xf0) == 0xe0) - { - count = 2; - code = c & 0x0f; - } - else if ((c & 0xf8) == 0xf0) - { - count = 3; - code = c & 0x07; - } - else if ((c & 0xfc) == 0xf8) - { - count = 4; - code = c & 0x03; - } - else if ((c & 0xfe) == 0xfc) - { - count = 5; - code = c & 0x01; - } - else - { - /* invalid */ - code = '?'; - count = 0; - } - } - - if (count == 0) - { - *p++ = code; - destsize--; + code = '?'; + count = 0; + /* Character c may be valid, don't eat it. */ + if (was_count) + src--; } + if (count != 0) + continue; + if (code == 0) + break; + *p++ = code; + destsize--; } if (srcend) @@ -419,9 +366,9 @@ unpack_join (void) grub_errno = GRUB_ERR_NONE; return; } - for (cur = grub_unicode_compact; cur->end; cur++) - for (i = cur->start; i <= cur->end - && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) + for (cur = grub_unicode_compact; cur->len; cur++) + for (i = cur->start; i < cur->start + (unsigned) cur->len + && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) join_types[i] = cur->join_type; } @@ -439,9 +386,9 @@ unpack_bidi (void) grub_errno = GRUB_ERR_NONE; return; } - for (cur = grub_unicode_compact; cur->end; cur++) - for (i = cur->start; i <= cur->end - && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) + for (cur = grub_unicode_compact; cur->len; cur++) + for (i = cur->start; i < cur->start + (unsigned) cur->len + && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) if (cur->bidi_mirror) bidi_types[i] = cur->bidi_type | 0x80; else @@ -459,8 +406,8 @@ get_bidi_type (grub_uint32_t c) if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) return bidi_types[c] & 0x7f; - for (cur = grub_unicode_compact; cur->end; cur++) - if (cur->start <= c && c <= cur->end) + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) return cur->bidi_type; return GRUB_BIDI_TYPE_L; @@ -477,8 +424,8 @@ get_join_type (grub_uint32_t c) if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) return join_types[c]; - for (cur = grub_unicode_compact; cur->end; cur++) - if (cur->start <= c && c <= cur->end) + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) return cur->join_type; return GRUB_JOIN_TYPE_NONJOINING; @@ -495,8 +442,8 @@ is_mirrored (grub_uint32_t c) if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) return !!(bidi_types[c] & 0x80); - for (cur = grub_unicode_compact; cur->end; cur++) - if (cur->start <= c && c <= cur->end) + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) return cur->bidi_mirror; return 0; @@ -513,8 +460,8 @@ grub_unicode_get_comb_type (grub_uint32_t c) unsigned i; comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); if (comb_types) - for (cur = grub_unicode_compact; cur->end; cur++) - for (i = cur->start; i <= cur->end + for (cur = grub_unicode_compact; cur->len; cur++) + for (i = cur->start; i < cur->start + (unsigned) cur->len && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) comb_types[i] = cur->comb_type; else @@ -524,8 +471,8 @@ grub_unicode_get_comb_type (grub_uint32_t c) if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) return comb_types[c]; - for (cur = grub_unicode_compact; cur->end; cur++) - if (cur->start <= c && c <= cur->end) + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) return cur->comb_type; return GRUB_UNICODE_COMB_NONE; @@ -958,6 +905,10 @@ grub_bidi_line_logical_to_visual (const grub_uint32_t *logical, continue; } + /* The tags: deprecated, never used. */ + if (*lptr >= GRUB_UNICODE_TAG_START && *lptr <= GRUB_UNICODE_TAG_END) + continue; + p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr, &visual[visual_len]); diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c index b8c20d91c..ea06b4cc7 100644 --- a/grub-core/normal/cmdline.c +++ b/grub-core/normal/cmdline.c @@ -240,7 +240,7 @@ grub_cmdline_get (const char *prompt) grub_term_gotoxy (cl_term->term, cl_term->xpos, cl_term->ypos); } - void cl_set_pos_all () + void cl_set_pos_all (void) { unsigned i; for (i = 0; i < nterms; i++) @@ -500,8 +500,7 @@ grub_cmdline_get (const char *prompt) case GRUB_TERM_CTRL | 'k': if (lpos < llen) { - if (kill_buf) - grub_free (kill_buf); + grub_free (kill_buf); kill_buf = grub_malloc ((llen - lpos + 1) * sizeof (grub_uint32_t)); @@ -566,8 +565,7 @@ grub_cmdline_get (const char *prompt) { grub_size_t n = lpos; - if (kill_buf) - grub_free (kill_buf); + grub_free (kill_buf); kill_buf = grub_malloc (n + 1); if (grub_errno) diff --git a/grub-core/normal/color.c b/grub-core/normal/color.c index 2e6c80b94..06f1a877c 100644 --- a/grub-core/normal/color.c +++ b/grub-core/normal/color.c @@ -23,7 +23,7 @@ #include /* Borrowed from GRUB Legacy */ -static char *color_list[16] = +static const char *color_list[16] = { "black", "blue", diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c index 67676dfe4..2a802390f 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -26,9 +26,10 @@ #include #include #include +#include /* The current word. */ -static char *current_word; +static const char *current_word; /* The matched string. */ static char *match; @@ -86,6 +87,7 @@ add_completion (const char *completion, const char *extra, s++; t++; } + s = match + grub_getend (match, s); *s = '\0'; } @@ -159,29 +161,43 @@ iterate_dev (const char *devname) /* Complete the partition part. */ dev = grub_device_open (devname); - if (dev) + if (!dev) { - char tmp[grub_strlen (devname) + sizeof (",")]; - - grub_memcpy (tmp, devname, grub_strlen (devname)); - - if (grub_strcmp (devname, current_word) == 0) - { - if (add_completion (devname, ")", GRUB_COMPLETION_TYPE_PARTITION)) - return 1; - - if (dev->disk) - if (grub_partition_iterate (dev->disk, iterate_partition)) - return 1; - } - else - { - grub_memcpy (tmp + grub_strlen (devname), "", sizeof ("")); - if (add_completion (tmp, "", GRUB_COMPLETION_TYPE_DEVICE)) - return 1; - } + grub_errno = GRUB_ERR_NONE; + return 0; } + { + char tmp[grub_strlen (devname) + sizeof (",")]; + grub_memcpy (tmp, devname, grub_strlen (devname)); + + if (grub_strcmp (devname, current_word) == 0) + { + if (add_completion (devname, ")", GRUB_COMPLETION_TYPE_PARTITION)) + { + grub_device_close (dev); + return 1; + } + + if (dev->disk) + if (grub_partition_iterate (dev->disk, iterate_partition)) + { + grub_device_close (dev); + return 1; + } + } + else + { + grub_memcpy (tmp + grub_strlen (devname), "", sizeof ("")); + if (add_completion (tmp, "", GRUB_COMPLETION_TYPE_DEVICE)) + { + grub_device_close (dev); + return 1; + } + } + } + + grub_device_close (dev); grub_errno = GRUB_ERR_NONE; return 0; } diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c index 75beeefda..581316603 100644 --- a/grub-core/normal/context.c +++ b/grub-core/normal/context.c @@ -31,8 +31,8 @@ struct menu_pointer struct menu_pointer *prev; }; -struct menu_pointer initial_menu; -struct menu_pointer *current_menu = &initial_menu; +static struct menu_pointer initial_menu; +static struct menu_pointer *current_menu = &initial_menu; void grub_env_unset_menu (void) @@ -148,7 +148,7 @@ grub_env_context_close (void) grub_err_t grub_env_extractor_close (int source) { - grub_menu_t menu, menu2; + grub_menu_t menu = NULL; grub_menu_entry_t *last; grub_err_t err; @@ -161,6 +161,7 @@ grub_env_extractor_close (int source) if (source) { + grub_menu_t menu2; menu2 = grub_env_get_menu (); last = &menu2->entry_list; @@ -175,26 +176,6 @@ grub_env_extractor_close (int source) return err; } -grub_err_t -grub_env_export (const char *name) -{ - struct grub_env_var *var; - - var = grub_env_find (name); - if (! var) - { - grub_err_t err; - - err = grub_env_set (name, ""); - if (err) - return err; - var = grub_env_find (name); - } - var->global = 1; - - return GRUB_ERR_NONE; -} - static grub_command_t export_cmd; static grub_err_t @@ -216,9 +197,6 @@ grub_cmd_export (struct grub_command *cmd __attribute__ ((unused)), void grub_context_init (void) { - grub_env_export ("root"); - grub_env_export ("prefix"); - export_cmd = grub_register_command ("export", grub_cmd_export, N_("ENVVAR [ENVVAR] ..."), N_("Export variables.")); diff --git a/grub-core/normal/crypto.c b/grub-core/normal/crypto.c index 465c9f81d..8e61255f3 100644 --- a/grub-core/normal/crypto.c +++ b/grub-core/normal/crypto.c @@ -31,14 +31,21 @@ struct load_spec char *modname; }; -struct load_spec *crypto_specs = NULL; +static struct load_spec *crypto_specs = NULL; static void grub_crypto_autoload (const char *name) { struct load_spec *cur; grub_dl_t mod; - + static int depth = 0; + + /* Some bufio of filesystems may want some crypto modules. + It may result in infinite recursion. Hence this check. */ + if (depth) + return; + depth++; + for (cur = crypto_specs; cur; cur = cur->next) if (grub_strcasecmp (name, cur->name) == 0) { @@ -47,6 +54,7 @@ grub_crypto_autoload (const char *name) grub_dl_ref (mod); grub_errno = GRUB_ERR_NONE; } + depth--; } static void diff --git a/grub-core/normal/datetime.c b/grub-core/normal/datetime.c index 44791e18c..bbc2cdea9 100644 --- a/grub-core/normal/datetime.c +++ b/grub-core/normal/datetime.c @@ -18,16 +18,17 @@ */ #include +#include -static char *grub_weekday_names[] = +static const char *const grub_weekday_names[] = { - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", + N_("Sunday"), + N_("Monday"), + N_("Tuesday"), + N_("Wednesday"), + N_("Thursday"), + N_("Friday"), + N_("Saturday"), }; int @@ -42,10 +43,10 @@ grub_get_weekday (struct grub_datetime *datetime) return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7; } -char * +const char * grub_get_weekday_name (struct grub_datetime *datetime) { - return grub_weekday_names[grub_get_weekday (datetime)]; + return _ (grub_weekday_names[grub_get_weekday (datetime)]); } #define SECPERMIN 60 diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index 3bfbbeb72..21fcdf56f 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -33,6 +33,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_DEFAULT_HISTORY_SIZE 50 static int nested_level = 0; @@ -272,7 +274,6 @@ grub_normal_execute (const char *config, int nested, int batch) prefix = grub_env_get ("prefix"); read_lists (prefix); grub_register_variable_hook ("prefix", NULL, read_lists_hook); - grub_command_execute ("parser.grub", 0, 0); } if (config) @@ -287,7 +288,7 @@ grub_normal_execute (const char *config, int nested, int batch) { if (menu && menu->size) { - grub_show_menu (menu, nested); + grub_show_menu (menu, nested, 0); if (nested) grub_normal_free_menu (menu); } @@ -471,9 +472,14 @@ grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)), static grub_command_t cmd_clear; static void (*grub_xputs_saved) (const char *str); +static const char *features[] = { + "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint" +}; GRUB_MOD_INIT(normal) { + unsigned i; + /* Previously many modules depended on gzio. Be nice to user and load it. */ grub_dl_load ("gzio"); @@ -496,6 +502,7 @@ GRUB_MOD_INIT(normal) grub_set_history (GRUB_DEFAULT_HISTORY_SIZE); grub_register_variable_hook ("pager", 0, grub_env_write_pager); + grub_env_export ("pager"); /* Register a command "normal" for the rescue mode. */ grub_register_command ("normal", grub_cmd_normal, @@ -514,6 +521,12 @@ GRUB_MOD_INIT(normal) /* Set default color names. */ grub_env_set ("color_normal", "white/black"); grub_env_set ("color_highlight", "black/white"); + + for (i = 0; i < ARRAY_SIZE (features); i++) + { + grub_env_set (features[i], "y"); + grub_env_export (features[i]); + } } GRUB_MOD_FINI(normal) diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index 807ad51e0..8b428f220 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include /* Time to delay after displaying an error message about a default/fallback entry failing to boot. */ @@ -77,7 +79,7 @@ grub_menu_get_entry (grub_menu_t menu, int no) int grub_menu_get_timeout (void) { - char *val; + const char *val; int timeout; val = grub_env_get ("timeout"); @@ -122,7 +124,7 @@ grub_menu_set_timeout (int timeout) static int get_and_remove_first_entry_number (const char *name) { - char *val; + const char *val; char *tail; int entry; @@ -154,12 +156,15 @@ get_and_remove_first_entry_number (const char *name) } /* Run a menu entry. */ -void -grub_menu_execute_entry(grub_menu_entry_t entry) +static void +grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) { grub_err_t err = GRUB_ERR_NONE; int errs_before; - grub_menu_t menu; + grub_menu_t menu = NULL; + char *optr, *buf, *oldchosen = NULL, *olddefault = NULL; + const char *ptr, *chosen, *def; + grub_size_t sz = 0; if (entry->restricted) err = grub_auth_check_authentication (entry->users); @@ -173,6 +178,9 @@ grub_menu_execute_entry(grub_menu_entry_t entry) errs_before = grub_err_printed_errors; + chosen = grub_env_get ("chosen"); + def = grub_env_get ("default"); + if (entry->submenu) { grub_env_context_open (); @@ -180,9 +188,67 @@ grub_menu_execute_entry(grub_menu_entry_t entry) if (! menu) return; grub_env_set_menu (menu); + if (auto_boot) + grub_env_set ("timeout", "0"); } - grub_env_set ("chosen", entry->title); + for (ptr = entry->title; *ptr; ptr++) + sz += (*ptr == '>') ? 2 : 1; + if (chosen) + { + oldchosen = grub_strdup (chosen); + if (!oldchosen) + grub_print_error (); + } + if (def) + { + olddefault = grub_strdup (def); + if (!olddefault) + grub_print_error (); + } + sz++; + if (chosen) + sz += grub_strlen (chosen); + sz++; + buf = grub_malloc (sz); + if (!buf) + grub_print_error (); + else + { + optr = buf; + if (chosen) + { + optr = grub_stpcpy (optr, chosen); + *optr++ = '>'; + } + for (ptr = entry->title; *ptr; ptr++) + { + if (*ptr == '>') + *optr++ = '>'; + *optr++ = *ptr; + } + *optr = 0; + grub_env_set ("chosen", buf); + grub_env_export ("chosen"); + grub_free (buf); + } + + for (ptr = def; ptr && *ptr; ptr++) + { + if (ptr[0] == '>' && ptr[1] == '>') + { + ptr++; + continue; + } + if (ptr[0] == '>') + break; + } + + if (ptr && ptr[0] && ptr[1]) + grub_env_set ("default", ptr + 1); + else + grub_env_unset ("default"); + grub_script_execute_sourcecode (entry->sourcecode, entry->argc, entry->args); if (errs_before != grub_err_printed_errors) @@ -196,20 +262,30 @@ grub_menu_execute_entry(grub_menu_entry_t entry) { if (menu && menu->size) { - grub_show_menu (menu, 1); + grub_show_menu (menu, 1, auto_boot); grub_normal_free_menu (menu); } grub_env_context_close (); } + if (oldchosen) + grub_env_set ("chosen", oldchosen); + else + grub_env_unset ("chosen"); + if (olddefault) + grub_env_set ("default", olddefault); + else + grub_env_unset ("default"); + grub_env_unset ("timeout"); } /* Execute ENTRY from the menu MENU, falling back to entries specified in the environment variable "fallback" if it fails. CALLBACK is a pointer to a struct of function pointers which are used to allow the caller provide feedback to the user. */ -void +static void grub_menu_execute_with_fallback (grub_menu_t menu, grub_menu_entry_t entry, + int autobooted, grub_menu_execute_callback_t callback, void *callback_data) { @@ -217,7 +293,7 @@ grub_menu_execute_with_fallback (grub_menu_t menu, callback->notify_booting (entry, callback_data); - grub_menu_execute_entry (entry); + grub_menu_execute_entry (entry, 1); /* Deal with fallback entries. */ while ((fallback_entry = get_and_remove_first_entry_number ("fallback")) @@ -228,14 +304,15 @@ grub_menu_execute_with_fallback (grub_menu_t menu, entry = grub_menu_get_entry (menu, fallback_entry); callback->notify_fallback (entry, callback_data); - grub_menu_execute_entry (entry); + grub_menu_execute_entry (entry, 1); /* If the function call to execute the entry returns at all, then this is taken to indicate a boot failure. For menu entries that do something other than actually boot an operating system, this could assume incorrectly that something failed. */ } - callback->notify_failure (callback_data); + if (!autobooted) + callback->notify_failure (callback_data); } static struct grub_menu_viewer *viewers; @@ -273,18 +350,44 @@ static void menu_init (int entry, grub_menu_t menu, int nested) { struct grub_term_output *term; + int gfxmenu = 0; + + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "gfxterm") == 0) + { + if (grub_env_get ("theme")) + { + if (!grub_gfxmenu_try_hook) + { + grub_dl_load ("gfxmenu"); + grub_print_error (); + } + if (grub_gfxmenu_try_hook) + { + grub_err_t err; + err = grub_gfxmenu_try_hook (entry, menu, nested); + if(!err) + { + gfxmenu = 1; + break; + } + } + else + grub_error (GRUB_ERR_BAD_MODULE, "no gfxmenu found"); + grub_print_error (); + grub_wait_after_message (); + } + grub_errno = GRUB_ERR_NONE; + grub_gfxterm_fullscreen (); + break; + } FOR_ACTIVE_TERM_OUTPUTS(term) { grub_err_t err; - if (grub_gfxmenu_try_hook && grub_strcmp (term->name, "gfxterm") == 0) - { - err = grub_gfxmenu_try_hook (entry, menu, nested); - if(!err) - continue; - grub_errno = GRUB_ERR_NONE; - } + if (grub_strcmp (term->name, "gfxterm") == 0 && gfxmenu) + continue; err = grub_menu_try_text (term, entry, menu, nested); if(!err) @@ -309,11 +412,35 @@ grub_menu_register_viewer (struct grub_menu_viewer *viewer) viewers = viewer; } +static int +menuentry_eq (const char *title, const char *spec) +{ + const char *ptr1, *ptr2; + ptr1 = title; + ptr2 = spec; + while (1) + { + if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) + return 1; + if (*ptr2 == '>' && ptr2[1] != '>') + return 0; + if (*ptr2 == '>') + ptr2++; + if (*ptr1 != *ptr2) + return 0; + if (*ptr1 == 0) + return 1; + ptr1++; + ptr2++; + } +} + + /* Get the entry number from the variable NAME. */ static int get_entry_number (grub_menu_t menu, const char *name) { - char *val; + const char *val; int entry; val = grub_env_get (name); @@ -334,7 +461,7 @@ get_entry_number (grub_menu_t menu, const char *name) for (i = 0; e; i++) { - if (grub_strcmp (e->title, val) == 0) + if (menuentry_eq (e->title, val)) { entry = i; break; @@ -539,7 +666,6 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) } /* Never reach here. */ - return -1; } /* Callback invoked immediately before a menu entry is executed. */ @@ -590,7 +716,7 @@ static struct grub_menu_execute_callback execution_callback = }; static grub_err_t -show_menu (grub_menu_t menu, int nested) +show_menu (grub_menu_t menu, int nested, int autobooted) { while (1) { @@ -609,22 +735,26 @@ show_menu (grub_menu_t menu, int nested) grub_cls (); if (auto_boot) - grub_menu_execute_with_fallback (menu, e, &execution_callback, 0); + grub_menu_execute_with_fallback (menu, e, autobooted, + &execution_callback, 0); else - grub_menu_execute_entry (e); + grub_menu_execute_entry (e, 0); + if (autobooted) + break; } return GRUB_ERR_NONE; } grub_err_t -grub_show_menu (grub_menu_t menu, int nested) +grub_show_menu (grub_menu_t menu, int nested, int autoboot) { grub_err_t err1, err2; while (1) { - err1 = show_menu (menu, nested); + err1 = show_menu (menu, nested, autoboot); + autoboot = 0; grub_print_error (); if (grub_normal_exit_level) diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c index 6cadf81ba..7af093fd8 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c @@ -52,6 +52,8 @@ struct per_term_screen int x; /* The Y coordinate. */ int y; + /* Number of entries. */ + int num_entries; }; struct screen @@ -87,7 +89,7 @@ init_line (struct line *linep) { linep->len = 0; linep->max_len = 80; /* XXX */ - linep->buf = grub_malloc (linep->max_len); + linep->buf = grub_malloc (linep->max_len + 1); if (! linep->buf) return 0; @@ -172,7 +174,7 @@ static void print_up (int flag, struct per_term_screen *term_screen) { grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X - + grub_term_entry_width (term_screen->term), + + grub_term_border_width (term_screen->term), GRUB_TERM_FIRST_ENTRY_Y); if (flag) @@ -188,7 +190,7 @@ print_down (int flag, struct per_term_screen *term_screen) grub_term_gotoxy (term_screen->term, GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term_screen->term), GRUB_TERM_TOP_BORDER_Y - + grub_term_num_entries (term_screen->term)); + + term_screen->num_entries); if (flag) grub_putcode (GRUB_UNICODE_DOWNARROW, term_screen->term); @@ -209,13 +211,12 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen, struct line *linep; /* Check if scrolling is necessary. */ - if (term_screen->y < 0 || term_screen->y - >= grub_term_num_entries (term_screen->term)) + if (term_screen->y < 0 || term_screen->y >= term_screen->num_entries) { if (term_screen->y < 0) term_screen->y = 0; else - term_screen->y = grub_term_num_entries (term_screen->term) - 1; + term_screen->y = term_screen->num_entries - 1; region_start = 0; region_column = 0; @@ -251,7 +252,7 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen, for (column = 0; column <= linep->len - && y < grub_term_num_entries (term_screen->term); + && y < term_screen->num_entries; column += grub_term_entry_width (term_screen->term), y++) { if (y < 0) @@ -272,7 +273,7 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen, print_line (linep, column, 0, y, term_screen); } - if (y == grub_term_num_entries (term_screen->term)) + if (y == term_screen->num_entries) { if (column <= linep->len || i + 1 < screen->num_lines) down_flag = 1; @@ -282,11 +283,11 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen, i++; if (mode == ALL_LINES && i == screen->num_lines) - for (; y < grub_term_num_entries (term_screen->term); y++) + for (; y < term_screen->num_entries; y++) print_empty_line (y, term_screen); } - while (y < grub_term_num_entries (term_screen->term)); + while (y < term_screen->num_entries); /* Draw up and down arrows. */ if (up) @@ -316,7 +317,7 @@ update_screen_all (struct screen *screen, } static int -insert_string (struct screen *screen, char *s, int update) +insert_string (struct screen *screen, const char *s, int update) { int region_start = screen->num_lines; int region_column = 0; @@ -396,7 +397,7 @@ insert_string (struct screen *screen, char *s, int update) else { /* All but LF. */ - char *p; + const char *p; struct line *current_linep; int size; int orig_num[screen->nterms], new_num[screen->nterms]; @@ -1163,37 +1164,35 @@ clear_completions_all (struct screen *screen) static int run (struct screen *screen) { - int currline = 0; - char *nextline; + char *script; int errs_before; - grub_menu_t menu; + grub_menu_t menu = NULL; + char *dummy[1] = { NULL }; - auto grub_err_t editor_getline (char **line, int cont); - grub_err_t editor_getline (char **line, int cont __attribute__ ((unused))) - { - struct line *linep = screen->lines + currline; - char *p; + auto char * editor_getsource (void); + char * editor_getsource (void) + { + int i; + int size = 0; + char *source; - if (currline > screen->num_lines) - { - *line = 0; - return 0; - } + for (i = 0; i < screen->num_lines; i++) + size += screen->lines[i].len + 1; - /* Trim down space characters. */ - for (p = linep->buf + linep->len - 1; - p >= linep->buf && grub_isspace (*p); - p--) - ; - *++p = '\0'; + source = grub_malloc (size + 1); + if (! source) + return NULL; - linep->len = p - linep->buf; - for (p = linep->buf; grub_isspace (*p); p++) - ; - *line = grub_strdup (p); - currline++; - return 0; - } + size = 0; + for (i = 0; i < screen->num_lines; i++) + { + grub_memcpy (source + size, screen->lines[i].buf, screen->lines[i].len); + size += screen->lines[i].len; + source[size++] = '\n'; + } + source[size] = '\0'; + return source; + } grub_cls (); grub_printf (" "); @@ -1212,12 +1211,11 @@ run (struct screen *screen) } /* Execute the script, line for line. */ - while (currline < screen->num_lines) - { - editor_getline (&nextline, 0); - if (grub_normal_parse_line (nextline, editor_getline)) - break; - } + script = editor_getsource (); + if (! script) + return 0; + grub_script_execute_sourcecode (script, 0, dummy); + grub_free (script); if (errs_before != grub_err_printed_errors) grub_wait_after_message (); @@ -1230,7 +1228,7 @@ run (struct screen *screen) { if (menu && menu->size) { - grub_show_menu (menu, 1); + grub_show_menu (menu, 1, 0); grub_normal_free_menu (menu); } grub_env_context_close (); @@ -1293,7 +1291,8 @@ grub_menu_entry_run (grub_menu_entry_t entry) } /* Draw the screen. */ for (i = 0; i < screen->nterms; i++) - grub_menu_init_page (0, 1, screen->terms[i].term); + grub_menu_init_page (0, 1, &screen->terms[i].num_entries, + screen->terms[i].term); update_screen_all (screen, 0, 0, 1, 1, ALL_LINES); for (i = 0; i < screen->nterms; i++) grub_term_setcursor (screen->terms[i].term, 1); diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c index fc4a89196..93f0492bc 100644 --- a/grub-core/normal/menu_text.c +++ b/grub-core/normal/menu_text.c @@ -34,10 +34,19 @@ static grub_uint8_t grub_color_menu_highlight; struct menu_viewer_data { int first, offset; + /* The number of entries shown at a time. */ + int num_entries; grub_menu_t menu; struct grub_term_output *term; }; +static inline int +grub_term_cursor_x (struct grub_term_output *term) +{ + return (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) + - GRUB_TERM_MARGIN - 1); +} + grub_ssize_t grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position, struct grub_term_output *term) @@ -53,30 +62,45 @@ grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position, return width; } -void -grub_print_message_indented (const char *msg, int margin_left, int margin_right, - struct grub_term_output *term) +static int +grub_print_message_indented_real (const char *msg, int margin_left, + int margin_right, + struct grub_term_output *term, int dry_run) { grub_uint32_t *unicode_msg; grub_uint32_t *last_position; int msg_len; + int ret = 0; msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position); if (msg_len < 0) { - return; + return 0; } - grub_print_ucs4 (unicode_msg, last_position, margin_left, margin_right, term); + if (dry_run) + ret = grub_ucs4_count_lines (unicode_msg, last_position, margin_left, + margin_right, term); + else + grub_print_ucs4 (unicode_msg, last_position, margin_left, + margin_right, term); grub_free (unicode_msg); + + return ret; } +void +grub_print_message_indented (const char *msg, int margin_left, int margin_right, + struct grub_term_output *term) +{ + grub_print_message_indented_real (msg, margin_left, margin_right, term, 0); +} static void -draw_border (struct grub_term_output *term) +draw_border (struct grub_term_output *term, int num_entries) { unsigned i; @@ -88,7 +112,7 @@ draw_border (struct grub_term_output *term) grub_putcode (GRUB_UNICODE_HLINE, term); grub_putcode (GRUB_UNICODE_CORNER_UR, term); - for (i = 0; i < (unsigned) grub_term_num_entries (term); i++) + for (i = 0; i < (unsigned) num_entries; i++) { grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1); grub_putcode (GRUB_UNICODE_VLINE, term); @@ -99,7 +123,7 @@ draw_border (struct grub_term_output *term) } grub_term_gotoxy (term, GRUB_TERM_MARGIN, - GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + 1); + GRUB_TERM_TOP_BORDER_Y + num_entries + 1); grub_putcode (GRUB_UNICODE_CORNER_LL, term); for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++) grub_putcode (GRUB_UNICODE_HLINE, term); @@ -108,22 +132,27 @@ draw_border (struct grub_term_output *term) grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); grub_term_gotoxy (term, GRUB_TERM_MARGIN, - (GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + (GRUB_TERM_TOP_BORDER_Y + num_entries + GRUB_TERM_MARGIN + 1)); } -static void -print_message (int nested, int edit, struct grub_term_output *term) +static int +print_message (int nested, int edit, struct grub_term_output *term, int dry_run) { + int ret = 0; grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); if (edit) { - grub_putcode ('\n', term); - grub_print_message_indented (_("Minimum Emacs-like screen editing is \ + if(dry_run) + ret++; + else + grub_putcode ('\n', term); + ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \ supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \ command-line or ESC to discard edits and return to the GRUB menu."), - STANDARD_MARGIN, STANDARD_MARGIN, term); + STANDARD_MARGIN, STANDARD_MARGIN, + term, dry_run); } else { @@ -134,30 +163,34 @@ command-line or ESC to discard edits and return to the GRUB menu."), msg_translated = grub_xasprintf (msg, GRUB_UNICODE_UPARROW, GRUB_UNICODE_DOWNARROW); if (!msg_translated) - return; - grub_putcode ('\n', term); - grub_print_message_indented (msg_translated, STANDARD_MARGIN, - STANDARD_MARGIN, term); + return 0; + if(dry_run) + ret++; + else + grub_putcode ('\n', term); + ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN, + STANDARD_MARGIN, term, dry_run); grub_free (msg_translated); if (nested) { - grub_print_message_indented + ret += grub_print_message_indented_real (_("Press enter to boot the selected OS, " "\'e\' to edit the commands before booting " "or \'c\' for a command-line. ESC to return previous menu.\n"), - STANDARD_MARGIN, STANDARD_MARGIN, term); + STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); } else { - grub_print_message_indented + ret += grub_print_message_indented_real (_("Press enter to boot the selected OS, " "\'e\' to edit the commands before booting " "or \'c\' for a command-line.\n"), - STANDARD_MARGIN, STANDARD_MARGIN, term); + STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); } } + return ret; } static void @@ -256,52 +289,56 @@ print_entry (int y, int highlight, grub_menu_entry_t entry, } static void -print_entries (grub_menu_t menu, int first, int offset, - struct grub_term_output *term) +print_entries (grub_menu_t menu, const struct menu_viewer_data *data) { grub_menu_entry_t e; int i; - grub_term_gotoxy (term, - GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term), + grub_term_gotoxy (data->term, + GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (data->term), GRUB_TERM_FIRST_ENTRY_Y); - if (first) - grub_putcode (GRUB_UNICODE_UPARROW, term); + if (data->first) + grub_putcode (GRUB_UNICODE_UPARROW, data->term); else - grub_putcode (' ', term); + grub_putcode (' ', data->term); - e = grub_menu_get_entry (menu, first); + e = grub_menu_get_entry (menu, data->first); - for (i = 0; i < grub_term_num_entries (term); i++) + for (i = 0; i < data->num_entries; i++) { - print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term); + print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, data->offset == i, + e, data->term); if (e) e = e->next; } - grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X - + grub_term_border_width (term), - GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)); + grub_term_gotoxy (data->term, GRUB_TERM_LEFT_BORDER_X + + grub_term_border_width (data->term), + GRUB_TERM_TOP_BORDER_Y + data->num_entries); if (e) - grub_putcode (GRUB_UNICODE_DOWNARROW, term); + grub_putcode (GRUB_UNICODE_DOWNARROW, data->term); else - grub_putcode (' ', term); + grub_putcode (' ', data->term); - grub_term_gotoxy (term, grub_term_cursor_x (term), - GRUB_TERM_FIRST_ENTRY_Y + offset); + grub_term_gotoxy (data->term, grub_term_cursor_x (data->term), + GRUB_TERM_FIRST_ENTRY_Y + data->offset); } /* Initialize the screen. If NESTED is non-zero, assume that this menu is run from another menu or a command-line. If EDIT is non-zero, show a message for the menu entry editor. */ void -grub_menu_init_page (int nested, int edit, +grub_menu_init_page (int nested, int edit, int *num_entries, struct grub_term_output *term) { grub_uint8_t old_color_normal, old_color_highlight; + /* 3 lines for timeout message and bottom margin. 2 lines for the border. */ + *num_entries = grub_term_height (term) - GRUB_TERM_TOP_BORDER_Y + - (print_message (nested, edit, term, 1) + 3) - 2; + grub_term_getcolor (term, &old_color_normal, &old_color_highlight); /* By default, use the same colors for the menu. */ @@ -316,9 +353,9 @@ grub_menu_init_page (int nested, int edit, grub_normal_init_page (term); grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight); - draw_border (term); + draw_border (term, *num_entries); grub_term_setcolor (term, old_color_normal, old_color_highlight); - print_message (nested, edit, term); + print_message (nested, edit, term, 0); } static void @@ -359,10 +396,10 @@ menu_text_set_chosen_entry (int entry, void *dataptr) int complete_redraw = 0; data->offset = entry - data->first; - if (data->offset > grub_term_num_entries (data->term) - 1) + if (data->offset > data->num_entries - 1) { - data->first = entry - (grub_term_num_entries (data->term) - 1); - data->offset = grub_term_num_entries (data->term) - 1; + data->first = entry - (data->num_entries - 1); + data->offset = data->num_entries - 1; complete_redraw = 1; } if (data->offset < 0) @@ -372,7 +409,7 @@ menu_text_set_chosen_entry (int entry, void *dataptr) complete_redraw = 1; } if (complete_redraw) - print_entries (data->menu, data->first, data->offset, data->term); + print_entries (data->menu, data); else { print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0, @@ -436,15 +473,17 @@ grub_menu_try_text (struct grub_term_output *term, data->offset = entry; data->first = 0; - if (data->offset > grub_term_num_entries (data->term) - 1) - { - data->first = data->offset - (grub_term_num_entries (data->term) - 1); - data->offset = grub_term_num_entries (data->term) - 1; - } grub_term_setcursor (data->term, 0); - grub_menu_init_page (nested, 0, data->term); - print_entries (menu, data->first, data->offset, data->term); + grub_menu_init_page (nested, 0, &data->num_entries, data->term); + + if (data->offset > data->num_entries - 1) + { + data->first = data->offset - (data->num_entries - 1); + data->offset = data->num_entries - 1; + } + + print_entries (menu, data); grub_term_refresh (data->term); grub_menu_register_viewer (instance); diff --git a/grub-core/normal/misc.c b/grub-core/normal/misc.c index d81b6d26f..4a7e6a3ea 100644 --- a/grub-core/normal/misc.c +++ b/grub-core/normal/misc.c @@ -112,14 +112,13 @@ grub_normal_print_device_info (const char *name) grub_printf ("%s", _("Not a known filesystem")); if (dev->disk->partition) - grub_printf (_(" - Partition start at %u"), - grub_partition_get_start (dev->disk->partition)); + grub_printf (_(" - Partition start at %llu"), + (unsigned long long) grub_partition_get_start (dev->disk->partition)); if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) - grub_printf (_(" - Total size unknown"), - grub_disk_get_size (dev->disk)); + grub_puts_ (" - Total size unknown"); else - grub_printf (_(" - Total size %u sectors"), - grub_disk_get_size (dev->disk)); + grub_printf (_(" - Total size %llu sectors"), + (unsigned long long) grub_disk_get_size (dev->disk)); grub_device_close (dev); } diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c index 00721c447..922f8518f 100644 --- a/grub-core/normal/term.c +++ b/grub-core/normal/term.c @@ -24,6 +24,7 @@ #include #include #include +#include struct term_state { @@ -63,7 +64,9 @@ print_more (void) pos = grub_term_save_pos (); - grub_utf8_to_ucs4_alloc ("--MORE--", &unicode_str, + /* TRANSLATORS: This has to fit on one line. It's ok to include few + words but don't write poems. */ + grub_utf8_to_ucs4_alloc (_("--MORE--"), &unicode_str, &unicode_last_position); if (!unicode_str) @@ -91,16 +94,16 @@ print_more (void) grub_term_restore_pos (pos); grub_free (pos); - /* Scroll one lines or an entire page, depending on the key. */ + /* Scroll one line or an entire page, depending on the key. */ if (key == '\r' || key =='\n') - grub_normal_reset_more (); - else { static struct term_state *state; for (state = term_states; state; state = state->next) - state->num_lines -= 2; + state->num_lines--; } + else + grub_normal_reset_more (); } void @@ -515,14 +518,16 @@ print_ucs4_terminal (const grub_uint32_t * str, const grub_uint32_t * last_position, int margin_left, int margin_right, struct grub_term_output *term, - struct term_state *state) + struct term_state *state, + int dry_run) { const grub_uint32_t *ptr; - grub_ssize_t startwidth = get_startwidth (term, margin_left); + grub_ssize_t startwidth = dry_run ? 0 : get_startwidth (term, margin_left); grub_ssize_t line_width = startwidth; grub_ssize_t lastspacewidth = 0; grub_ssize_t max_width = get_maxwidth (term, margin_left, margin_right); const grub_uint32_t *line_start = str, *last_space = str - 1; + int lines = 0; for (ptr = str; ptr < last_position; ptr++) { @@ -552,7 +557,7 @@ print_ucs4_terminal (const grub_uint32_t * str, if (line_width > max_width && last_space > line_start) ptr = last_space; else if (line_width > max_width - && line_start == str && startwidth != 0) + && line_start == str && line_width - lastspacewidth < max_width - 5) { ptr = str; lastspacewidth = startwidth; @@ -560,50 +565,59 @@ print_ucs4_terminal (const grub_uint32_t * str, else lastspacewidth = line_width - last_width; - for (ptr2 = line_start; ptr2 < ptr; ptr2++) - { - /* Skip combining characters on non-UTF8 terminals. */ - if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) - != GRUB_TERM_CODE_TYPE_UTF8_LOGICAL - && grub_unicode_get_comb_type (*ptr2) - != GRUB_UNICODE_COMB_NONE) - continue; - putcode_real (*ptr2, term); - } + lines++; - grub_print_spaces (term, margin_right); - grub_putcode ('\n', term); - if (state && ++state->num_lines - >= (grub_ssize_t) grub_term_height (term) - 2) + if (!dry_run) { - state->backlog_ucs4 = (ptr == last_space || *ptr == '\n') - ? ptr + 1 : ptr; - state->backlog_len = last_position - state->backlog_ucs4; - return 1; + for (ptr2 = line_start; ptr2 < ptr; ptr2++) + { + /* Skip combining characters on non-UTF8 terminals. */ + if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) + != GRUB_TERM_CODE_TYPE_UTF8_LOGICAL + && grub_unicode_get_comb_type (*ptr2) + != GRUB_UNICODE_COMB_NONE) + continue; + putcode_real (*ptr2, term); + } + + grub_print_spaces (term, margin_right); + grub_putcode ('\n', term); + if (state && ++state->num_lines + >= (grub_ssize_t) grub_term_height (term) - 2) + { + state->backlog_ucs4 = (ptr == last_space || *ptr == '\n') + ? ptr + 1 : ptr; + state->backlog_len = last_position - state->backlog_ucs4; + return 1; + } } line_width -= lastspacewidth; - grub_print_spaces (term, margin_left); + if (!dry_run) + grub_print_spaces (term, margin_left); if (ptr == last_space || *ptr == '\n') ptr++; line_start = ptr; } } - { - const grub_uint32_t *ptr2; - for (ptr2 = line_start; ptr2 < last_position; ptr2++) - { - /* Skip combining characters on non-UTF8 terminals. */ - if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) - != GRUB_TERM_CODE_TYPE_UTF8_LOGICAL - && grub_unicode_get_comb_type (*ptr2) - != GRUB_UNICODE_COMB_NONE) - continue; - putcode_real (*ptr2, term); - } - } - return 0; + if (line_start < last_position) + lines++; + if (!dry_run) + { + const grub_uint32_t *ptr2; + for (ptr2 = line_start; ptr2 < last_position; ptr2++) + { + /* Skip combining characters on non-UTF8 terminals. */ + if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) + != GRUB_TERM_CODE_TYPE_UTF8_LOGICAL + && grub_unicode_get_comb_type (*ptr2) + != GRUB_UNICODE_COMB_NONE) + continue; + putcode_real (*ptr2, term); + } + } + return dry_run ? lines : 0; } static struct term_state * @@ -672,7 +686,7 @@ print_backlog (struct grub_term_output *term, int ret; ret = print_ucs4_terminal (state->backlog_ucs4, state->backlog_ucs4 + state->backlog_len, - margin_left, margin_right, term, state); + margin_left, margin_right, term, state, 0); if (!ret) { grub_free (state->free); @@ -706,15 +720,19 @@ static int print_ucs4_real (const grub_uint32_t * str, const grub_uint32_t * last_position, int margin_left, int margin_right, - struct grub_term_output *term, int backlog) + struct grub_term_output *term, int backlog, + int dry_run) { struct term_state *state = NULL; - if (backlog) - state = find_term_state (term); + if (!dry_run) + { + if (backlog) + state = find_term_state (term); - if (((term->getxy (term) >> 8) & 0xff) < margin_left) - grub_print_spaces (term, margin_left - ((term->getxy (term) >> 8) & 0xff)); + if (((term->getxy (term) >> 8) & 0xff) < margin_left) + grub_print_spaces (term, margin_left - ((term->getxy (term) >> 8) & 0xff)); + } if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) == GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS @@ -743,16 +761,30 @@ print_ucs4_real (const grub_uint32_t * str, grub_print_error (); return 0; } - ret = put_glyphs_terminal (visual, visual_len, margin_left, margin_right, - term, state); - if (!ret) - grub_free (visual); + if (dry_run) + { + struct grub_unicode_glyph *vptr; + ret = 0; + for (vptr = visual; vptr < visual + visual_len; vptr++) + if (vptr->base == '\n') + ret++; + if (visual_len && visual[visual_len - 1].base != '\n') + ret++; + grub_free (visual); + } else - state->free = visual; + { + ret = put_glyphs_terminal (visual, visual_len, margin_left, + margin_right, term, state); + if (!ret) + grub_free (visual); + else + state->free = visual; + } return ret; } return print_ucs4_terminal (str, last_position, margin_left, margin_right, - term, state); + term, state, dry_run); } void @@ -762,9 +794,18 @@ grub_print_ucs4 (const grub_uint32_t * str, struct grub_term_output *term) { print_ucs4_real (str, last_position, margin_left, margin_right, - term, 0); + term, 0, 0); } +int +grub_ucs4_count_lines (const grub_uint32_t * str, + const grub_uint32_t * last_position, + int margin_left, int margin_right, + struct grub_term_output *term) +{ + return print_ucs4_real (str, last_position, margin_left, margin_right, + term, 0, 1); +} void grub_xputs_normal (const char *str) @@ -813,7 +854,7 @@ grub_xputs_normal (const char *str) { int cur; cur = print_ucs4_real (unicode_str, unicode_last_position, 0, 0, - term, grub_more); + term, grub_more, 0); if (cur) backlog = 1; } diff --git a/grub-core/partmap/acorn.c b/grub-core/partmap/acorn.c index 677ec61d5..341b8ac5f 100644 --- a/grub-core/partmap/acorn.c +++ b/grub-core/partmap/acorn.c @@ -23,6 +23,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define LINUX_NATIVE_MAGIC grub_cpu_to_le32 (0xdeafa1de) #define LINUX_SWAP_MAGIC grub_cpu_to_le32 (0xdeafab1e) #define LINUX_MAP_ENTRIES (512 / 12) @@ -32,11 +34,18 @@ struct grub_acorn_boot_block { - grub_uint8_t misc[0x1C0]; - struct grub_filecore_disc_record disc_record; - grub_uint8_t flags; - grub_uint16_t start_cylinder; - grub_uint8_t checksum; + union + { + struct + { + grub_uint8_t misc[0x1C0]; + struct grub_filecore_disc_record disc_record; + grub_uint8_t flags; + grub_uint16_t start_cylinder; + grub_uint8_t checksum; + } __attribute__ ((packed, aligned)); + grub_uint8_t bin[0x200]; + }; } __attribute__ ((packed, aligned)); struct linux_part @@ -69,7 +78,7 @@ acorn_partition_map_find (grub_disk_t disk, struct linux_part *m, goto fail; for (i = 0; i != 0x1ff; ++i) - checksum = (checksum & 0xff) + (checksum >> 8) + boot.misc[i]; + checksum = ((checksum & 0xff) + (checksum >> 8) + boot.bin[i]); if ((grub_uint8_t) checksum != boot.checksum) goto fail; diff --git a/grub-core/partmap/amiga.c b/grub-core/partmap/amiga.c index f21c5b243..0b89cdc11 100644 --- a/grub-core/partmap/amiga.c +++ b/grub-core/partmap/amiga.c @@ -23,10 +23,13 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_amiga_rdsk { /* "RDSK". */ grub_uint8_t magic[4]; +#define GRUB_AMIGA_RDSK_MAGIC "RDSK" grub_uint32_t size; grub_int32_t checksum; grub_uint32_t scsihost; @@ -36,13 +39,14 @@ struct grub_amiga_rdsk grub_uint32_t partitionlst; grub_uint32_t fslst; - /* The other information is not important for us. */ + grub_uint32_t unused[128 - 9]; } __attribute__ ((packed)); struct grub_amiga_partition { /* "PART". */ grub_uint8_t magic[4]; +#define GRUB_AMIGA_PART_MAGIC "PART" grub_int32_t size; grub_int32_t checksum; grub_uint32_t scsihost; @@ -63,12 +67,24 @@ struct grub_amiga_partition grub_uint32_t highcyl; grub_uint32_t firstcyl; + grub_uint32_t unused[128 - 44]; } __attribute__ ((packed)); static struct grub_partition_map grub_amiga_partition_map; +static grub_uint32_t +amiga_partition_map_checksum (void *buf, grub_size_t sz) +{ + grub_uint32_t *ptr = buf; + grub_uint32_t r = 0; + sz /= sizeof (grub_uint32_t); + for (; sz; sz--, ptr++) + r += grub_be_to_cpu32 (*ptr); + return r; +} + static grub_err_t amiga_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, @@ -87,7 +103,9 @@ amiga_partition_map_iterate (grub_disk_t disk, if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk)) return grub_errno; - if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0) + if (grub_memcmp (rdsk.magic, GRUB_AMIGA_RDSK_MAGIC, + sizeof (rdsk.magic)) == 0 + && amiga_partition_map_checksum (&rdsk, sizeof (rdsk)) == 0) { /* Found the first PART block. */ next = grub_be_to_cpu32 (rdsk.partitionlst); @@ -108,6 +126,11 @@ amiga_partition_map_iterate (grub_disk_t disk, if (grub_disk_read (disk, next, 0, sizeof (apart), &apart)) return grub_errno; + if (grub_memcmp (apart.magic, GRUB_AMIGA_PART_MAGIC, + sizeof (apart.magic)) != 0 + || amiga_partition_map_checksum (&apart, sizeof (apart)) != 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "invalid Amiga partition map"); /* Calculate the first block and the size of the partition. */ part.start = (grub_be_to_cpu32 (apart.lowcyl) * grub_be_to_cpu32 (apart.heads) diff --git a/grub-core/partmap/apple.c b/grub-core/partmap/apple.c index e162d18d7..c08cae589 100644 --- a/grub-core/partmap/apple.c +++ b/grub-core/partmap/apple.c @@ -22,6 +22,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_APPLE_HEADER_MAGIC 0x4552 #define GRUB_APPLE_PART_MAGIC 0x504D diff --git a/grub-core/partmap/bsdlabel.c b/grub-core/partmap/bsdlabel.c index eff3bbe44..490fbdd7b 100644 --- a/grub-core/partmap/bsdlabel.c +++ b/grub-core/partmap/bsdlabel.c @@ -24,9 +24,12 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); #ifdef GRUB_UTIL -#include +#include #endif static struct grub_partition_map grub_bsdlabel_partition_map; @@ -44,7 +47,7 @@ iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd, struct grub_partition_bsd_disk_label label; struct grub_partition p; grub_disk_addr_t delta = 0; - unsigned pos; + grub_disk_addr_t pos; /* Read the BSD label. */ if (grub_disk_read (disk, sector, 0, sizeof (label), &label)) @@ -101,8 +104,9 @@ iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd, #ifdef GRUB_UTIL char *partname; /* disk->partition != NULL as 0 < delta */ - partname = grub_partition_get_name (disk->partition); - grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", + partname = disk->partition ? grub_partition_get_name (disk->partition) + : ""; + grub_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"), disk->name, partname, p.partmap->name, p.number + 1); grub_free (partname); #endif diff --git a/grub-core/partmap/dvh.c b/grub-core/partmap/dvh.c new file mode 100644 index 000000000..c8f467eb5 --- /dev/null +++ b/grub-core/partmap/dvh.c @@ -0,0 +1,128 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2011 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 + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define DVH_MAGIC 0x0be5a941 + +struct grub_dvh_partition_descriptor +{ + grub_uint32_t length; + grub_uint32_t start; + grub_uint32_t type; +} __attribute__ ((packed)); + +struct grub_dvh_block +{ + grub_uint32_t magic; + grub_uint8_t unused[308]; + struct grub_dvh_partition_descriptor parts[16]; + grub_uint32_t checksum; + grub_uint32_t unused2; +} __attribute__ ((packed)); + +static struct grub_partition_map grub_dvh_partition_map; + +/* Verify checksum (true=ok). */ +static int +grub_dvh_is_valid (grub_uint32_t *label) +{ + grub_uint32_t *pos; + grub_uint32_t sum = 0; + + for (pos = label; + pos < (label + sizeof (struct grub_dvh_block) / 4); + pos++) + sum += *pos; + + return ! sum; +} + +static grub_err_t +dvh_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + struct grub_partition p; + union + { + struct grub_dvh_block dvh; + grub_uint32_t raw[0]; + } block; + unsigned partnum; + grub_err_t err; + + p.partmap = &grub_dvh_partition_map; + err = grub_disk_read (disk, 0, 0, sizeof (struct grub_dvh_block), + &block); + if (err) + return err; + + if (DVH_MAGIC != grub_be_to_cpu32 (block.dvh.magic)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a dvh partition table"); + + if (! grub_dvh_is_valid (block.raw)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); + + /* Maybe another error value would be better, because partition + table _is_ recognized but invalid. */ + for (partnum = 0; partnum < ARRAY_SIZE (block.dvh.parts); partnum++) + { + if (block.dvh.parts[partnum].length == 0) + continue; + + if (partnum == 10) + continue; + + p.start = grub_be_to_cpu32 (block.dvh.parts[partnum].start); + p.len = grub_be_to_cpu32 (block.dvh.parts[partnum].length); + p.number = p.index = partnum; + if (hook (disk, &p)) + break; + } + + return grub_errno; +} + + +/* Partition map type. */ +static struct grub_partition_map grub_dvh_partition_map = + { + .name = "dvh", + .iterate = dvh_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_dvh) +{ + grub_partition_map_register (&grub_dvh_partition_map); +} + +GRUB_MOD_FINI(part_dvh) +{ + grub_partition_map_unregister (&grub_dvh_partition_map); +} + diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c index 7f2c36143..dd123aac4 100644 --- a/grub-core/partmap/gpt.c +++ b/grub-core/partmap/gpt.c @@ -25,6 +25,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_uint8_t grub_gpt_magic[8] = { 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 @@ -43,10 +45,10 @@ static struct grub_partition_map grub_gpt_partition_map; -static grub_err_t -gpt_partition_map_iterate (grub_disk_t disk, - int (*hook) (grub_disk_t disk, - const grub_partition_t partition)) +grub_err_t +grub_gpt_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) { struct grub_partition part; struct grub_gpt_header gpt; @@ -138,11 +140,17 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, const grub_partition_t p) { struct grub_gpt_partentry gptdata; + grub_partition_t p2; + p2 = disk->partition; disk->partition = p->parent; if (grub_disk_read (disk, p->offset, p->index, sizeof (gptdata), &gptdata)) - return 0; + { + disk->partition = p2; + return 0; + } + disk->partition = p2; /* If there's an embed region, it is in a dedicated partition. */ if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16)) @@ -157,9 +165,9 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, if (embed_type != GRUB_EMBED_PCBIOS) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "GPT curently supports only PC-BIOS embedding"); + "GPT currently supports only PC-BIOS embedding"); - err = gpt_partition_map_iterate (disk, find_usable_region); + err = grub_gpt_partition_map_iterate (disk, find_usable_region); if (err) return err; @@ -189,7 +197,7 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, static struct grub_partition_map grub_gpt_partition_map = { .name = "gpt", - .iterate = gpt_partition_map_iterate, + .iterate = grub_gpt_partition_map_iterate, #ifdef GRUB_UTIL .embed = gpt_partition_map_embed #endif diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c index f99e27a6e..c8ab6acab 100644 --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static struct grub_partition_map grub_msdos_partition_map; @@ -90,8 +92,11 @@ grub_partition_msdos_iterate (grub_disk_t disk, { e = mbr.entries + p.index; - p.start = p.offset + grub_le_to_cpu32 (e->start) - delta; - p.len = grub_le_to_cpu32 (e->length); + p.start = p.offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) - delta; + p.len = grub_le_to_cpu32 (e->length) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); p.msdostype = e->type; grub_dprintf ("partition", @@ -126,7 +131,9 @@ grub_partition_msdos_iterate (grub_disk_t disk, if (grub_msdos_partition_is_extended (e->type)) { - p.offset = ext_offset + grub_le_to_cpu32 (e->start); + p.offset = ext_offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); if (! ext_offset) ext_offset = p.offset; @@ -204,8 +211,11 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, e = mbr.entries + i; if (!grub_msdos_partition_is_empty (e->type) - && end > offset + grub_le_to_cpu32 (e->start)) - end = offset + grub_le_to_cpu32 (e->start); + && end > offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS))) + end = offset + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); /* If this is a GPT partition, this MBR is just a dummy. */ if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0) @@ -219,7 +229,9 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, if (grub_msdos_partition_is_extended (e->type)) { - offset = ext_offset + grub_le_to_cpu32 (e->start); + offset = ext_offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); if (! ext_offset) ext_offset = offset; @@ -232,10 +244,10 @@ pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, break; } - if (end >= *nsectors + 1) + if (end >= *nsectors + 2) { - int i; - *nsectors = end - 1; + unsigned i; + *nsectors = end - 2; *sectors = grub_malloc (*nsectors * sizeof (**sectors)); if (!*sectors) return grub_errno; diff --git a/grub-core/partmap/plan.c b/grub-core/partmap/plan.c new file mode 100644 index 000000000..e6e311319 --- /dev/null +++ b/grub-core/partmap/plan.c @@ -0,0 +1,120 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static struct grub_partition_map grub_plan_partition_map; + +static grub_err_t +plan_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)) +{ + struct grub_partition p; + int ptr = 0; + grub_err_t err; + + p.partmap = &grub_plan_partition_map; + p.msdostype = 0; + + for (p.number = 0; ; p.number++) + { + char sig[sizeof ("part ") - 1]; + char c; + + p.offset = (ptr >> GRUB_DISK_SECTOR_BITS) + 1; + p.index = ptr & (GRUB_DISK_SECTOR_SIZE - 1); + + err = grub_disk_read (disk, 1, ptr, sizeof (sig), sig); + if (err) + return err; + if (grub_memcmp (sig, "part ", sizeof ("part ") - 1) != 0) + break; + ptr += sizeof (sig); + do + { + err = grub_disk_read (disk, 1, ptr, 1, &c); + if (err) + return err; + ptr++; + } + while (grub_isdigit (c) || grub_isalpha (c)); + if (c != ' ') + break; + p.start = 0; + while (1) + { + err = grub_disk_read (disk, 1, ptr, 1, &c); + if (err) + return err; + ptr++; + if (!grub_isdigit (c)) + break; + p.start = p.start * 10 + (c - '0'); + } + if (c != ' ') + break; + p.len = 0; + while (1) + { + err = grub_disk_read (disk, 1, ptr, 1, &c); + if (err) + return err; + ptr++; + if (!grub_isdigit (c)) + break; + p.len = p.len * 10 + (c - '0'); + } + if (c != '\n') + break; + p.len -= p.start; + if (hook (disk, &p)) + return grub_errno; + } + if (p.number == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a plan partition table"); + + return GRUB_ERR_NONE; +} + +/* Partition map type. */ +static struct grub_partition_map grub_plan_partition_map = + { + .name = "plan", + .iterate = plan_partition_map_iterate, + }; + +GRUB_MOD_INIT(part_plan) +{ + grub_partition_map_register (&grub_plan_partition_map); +} + +GRUB_MOD_FINI(part_plan) +{ + grub_partition_map_unregister (&grub_plan_partition_map); +} + diff --git a/grub-core/partmap/sun.c b/grub-core/partmap/sun.c index 7af95c939..dfe51f35d 100644 --- a/grub-core/partmap/sun.c +++ b/grub-core/partmap/sun.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_PARTMAP_SUN_MAGIC 0xDABE #define GRUB_PARTMAP_SUN_MAX_PARTS 8 #define GRUB_PARTMAP_SUN_WHOLE_DISK_ID 0x05 @@ -69,13 +71,13 @@ static struct grub_partition_map grub_sun_partition_map; /* Verify checksum (true=ok). */ static int -grub_sun_is_valid (struct grub_sun_block *label) +grub_sun_is_valid (grub_uint16_t *label) { grub_uint16_t *pos; grub_uint16_t sum = 0; - for (pos = (grub_uint16_t *) label; - pos < (grub_uint16_t *) (label + 1); + for (pos = label; + pos < (label + sizeof (struct grub_sun_block) / 2); pos++) sum ^= *pos; @@ -88,7 +90,11 @@ sun_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition p; - struct grub_sun_block block; + union + { + struct grub_sun_block sun; + grub_uint16_t raw[0]; + } block; int partnum; grub_err_t err; @@ -98,10 +104,10 @@ sun_partition_map_iterate (grub_disk_t disk, if (err) return err; - if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic)) + if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.sun.magic)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); - if (! grub_sun_is_valid (&block)) + if (! grub_sun_is_valid (block.raw)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); /* Maybe another error value would be better, because partition @@ -110,14 +116,14 @@ sun_partition_map_iterate (grub_disk_t disk, { struct grub_sun_partition_descriptor *desc; - if (block.infos[partnum].id == 0 - || block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) + if (block.sun.infos[partnum].id == 0 + || block.sun.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) continue; - desc = &block.partitions[partnum]; + desc = &block.sun.partitions[partnum]; p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) - * grub_be_to_cpu16 (block.ntrks) - * grub_be_to_cpu16 (block.nsect)); + * grub_be_to_cpu16 (block.sun.ntrks) + * grub_be_to_cpu16 (block.sun.nsect)); p.len = grub_be_to_cpu32 (desc->num_sectors); p.number = p.index = partnum; if (p.len) diff --git a/grub-core/partmap/sunpc.c b/grub-core/partmap/sunpc.c index ea69c28b9..1c1fdced0 100644 --- a/grub-core/partmap/sunpc.c +++ b/grub-core/partmap/sunpc.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define GRUB_PARTMAP_SUN_PC_MAGIC 0xDABE #define GRUB_PARTMAP_SUN_PC_MAX_PARTS 16 #define GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID 0x05 @@ -51,13 +53,13 @@ static struct grub_partition_map grub_sun_pc_partition_map; /* Verify checksum (true=ok). */ static int -grub_sun_is_valid (struct grub_sun_pc_block *label) +grub_sun_is_valid (grub_uint16_t *label) { grub_uint16_t *pos; grub_uint16_t sum = 0; - for (pos = (grub_uint16_t *) label; - pos < (grub_uint16_t *) (label + 1); + for (pos = label; + pos < (label + sizeof (struct grub_sun_pc_block) / 2); pos++) sum ^= *pos; @@ -70,7 +72,11 @@ sun_pc_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { grub_partition_t p; - struct grub_sun_pc_block block; + union + { + struct grub_sun_pc_block sun; + grub_uint16_t raw[0]; + } block; int partnum; grub_err_t err; @@ -86,14 +92,14 @@ sun_pc_partition_map_iterate (grub_disk_t disk, return err; } - if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.magic)) + if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.sun.magic)) { grub_free (p); return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun_pc partition table"); } - if (! grub_sun_is_valid (&block)) + if (! grub_sun_is_valid (block.raw)) { grub_free (p); return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); @@ -105,11 +111,12 @@ sun_pc_partition_map_iterate (grub_disk_t disk, { struct grub_sun_pc_partition_descriptor *desc; - if (block.partitions[partnum].id == 0 - || block.partitions[partnum].id == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID) + if (block.sun.partitions[partnum].id == 0 + || block.sun.partitions[partnum].id + == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID) continue; - desc = &block.partitions[partnum]; + desc = &block.sun.partitions[partnum]; p->start = grub_le_to_cpu32 (desc->start_sector); p->len = grub_le_to_cpu32 (desc->num_sectors); p->number = partnum; diff --git a/grub-core/parttool/msdospart.c b/grub-core/parttool/msdospart.c index 006a87def..3377a2ccc 100644 --- a/grub-core/parttool/msdospart.c +++ b/grub-core/parttool/msdospart.c @@ -27,13 +27,16 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv2+"); static int activate_table_handle = -1; static int type_table_handle = -1; static struct grub_parttool_argdesc grub_pcpart_bootargs[] = { - {"boot", "Make partition active", GRUB_PARTTOOL_ARG_BOOL}, + {"boot", N_("Make partition active"), GRUB_PARTTOOL_ARG_BOOL}, {0, 0, 0} }; @@ -63,12 +66,12 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev, for (i = 0; i < 4; i++) mbr.entries[i].flag = 0x0; mbr.entries[index].flag = 0x80; - grub_printf ("Partition %d is active now. \n", index); + grub_printf_ (N_("Partition %d is active now. \n"), index); } else { mbr.entries[index].flag = 0x0; - grub_printf ("Cleared active flag on %d. \n", index); + grub_printf (N_("Cleared active flag on %d. \n"), index); } /* Write the MBR. */ @@ -81,8 +84,8 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev, static struct grub_parttool_argdesc grub_pcpart_typeargs[] = { - {"type", "Change partition type", GRUB_PARTTOOL_ARG_VAL}, - {"hidden", "Make partition hidden", GRUB_PARTTOOL_ARG_BOOL}, + {"type", N_("Change partition type"), GRUB_PARTTOOL_ARG_VAL}, + {"hidden", N_("Make partition hidden"), GRUB_PARTTOOL_ARG_BOOL}, {0, 0, 0} }; @@ -127,7 +130,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev, } mbr.entries[index].type = type; - grub_printf ("Setting partition type to 0x%x\n", type); + grub_printf_ (N_("Setting partition type to 0x%x\n"), type); /* Write the parttable. */ grub_disk_write (dev->disk, part->offset, 0, diff --git a/grub-core/script/argv.c b/grub-core/script/argv.c index 50f810fcf..b58d3e658 100644 --- a/grub-core/script/argv.c +++ b/grub-core/script/argv.c @@ -25,6 +25,8 @@ static unsigned round_up_exp (unsigned v) { + COMPILE_TIME_ASSERT (sizeof (v) == 4); + v--; v |= v >> 1; v |= v >> 2; @@ -32,9 +34,6 @@ round_up_exp (unsigned v) v |= v >> 8; v |= v >> 16; - if (sizeof (v) > 4) - v |= v >> 32; - v++; v += (v == 0); @@ -67,7 +66,8 @@ grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args) 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])) + if (grub_script_argv_next (&r) + || grub_script_argv_append (&r, args[i], grub_strlen (args[i]))) { grub_script_argv_free (&r); return 1; @@ -100,23 +100,23 @@ grub_script_argv_next (struct grub_script_argv *argv) /* Append `s' to the last argument. */ int -grub_script_argv_append (struct grub_script_argv *argv, const char *s) +grub_script_argv_append (struct grub_script_argv *argv, const char *s, + grub_size_t slen) { - int a; - int b; + grub_size_t a; char *p = argv->args[argv->argc - 1]; if (! s) return 0; a = p ? grub_strlen (p) : 0; - b = grub_strlen (s); - p = grub_realloc (p, round_up_exp ((a + b + 1) * sizeof (char))); + p = grub_realloc (p, round_up_exp ((a + slen + 1) * sizeof (char))); if (! p) return 1; - grub_strcpy (p + a, s); + grub_memcpy (p + a, s, slen); + p[a+slen] = 0; argv->args[argv->argc - 1] = p; return 0; @@ -124,10 +124,9 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) /* Split `s' and append words as multiple arguments. */ int -grub_script_argv_split_append (struct grub_script_argv *argv, char *s) +grub_script_argv_split_append (struct grub_script_argv *argv, const char *s) { - char ch; - char *p; + const char *p; int errors = 0; if (! s) @@ -139,10 +138,7 @@ grub_script_argv_split_append (struct grub_script_argv *argv, char *s) while (*s && ! grub_isspace (*s)) s++; - ch = *s; - *s = '\0'; - errors += grub_script_argv_append (argv, p); - *s = ch; + errors += grub_script_argv_append (argv, p, s - p); while (*s && grub_isspace (*s)) s++; diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index d859a13bd..95984fc23 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -82,7 +82,9 @@ grub_script_break (grub_command_t cmd, int argc, char *argv[]) return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad break"); is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0; - active_breaks = grub_min (active_loops, count); + active_breaks = count; + if (active_breaks > active_loops) + active_breaks = active_loops; return GRUB_ERR_NONE; } @@ -193,7 +195,7 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) if (! grub_env_special (name)) { - char *v = grub_env_get (name); + const char *v = grub_env_get (name); if (v && v[0]) { if (type == GRUB_SCRIPT_ARG_TYPE_VAR) @@ -202,20 +204,20 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) goto fail; } else - if (grub_script_argv_append (&result, v)) + if (grub_script_argv_append (&result, v, grub_strlen (v))) goto fail; } } else if (! scope) { - if (grub_script_argv_append (&result, 0)) + if (grub_script_argv_append (&result, 0, 0)) goto fail; } else if (grub_strcmp (name, "#") == 0) { char buffer[ERRNO_DIGITS_MAX + 1]; grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc); - if (grub_script_argv_append (&result, buffer)) + if (grub_script_argv_append (&result, buffer, grub_strlen (buffer))) goto fail; } else if (grub_strcmp (name, "*") == 0) @@ -231,10 +233,11 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else { - if (i != 0 && grub_script_argv_append (&result, " ")) + if (i != 0 && grub_script_argv_append (&result, " ", 1)) goto fail; - if (grub_script_argv_append (&result, scope->argv.args[i])) + if (grub_script_argv_append (&result, scope->argv.args[i], + grub_strlen (scope->argv.args[i]))) goto fail; } } @@ -251,7 +254,8 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) goto fail; } else - if (grub_script_argv_append (&result, scope->argv.args[i])) + if (grub_script_argv_append (&result, scope->argv.args[i], + grub_strlen (scope->argv.args[i]))) goto fail; } } @@ -270,7 +274,9 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) goto fail; } else - if (grub_script_argv_append (&result, scope->argv.args[num - 1])) + if (grub_script_argv_append (&result, scope->argv.args[num - 1], + grub_strlen (scope->argv.args[num - 1]) + )) goto fail; } } @@ -309,7 +315,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, char *p = 0; if (! grub_wildcard_translator || escape_type == 0) - return grub_script_argv_append (&result, s); + return grub_script_argv_append (&result, s, grub_strlen (s)); if (escape_type > 0) p = grub_wildcard_translator->escape (s); @@ -319,7 +325,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (! p) return 1; - r = grub_script_argv_append (&result, p); + r = grub_script_argv_append (&result, p, grub_strlen (p)); grub_free (p); return r; } @@ -344,7 +350,8 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR) { - if (grub_script_argv_append (&result, values[i])) + if (grub_script_argv_append (&result, values[i], + grub_strlen (values[i]))) goto fail; } else @@ -359,22 +366,24 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, 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, "}")) + if (grub_script_argv_append (&result, "{", 1) + || grub_script_argv_append (&result, arg->str, + grub_strlen (arg->str)) + || grub_script_argv_append (&result, "}", 1)) 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)) + grub_script_argv_append (&result, arg->str, + grub_strlen (arg->str))) goto fail; break; case GRUB_SCRIPT_ARG_TYPE_DQSTR: case GRUB_SCRIPT_ARG_TYPE_SQSTR: - if (grub_script_argv_append (&result, arg->str)) + if (append (arg->str, 1)) goto fail; break; } @@ -680,7 +689,7 @@ grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd) { int ret; - char *result; + const 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 diff --git a/grub-core/script/function.c b/grub-core/script/function.c index 47b236652..ae9240116 100644 --- a/grub-core/script/function.c +++ b/grub-core/script/function.c @@ -20,6 +20,7 @@ #include #include #include +#include grub_script_function_t grub_script_function_list; @@ -99,7 +100,14 @@ grub_script_function_find (char *functionname) break; if (! func) - grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%.20s'", functionname); + { + char tmp[21]; + grub_strncpy (tmp, functionname, 20); + tmp[20] = 0; + /* Avoid truncating inside UTF-8 character. */ + tmp[grub_getend (tmp, tmp + grub_strlen (tmp))] = 0; + grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", tmp); + } return func; } diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c index 909b515fa..bf3bb487b 100644 --- a/grub-core/script/lexer.c +++ b/grub-core/script/lexer.c @@ -24,6 +24,7 @@ #include #include +#define yytext_ptr char * #include "grub_script.tab.h" #include "grub_script.yy.h" @@ -106,7 +107,9 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) if (lexer->recordpos + len + 1 > lexer->recordlen) { old = lexer->recording; - lexer->recordlen = grub_max (len, lexer->recordlen) * 2; + if (lexer->recordlen < len) + lexer->recordlen = len; + lexer->recordlen *= 2; lexer->recording = grub_realloc (lexer->recording, lexer->recordlen); if (!lexer->recording) { @@ -126,7 +129,7 @@ int grub_script_lexer_yywrap (struct grub_parser_param *parserstate, const char *input) { - int len; + int len = 0; char *p = 0; char *line = 0; YY_BUFFER_STATE buffer; diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y index 88c7fe9e3..cc20b5479 100644 --- a/grub-core/script/parser.y +++ b/grub-core/script/parser.y @@ -74,7 +74,6 @@ %token GRUB_PARSER_TOKEN_THEN "then" %token GRUB_PARSER_TOKEN_UNTIL "until" %token GRUB_PARSER_TOKEN_WHILE "while" -%token GRUB_PARSER_TOKEN_TIME "time" %token GRUB_PARSER_TOKEN_FUNCTION "function" %token GRUB_PARSER_TOKEN_NAME "name" %token GRUB_PARSER_TOKEN_WORD "word" diff --git a/grub-core/script/yylex.l b/grub-core/script/yylex.l index 53ae4c54f..f0193ead0 100644 --- a/grub-core/script/yylex.l +++ b/grub-core/script/yylex.l @@ -24,6 +24,9 @@ #include #include "grub_script.tab.h" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + #define yyfree grub_lexer_yyfree #define yyalloc grub_lexer_yyalloc #define yyrealloc grub_lexer_yyrealloc @@ -161,7 +164,6 @@ MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n)) "}" { RECORD; return GRUB_PARSER_TOKEN_RBR; } "[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; } "]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; } -"time" { RECORD; return GRUB_PARSER_TOKEN_TIME; } "case" { RECORD; return GRUB_PARSER_TOKEN_CASE; } "do" { RECORD; return GRUB_PARSER_TOKEN_DO; } "done" { RECORD; return GRUB_PARSER_TOKEN_DONE; } @@ -314,14 +316,16 @@ grub_lexer_yyrealloc (void *ptr, yy_size_t size, static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) { - int size; + grub_size_t size; char *ptr; unsigned len; len = hint ? hint : grub_strlen (str); if (parser->lexerstate->used + len >= parser->lexerstate->size) { - size = grub_max (len, parser->lexerstate->size) * 2; + size = len * 2; + if (size < parser->lexerstate->size * 2) + size = parser->lexerstate->size * 2; ptr = grub_realloc (parser->lexerstate->text, size); if (!ptr) { @@ -355,8 +359,7 @@ 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); + grub_free (lexerstate->prefix); lexerstate->prefix = grub_strdup (text); if (! lexerstate->prefix) diff --git a/grub-core/term/arc/console.c b/grub-core/term/arc/console.c new file mode 100644 index 000000000..b7e428795 --- /dev/null +++ b/grub-core/term/arc/console.c @@ -0,0 +1,123 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +/* FIXME: use unicode. */ + +static int +readkey (struct grub_term_input *term __attribute__ ((unused))) +{ + unsigned long count; + char chr; + + if (GRUB_ARC_FIRMWARE_VECTOR->get_read_status (GRUB_ARC_STDIN)) + return -1; + + if (GRUB_ARC_FIRMWARE_VECTOR->read (GRUB_ARC_STDIN, &chr, 1, &count)) + return -1; + if (!count) + return -1; + return chr; +} + +static void +put (struct grub_term_output *term __attribute__ ((unused)), const int c) +{ + unsigned long count; + char chr = c; + + GRUB_ARC_FIRMWARE_VECTOR->write (GRUB_ARC_STDOUT, &chr, 1, &count); +} + +static struct grub_terminfo_output_state grub_console_terminfo_output; + +static grub_err_t +grub_console_init_output (struct grub_term_output *term) +{ + struct grub_arc_display_status *info = NULL; + if (GRUB_ARC_SYSTEM_PARAMETER_BLOCK->firmware_vector_length + >= ((char *) (&GRUB_ARC_FIRMWARE_VECTOR->getdisplaystatus + 1) + - (char *) GRUB_ARC_FIRMWARE_VECTOR) + && GRUB_ARC_FIRMWARE_VECTOR->getdisplaystatus) + info = GRUB_ARC_FIRMWARE_VECTOR->getdisplaystatus (GRUB_ARC_STDOUT); + if (info) + { + grub_console_terminfo_output.width = info->w; + grub_console_terminfo_output.height = info->h; + } + grub_terminfo_output_init (term); + + return 0; +} + +static struct grub_terminfo_input_state grub_console_terminfo_input = + { + .readkey = readkey + }; + +static struct grub_terminfo_output_state grub_console_terminfo_output = + { + .put = put, + .width = 80, + .height = 36 + }; + +static struct grub_term_input grub_console_term_input = + { + .name = "console", + .init = grub_terminfo_input_init, + .getkey = grub_terminfo_getkey, + .data = &grub_console_terminfo_input + }; + +static struct grub_term_output grub_console_term_output = + { + .name = "console", + .init = grub_console_init_output, + .putchar = grub_terminfo_putchar, + .getxy = grub_terminfo_getxy, + .getwh = grub_terminfo_getwh, + .gotoxy = grub_terminfo_gotoxy, + .cls = grub_terminfo_cls, + .setcolorstate = grub_terminfo_setcolorstate, + .setcursor = grub_terminfo_setcursor, + .flags = GRUB_TERM_CODE_TYPE_ASCII, + .data = &grub_console_terminfo_output, + .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR, + .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR, + }; + +void +grub_console_init_early (void) +{ + grub_term_register_input ("console", &grub_console_term_input); + grub_term_register_output ("console", &grub_console_term_output); +} + +void grub_terminfo_init (void); + +void +grub_console_init_lately (void) +{ + grub_terminfo_init (); + grub_terminfo_output_register (&grub_console_term_output, "arc"); +} diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c index 1b130bd62..bcd20d3ff 100644 --- a/grub-core/term/at_keyboard.c +++ b/grub-core/term/at_keyboard.c @@ -26,6 +26,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static short at_keyboard_status = 0; static int e0_received = 0; static int f0_received = 0; @@ -109,12 +111,12 @@ static const struct {0x38, GRUB_KEYBOARD_KEY_RIGHT_ALT}, {0x47, GRUB_KEYBOARD_KEY_HOME}, {0x48, GRUB_KEYBOARD_KEY_UP}, - {0x49, GRUB_KEYBOARD_KEY_NPAGE}, + {0x49, GRUB_KEYBOARD_KEY_PPAGE}, {0x4b, GRUB_KEYBOARD_KEY_LEFT}, {0x4d, GRUB_KEYBOARD_KEY_RIGHT}, {0x4f, GRUB_KEYBOARD_KEY_END}, {0x50, GRUB_KEYBOARD_KEY_DOWN}, - {0x51, GRUB_KEYBOARD_KEY_PPAGE}, + {0x51, GRUB_KEYBOARD_KEY_NPAGE}, {0x52, GRUB_KEYBOARD_KEY_INSERT}, {0x53, GRUB_KEYBOARD_KEY_DELETE}, }; @@ -257,6 +259,8 @@ grub_keyboard_controller_write (grub_uint8_t c) grub_outb (c, KEYBOARD_REG_DATA); } +#if !defined (GRUB_MACHINE_MIPS_LOONGSON) && !defined (GRUB_MACHINE_QEMU) && !defined (GRUB_MACHINE_MIPS_QEMU_MIPS) + static grub_uint8_t grub_keyboard_controller_read (void) { @@ -265,6 +269,8 @@ grub_keyboard_controller_read (void) return grub_inb (KEYBOARD_REG_DATA); } +#endif + static int write_mode (int mode) { @@ -326,6 +332,11 @@ set_scancodes (void) return; } +#if !(defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_QEMU) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS)) + current_set = 1; + return; +#else + grub_keyboard_controller_write (grub_keyboard_controller_orig & ~KEYBOARD_AT_TRANSLATE); @@ -341,6 +352,7 @@ set_scancodes (void) if (current_set == 1) return; grub_printf ("No supported scancode set found\n"); +#endif } static void @@ -420,11 +432,11 @@ fetch_key (int *is_break) if (!ret) { if (was_ext) - grub_printf ("Unknown key 0xe0+0x%02x from set %d\n", - at_key, current_set); + grub_dprintf ("atkeyb", "Unknown key 0xe0+0x%02x from set %d\n", + at_key, current_set); else - grub_printf ("Unknown key 0x%02x from set %d\n", - at_key, current_set); + grub_dprintf ("atkeyb", "Unknown key 0x%02x from set %d\n", + at_key, current_set); return -1; } return ret; @@ -490,7 +502,7 @@ static int grub_keyboard_getkey (void) { int key; - int is_break; + int is_break = 0; key = fetch_key (&is_break); if (key == -1) @@ -558,8 +570,13 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus keyboard_controller_wait_until_ready (); grub_inb (KEYBOARD_REG_DATA); } +#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_QEMU) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) + grub_keyboard_controller_orig = 0; + grub_keyboard_orig_set = 2; +#else grub_keyboard_controller_orig = grub_keyboard_controller_read (); grub_keyboard_orig_set = query_mode (); +#endif set_scancodes (); keyboard_controller_led (led_status); diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index 9a10d47b0..5ecd7c5b5 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -31,6 +31,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define DEFAULT_VIDEO_MODE "auto" #define DEFAULT_BORDER_WIDTH 10 @@ -52,12 +54,6 @@ struct grub_colored_char /* Color values. */ grub_video_color_t fg_color; grub_video_color_t bg_color; - - /* The width of this character minus one. */ - unsigned char width; - - /* The column index of this character. */ - unsigned char index; }; struct grub_virtual_screen @@ -128,6 +124,8 @@ static struct grub_video_render_target *text_layer; static unsigned int bitmap_width; static unsigned int bitmap_height; static struct grub_video_bitmap *bitmap; +static int blend_text_bg; +static grub_video_rgba_color_t default_bg_color = { 0, 0, 0, 0 }; static struct grub_dirty_region dirty_region; @@ -183,8 +181,6 @@ clear_char (struct grub_colored_char *c) grub_errno = GRUB_ERR_NONE; c->fg_color = virtual_screen.fg_color; c->bg_color = virtual_screen.bg_color; - c->width = 0; - c->index = 0; } static void @@ -263,7 +259,8 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, grub_video_set_active_render_target (render_target); - virtual_screen.bg_color_display = grub_video_map_rgba(0, 0, 0, 0); + virtual_screen.bg_color_display = + grub_video_map_rgba_color (default_bg_color); /* Clear out text buffer. */ for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) @@ -335,15 +332,14 @@ grub_gfxterm_fullscreen (void) double_redraw = mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); - /* Make sure screen is black. */ - color = grub_video_map_rgb (0, 0, 0); + /* Make sure screen is set to the default background color. */ + color = grub_video_map_rgba_color (default_bg_color); grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); if (double_redraw) { grub_video_swap_buffers (); grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height); } - bitmap = 0; /* Select the font to use. */ font_name = grub_env_get ("gfxterm_font"); @@ -392,12 +388,6 @@ grub_gfxterm_term_init (struct grub_term_output *term __attribute__ ((unused))) static void destroy_window (void) { - if (bitmap) - { - grub_video_bitmap_destroy (bitmap); - bitmap = 0; - } - repaint_callback = 0; grub_virtual_screen_free (); } @@ -481,26 +471,27 @@ redraw_screen_rect (unsigned int x, unsigned int y, /* Render background layer. */ grub_video_fill_rect (color, x, ty, width, h); } - - /* Render text layer as blended. */ - grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y, - x - virtual_screen.offset_x, - y - virtual_screen.offset_y, - width, height); } else { /* Render background layer. */ color = virtual_screen.bg_color_display; grub_video_fill_rect (color, x, y, width, height); - - /* Render text layer as replaced (to get texts background color). */ - grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y, - x - virtual_screen.offset_x, - y - virtual_screen.offset_y, - width, height); } + if (blend_text_bg) + /* Render text layer as blended. */ + grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y, + x - virtual_screen.offset_x, + y - virtual_screen.offset_y, + width, height); + else + /* Render text layer as replaced (to get texts background color). */ + grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_REPLACE, x, y, + x - virtual_screen.offset_x, + y - virtual_screen.offset_y, + width, height); + /* Restore saved viewport. */ grub_video_set_viewport (saved_view.x, saved_view.y, saved_view.width, saved_view.height); @@ -532,21 +523,8 @@ dirty_region_is_empty (void) } static void -dirty_region_add (int x, int y, unsigned int width, unsigned int height) +dirty_region_add_real (int x, int y, unsigned int width, unsigned int height) { - if ((width == 0) || (height == 0)) - return; - - if (repaint_scheduled) - { - x = virtual_screen.offset_x; - y = virtual_screen.offset_y; - width = virtual_screen.width; - height = virtual_screen.height; - repaint_scheduled = 0; - repaint_was_scheduled = 1; - } - if (dirty_region_is_empty ()) { dirty_region.top_left_x = x; @@ -567,6 +545,22 @@ dirty_region_add (int x, int y, unsigned int width, unsigned int height) } } +static void +dirty_region_add (int x, int y, unsigned int width, unsigned int height) +{ + if ((width == 0) || (height == 0)) + return; + + if (repaint_scheduled) + { + dirty_region_add_real (virtual_screen.offset_x, virtual_screen.offset_y, + virtual_screen.width, virtual_screen.height); + repaint_scheduled = 0; + repaint_was_scheduled = 1; + } + dirty_region_add_real (x, y, width, height); +} + static void dirty_region_add_virtualscreen (void) { @@ -619,7 +613,8 @@ paint_char (unsigned cx, unsigned cy) p = (virtual_screen.text_buffer + cx + (cy * virtual_screen.columns)); - p -= p->index; + if (!p->code) + return; /* Get glyph for character. */ glyph = grub_font_construct_glyph (virtual_screen.font, p->code); @@ -883,22 +878,18 @@ grub_gfxterm_putchar (struct grub_term_output *term, grub_errno = GRUB_ERR_NONE; p->fg_color = virtual_screen.fg_color; p->bg_color = virtual_screen.bg_color; - p->width = char_width - 1; - p->index = 0; /* If we have large glyph, add fixup info. */ if (char_width > 1) { unsigned i; - for (i = 1; i < char_width; i++) + for (i = 1; i < char_width && p + i < + virtual_screen.text_buffer + virtual_screen.columns + * virtual_screen.rows; i++) { grub_free (p[i].code); - p[i].code = grub_unicode_glyph_from_code (' '); - if (!p[i].code) - grub_errno = GRUB_ERR_NONE; - p[i].width = char_width - 1; - p[i].index = i; + p[i].code = NULL; } } @@ -945,6 +936,8 @@ calculate_normal_character_width (grub_font_t font) if (glyph->device_width > width) width = glyph->device_width; } + if (!width) + return 8; return width; } @@ -1107,7 +1100,10 @@ grub_gfxterm_set_repaint_callback (grub_gfxterm_repaint_callback_t func) static const struct grub_arg_option background_image_cmd_options[] = { - {"mode", 'm', 0, "Background image mode.", "stretch|normal", + /* TRANSLATORS: note that GRUB will accept only original keywords stretch + and normal, not the translated ones. So please put both in translation + e.g. stretch=(%STRETCH%)|normal(=%NORMAL). */ + {"mode", 'm', 0, N_("Background image mode."), N_("stretch|normal"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -1127,6 +1123,7 @@ grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt, { grub_video_bitmap_destroy (bitmap); bitmap = 0; + blend_text_bg = 0; /* Mark whole screen as dirty. */ dirty_region_add (0, 0, window.width, window.height); @@ -1166,6 +1163,8 @@ grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt, /* If bitmap was loaded correctly, display it. */ if (bitmap) { + blend_text_bg = 1; + /* Determine bitmap dimensions. */ bitmap_width = grub_video_bitmap_get_width (bitmap); bitmap_height = grub_video_bitmap_get_height (bitmap); @@ -1180,6 +1179,48 @@ grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt, return grub_errno; } +static grub_err_t +grub_gfxterm_background_color_cmd (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_video_render_target *old_target; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing operand"); + + /* Check that we have video adapter active. */ + if (grub_video_get_info (NULL) != GRUB_ERR_NONE) + return grub_errno; + + if (grub_video_parse_color (args[0], &default_bg_color) != GRUB_ERR_NONE) + return grub_errno; + + /* Destroy existing background bitmap if loaded. */ + if (bitmap) + { + grub_video_bitmap_destroy (bitmap); + bitmap = 0; + + /* Mark whole screen as dirty. */ + dirty_region_add (0, 0, window.width, window.height); + } + + /* Set the background and border colors. The background color needs to be + compatible with the text layer. */ + grub_video_get_active_render_target (&old_target); + grub_video_set_active_render_target (text_layer); + virtual_screen.bg_color = grub_video_map_rgba_color (default_bg_color); + grub_video_set_active_render_target (old_target); + virtual_screen.bg_color_display = + grub_video_map_rgba_color (default_bg_color); + blend_text_bg = 1; + + /* Mark whole screen as dirty. */ + dirty_region_add (0, 0, window.width, window.height); + + return GRUB_ERR_NONE; +} + static struct grub_term_output grub_video_term = { .name = "gfxterm", @@ -1201,6 +1242,7 @@ static struct grub_term_output grub_video_term = }; static grub_extcmd_t background_image_cmd_handle; +static grub_command_t background_color_cmd_handle; GRUB_MOD_INIT(gfxterm) { @@ -1211,10 +1253,16 @@ GRUB_MOD_INIT(gfxterm) N_("[-m (stretch|normal)] FILE"), N_("Load background image for active terminal."), background_image_cmd_options); + background_color_cmd_handle = + grub_register_command ("background_color", + grub_gfxterm_background_color_cmd, + N_("COLOR"), + N_("Set background color for active terminal.")); } GRUB_MOD_FINI(gfxterm) { + grub_unregister_command (background_color_cmd_handle); grub_unregister_extcmd (background_image_cmd_handle); grub_term_unregister_output (&grub_video_term); } diff --git a/grub-core/term/i386/pc/console.c b/grub-core/term/i386/pc/console.c index 0efeafe4e..7cf5ffc5f 100644 --- a/grub-core/term/i386/pc/console.c +++ b/grub-core/term/i386/pc/console.c @@ -20,6 +20,225 @@ #include #include #include +#include + +static void +int10_9 (grub_uint8_t ch, grub_uint16_t n) +{ + struct grub_bios_int_registers regs; + + regs.eax = ch | 0x0900; + regs.ebx = grub_console_cur_color & 0xff; + regs.ecx = n; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); +} + +/* + * BIOS call "INT 10H Function 03h" to get cursor position + * Call with %ah = 0x03 + * %bh = page + * Returns %ch = starting scan line + * %cl = ending scan line + * %dh = row (0 is top) + * %dl = column (0 is left) + */ + + +static grub_uint16_t +grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x0300; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + return ((regs.edx & 0xff) << 8) | ((regs.edx & 0xff00) >> 8); +} + +/* + * BIOS call "INT 10H Function 02h" to set cursor position + * Call with %ah = 0x02 + * %bh = page + * %dh = row (0 is top) + * %dl = column (0 is left) + */ +static void +grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), + grub_uint8_t x, grub_uint8_t y) +{ + struct grub_bios_int_registers regs; + + /* set page to 0 */ + regs.ebx = 0; + regs.eax = 0x0200; + regs.edx = (y << 8) | x; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); +} + +/* + * + * Put the character C on the console. Because GRUB wants to write a + * character with an attribute, this implementation is a bit tricky. + * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh + * (TELETYPE OUTPUT). Otherwise, save the original position, put a space, + * save the current position, restore the original position, write the + * character and the attribute, and restore the current position. + * + * The reason why this is so complicated is that there is no easy way to + * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't + * support setting a background attribute. + */ +static void +grub_console_putchar_real (grub_uint8_t c) +{ + struct grub_bios_int_registers regs; + grub_uint16_t pos; + + if (c == 7 || c == 8 || c == 0xa || c == 0xd) + { + regs.eax = c | 0x0e00; + regs.ebx = 0x0001; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return; + } + + /* get the current position */ + pos = grub_console_getxy (NULL); + + /* check the column with the width */ + if ((pos & 0xff00) >= (79 << 8)) + { + grub_console_putchar_real (0x0d); + grub_console_putchar_real (0x0a); + /* get the current position */ + pos = grub_console_getxy (NULL); + } + + /* write the character with the attribute */ + int10_9 (c, 1); + + grub_console_gotoxy (NULL, ((pos & 0xff00) >> 8) + 1, (pos & 0xff)); +} + +static void +grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), + const struct grub_unicode_glyph *c) +{ + grub_console_putchar_real (c->base); +} + +/* + * BIOS call "INT 10H Function 09h" to write character and attribute + * Call with %ah = 0x09 + * %al = (character) + * %bh = (page number) + * %bl = (attribute) + * %cx = (number of times) + */ +static void +grub_console_cls (struct grub_term_output *term) +{ + /* move the cursor to the beginning */ + grub_console_gotoxy (term, 0, 0); + + /* write spaces to the entire screen */ + int10_9 (' ', 80 * 25); + + /* move back the cursor */ + grub_console_gotoxy (term, 0, 0); +} + +/* + * void grub_console_setcursor (int on) + * BIOS call "INT 10H Function 01h" to set cursor type + * Call with %ah = 0x01 + * %ch = cursor starting scanline + * %cl = cursor ending scanline + */ +static void +grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), + int on) +{ + static grub_uint16_t console_cursor_shape = 0; + struct grub_bios_int_registers regs; + + /* check if the standard cursor shape has already been saved */ + if (!console_cursor_shape) + { + regs.eax = 0x0300; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + console_cursor_shape = regs.ecx; + if ((console_cursor_shape >> 8) >= (console_cursor_shape & 0xff)) + console_cursor_shape = 0x0d0e; + } + /* set %cx to the designated cursor shape */ + regs.ecx = on ? console_cursor_shape : 0x2000; + regs.eax = 0x0100; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); +} + +/* + * if there is a character pending, return it; otherwise return -1 + * BIOS call "INT 16H Function 01H" to check whether a character is pending + * Call with %ah = 0x1 + * Return: + * If key waiting to be input: + * %ah = keyboard scan code + * %al = ASCII character + * Zero flag = clear + * else + * Zero flag = set + * BIOS call "INT 16H Function 00H" to read character from keyboard + * Call with %ah = 0x0 + * Return: %ah = keyboard scan code + * %al = ASCII character + */ + +static int +grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) +{ + const grub_uint16_t bypass_table[] = { + 0x0100 | '\e', 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r', 0x1c00 | '\n' + }; + struct grub_bios_int_registers regs; + unsigned i; + + /* + * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would + * cause the machine to hang at the second keystroke. However, we can + * work around this problem by ensuring the presence of keystroke with + * INT 16/AH = 1 before calling INT 16/AH = 0. + */ + + regs.eax = 0x0100; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x16, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_ZERO) + return GRUB_TERM_NO_KEY; + + regs.eax = 0x0000; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x16, ®s); + if (!(regs.eax & 0xff)) + return ((regs.eax >> 8) & 0xff) | GRUB_TERM_EXTENDED; + + if ((regs.eax & 0xff) >= ' ') + return regs.eax & 0xff; + + for (i = 0; i < ARRAY_SIZE (bypass_table); i++) + if (bypass_table[i] == (regs.eax & 0xffff)) + return regs.eax & 0xff; + + return (regs.eax & 0xff) + (('a' - 1) | GRUB_TERM_CTRL); +} static const struct grub_machine_bios_data_area *bios_data_area = (struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; diff --git a/grub-core/term/i386/pc/vga_text.c b/grub-core/term/i386/pc/vga_text.c index 1685b3db0..9abffcc0a 100644 --- a/grub-core/term/i386/pc/vga_text.c +++ b/grub-core/term/i386/pc/vga_text.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007, 2008 Free Software Foundation, Inc. + * Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,27 +18,33 @@ #include #include -#include +#include #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define COLS 80 #define ROWS 25 static int grub_curr_x, grub_curr_y; -#define VGA_TEXT_SCREEN 0xb8000 +#ifdef __mips__ +#define VGA_TEXT_SCREEN ((grub_uint16_t *) 0xb00b8000) +#else +#define VGA_TEXT_SCREEN ((grub_uint16_t *) 0xb8000) +#endif static void screen_write_char (int x, int y, short c) { - ((short *) VGA_TEXT_SCREEN)[y * COLS + x] = c; + VGA_TEXT_SCREEN[y * COLS + x] = c; } static short screen_read_char (int x, int y) { - return ((short *) VGA_TEXT_SCREEN)[y * COLS + x]; + return VGA_TEXT_SCREEN[y * COLS + x]; } static void @@ -120,7 +126,7 @@ grub_vga_text_cls (struct grub_term_output *term) { int i; for (i = 0; i < ROWS * COLS; i++) - ((short *) VGA_TEXT_SCREEN)[i] = ' ' | (grub_console_cur_color << 8); + VGA_TEXT_SCREEN[i] = ' ' | (grub_console_cur_color << 8); grub_vga_text_gotoxy (term, 0, 0); } diff --git a/grub-core/term/ieee1275/ofconsole.c b/grub-core/term/ieee1275/console.c similarity index 77% rename from grub-core/term/ieee1275/ofconsole.c rename to grub-core/term/ieee1275/console.c index 2b0bddbbb..d8c56e70d 100644 --- a/grub-core/term/ieee1275/ofconsole.c +++ b/grub-core/term/ieee1275/console.c @@ -1,4 +1,4 @@ -/* ofconsole.c -- Open Firmware console for GRUB. */ +/* console.c -- Open Firmware console for GRUB. */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. @@ -29,7 +29,7 @@ static grub_ieee1275_ihandle_t stdout_ihandle; static grub_ieee1275_ihandle_t stdin_ihandle; -extern struct grub_terminfo_output_state grub_ofconsole_terminfo_output; +extern struct grub_terminfo_output_state grub_console_terminfo_output; struct color { @@ -74,7 +74,7 @@ readkey (struct grub_term_input *term __attribute__ ((unused))) } static void -grub_ofconsole_dimensions (void) +grub_console_dimensions (void) { grub_ieee1275_ihandle_t options; grub_ssize_t lval; @@ -90,7 +90,7 @@ grub_ofconsole_dimensions (void) if (! grub_ieee1275_get_property (options, "screen-#columns", val, lval, 0)) - grub_ofconsole_terminfo_output.width + grub_console_terminfo_output.width = (grub_uint8_t) grub_strtoul (val, 0, 10); } if (! grub_ieee1275_get_property_length (options, "screen-#rows", &lval) @@ -99,20 +99,20 @@ grub_ofconsole_dimensions (void) char val[lval]; if (! grub_ieee1275_get_property (options, "screen-#rows", val, lval, 0)) - grub_ofconsole_terminfo_output.height + grub_console_terminfo_output.height = (grub_uint8_t) grub_strtoul (val, 0, 10); } } /* Use a small console by default. */ - if (! grub_ofconsole_terminfo_output.width) - grub_ofconsole_terminfo_output.width = 80; - if (! grub_ofconsole_terminfo_output.height) - grub_ofconsole_terminfo_output.height = 24; + if (! grub_console_terminfo_output.width) + grub_console_terminfo_output.width = 80; + if (! grub_console_terminfo_output.height) + grub_console_terminfo_output.height = 24; } static void -grub_ofconsole_setcursor (struct grub_term_output *term, +grub_console_setcursor (struct grub_term_output *term, int on) { grub_terminfo_setcursor (term, on); @@ -128,7 +128,7 @@ grub_ofconsole_setcursor (struct grub_term_output *term, } static grub_err_t -grub_ofconsole_init_input (struct grub_term_input *term) +grub_console_init_input (struct grub_term_input *term) { grub_ssize_t actual; @@ -141,7 +141,7 @@ grub_ofconsole_init_input (struct grub_term_input *term) } static grub_err_t -grub_ofconsole_init_output (struct grub_term_output *term) +grub_console_init_output (struct grub_term_output *term) { grub_ssize_t actual; @@ -168,46 +168,48 @@ grub_ofconsole_init_output (struct grub_term_output *term) grub_terminfo_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); } - grub_ofconsole_dimensions (); + grub_console_dimensions (); + + grub_terminfo_output_init (term); return 0; } -struct grub_terminfo_input_state grub_ofconsole_terminfo_input = +struct grub_terminfo_input_state grub_console_terminfo_input = { .readkey = readkey }; -struct grub_terminfo_output_state grub_ofconsole_terminfo_output = +struct grub_terminfo_output_state grub_console_terminfo_output = { .put = put, .width = 80, .height = 24 }; -static struct grub_term_input grub_ofconsole_term_input = +static struct grub_term_input grub_console_term_input = { - .name = "ofconsole", - .init = grub_ofconsole_init_input, + .name = "console", + .init = grub_console_init_input, .getkey = grub_terminfo_getkey, - .data = &grub_ofconsole_terminfo_input + .data = &grub_console_terminfo_input }; -static struct grub_term_output grub_ofconsole_term_output = +static struct grub_term_output grub_console_term_output = { - .name = "ofconsole", - .init = grub_ofconsole_init_output, + .name = "console", + .init = grub_console_init_output, .putchar = grub_terminfo_putchar, .getxy = grub_terminfo_getxy, .getwh = grub_terminfo_getwh, .gotoxy = grub_terminfo_gotoxy, .cls = grub_terminfo_cls, .setcolorstate = grub_terminfo_setcolorstate, - .setcursor = grub_ofconsole_setcursor, + .setcursor = grub_console_setcursor, .flags = GRUB_TERM_CODE_TYPE_ASCII, - .data = &grub_ofconsole_terminfo_output, + .data = &grub_console_terminfo_output, .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR, .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR, }; @@ -218,8 +220,8 @@ void grub_terminfo_init (void); void grub_console_init_early (void) { - grub_term_register_input ("ofconsole", &grub_ofconsole_term_input); - grub_term_register_output ("ofconsole", &grub_ofconsole_term_output); + grub_term_register_input ("console", &grub_console_term_input); + grub_term_register_output ("console", &grub_console_term_output); } void @@ -233,15 +235,15 @@ grub_console_init_lately (void) type = "ieee1275"; grub_terminfo_init (); - grub_terminfo_output_register (&grub_ofconsole_term_output, type); + grub_terminfo_output_register (&grub_console_term_output, type); } void grub_console_fini (void) { - grub_term_unregister_input (&grub_ofconsole_term_input); - grub_term_unregister_output (&grub_ofconsole_term_output); - grub_terminfo_output_unregister (&grub_ofconsole_term_output); + grub_term_unregister_input (&grub_console_term_input); + grub_term_unregister_output (&grub_console_term_output); + grub_terminfo_output_unregister (&grub_console_term_output); grub_terminfo_fini (); } diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c index 550ee6341..996fc81f3 100644 --- a/grub-core/term/ns8250.c +++ b/grub-core/term/ns8250.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef GRUB_MACHINE_PCBIOS #include @@ -36,7 +37,8 @@ static const grub_port_t serial_hw_io_addr[] = GRUB_MACHINE_SERIAL_PORTS; /* Convert speed to divisor. */ static unsigned short -serial_get_divisor (unsigned int speed) +serial_get_divisor (const struct grub_serial_port *port __attribute__ ((unused)), + const struct grub_serial_config *config) { unsigned int i; @@ -62,13 +64,16 @@ serial_get_divisor (unsigned int speed) /* Set the baud rate. */ for (i = 0; i < ARRAY_SIZE (divisor_tab); i++) - if (divisor_tab[i].speed == speed) - /* UART in Yeeloong runs twice the usual rate. */ -#ifdef GRUB_MACHINE_MIPS_YEELOONG - return 2 * divisor_tab[i].div; -#else - return divisor_tab[i].div; + if (divisor_tab[i].speed == config->speed) + { + /* internal Loongson UART runs twice the usual rate. */ +#ifdef GRUB_MACHINE_MIPS_LOONGSON + if (port->port == 0xbff003f8) + return 2 * divisor_tab[i].div; + else #endif + return divisor_tab[i].div; + } return 0; } @@ -90,7 +95,9 @@ do_real_config (struct grub_serial_port *port) if (port->configured) return; - divisor = serial_get_divisor (port->config.speed); + port->broken = 0; + + divisor = serial_get_divisor (port, &port->config); /* Turn off the interrupt. */ grub_outb (0, port->port + UART_IER); @@ -108,8 +115,8 @@ do_real_config (struct grub_serial_port *port) | stop_bits[port->config.stop_bits]); grub_outb (status, port->port + UART_LCR); - /* In Yeeloong serial port has only 3 wires. */ -#ifndef GRUB_MACHINE_MIPS_YEELOONG + /* On Loongson machines serial port has only 3 wires. */ +#ifndef GRUB_MACHINE_MIPS_LOONGSON /* Enable the FIFO. */ grub_outb (UART_ENABLE_FIFO_TRIGGER1, port->port + UART_FCR); @@ -145,18 +152,30 @@ serial_hw_fetch (struct grub_serial_port *port) static void serial_hw_put (struct grub_serial_port *port, const int c) { - unsigned int timeout = 100000; + grub_uint64_t endtime; do_real_config (port); + if (port->broken > 5) + endtime = grub_get_time_ms (); + else if (port->broken > 1) + endtime = grub_get_time_ms () + 50; + else + endtime = grub_get_time_ms () + 200; /* Wait until the transmitter holding register is empty. */ while ((grub_inb (port->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0) { - if (--timeout == 0) - /* There is something wrong. But what can I do? */ - return; + if (grub_get_time_ms () > endtime) + { + port->broken++; + /* There is something wrong. But what can I do? */ + return; + } } + if (port->broken) + port->broken--; + grub_outb (c, port->port + UART_TX); } @@ -173,7 +192,7 @@ serial_hw_configure (struct grub_serial_port *port, { unsigned short divisor; - divisor = serial_get_divisor (config->speed); + divisor = serial_get_divisor (port, config); if (divisor == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed"); diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c index 1ef17aa25..20ab90d92 100644 --- a/grub-core/term/serial.c +++ b/grub-core/term/serial.c @@ -26,6 +26,11 @@ #include #include #include +#ifdef GRUB_MACHINE_MIPS_LOONGSON +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); #define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports)) @@ -41,7 +46,7 @@ static const struct grub_arg_option options[] = {0, 0, 0, 0, 0, 0} }; -struct grub_serial_port *grub_serial_ports; +static struct grub_serial_port *grub_serial_ports; struct grub_serial_output_state { @@ -69,7 +74,7 @@ serial_fetch (grub_term_input_t term) return data->port->driver->fetch (data->port); } -struct grub_serial_input_state grub_serial_terminfo_input = +static const struct grub_serial_input_state grub_serial_terminfo_input_template = { .tinfo = { @@ -77,7 +82,7 @@ struct grub_serial_input_state grub_serial_terminfo_input = } }; -struct grub_serial_output_state grub_serial_terminfo_output = +static const struct grub_serial_output_state grub_serial_terminfo_output_template = { .tinfo = { @@ -87,7 +92,11 @@ struct grub_serial_output_state grub_serial_terminfo_output = } }; -int registered = 0; +static struct grub_serial_input_state grub_serial_terminfo_input; + +static struct grub_serial_output_state grub_serial_terminfo_output; + +static int registered = 0; static struct grub_term_input grub_serial_term_input = { @@ -100,6 +109,7 @@ static struct grub_term_input grub_serial_term_input = static struct grub_term_output grub_serial_term_output = { .name = "serial", + .init = grub_terminfo_output_init, .putchar = grub_terminfo_putchar, .getwh = grub_terminfo_getwh, .getxy = grub_terminfo_getxy, @@ -115,8 +125,8 @@ static struct grub_term_output grub_serial_term_output = -static struct grub_serial_port * -grub_serial_find (char *name) +struct grub_serial_port * +grub_serial_find (const char *name) { struct grub_serial_port *port; @@ -126,7 +136,7 @@ grub_serial_find (char *name) #ifndef GRUB_MACHINE_EMU if (!port && grub_memcmp (name, "port", sizeof ("port") - 1) == 0 - && grub_isdigit (name [sizeof ("port") - 1])) + && grub_isxdigit (name [sizeof ("port") - 1])) { name = grub_serial_ns8250_add_port (grub_strtoul (&name[sizeof ("port") - 1], 0, 16)); @@ -147,7 +157,7 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) { struct grub_arg_list *state = ctxt->state; char pname[40]; - char *name = NULL; + const char *name = NULL; struct grub_serial_port *port; struct grub_serial_config config; grub_err_t err; @@ -216,6 +226,8 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) { if (!registered) { + grub_terminfo_output_register (&grub_serial_term_output, "vt100"); + grub_term_register_input ("serial", &grub_serial_term_input); grub_term_register_output ("serial", &grub_serial_term_output); } @@ -227,6 +239,15 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) return GRUB_ERR_NONE; } +#ifdef GRUB_MACHINE_MIPS_LOONGSON +const char loongson_defserial[][6] = + { + [GRUB_ARCH_MACHINE_YEELOONG] = "com0", + [GRUB_ARCH_MACHINE_FULOONG2F] = "com2", + [GRUB_ARCH_MACHINE_FULOONG2E] = "com1" + }; +#endif + grub_err_t grub_serial_register (struct grub_serial_port *port) { @@ -288,18 +309,32 @@ grub_serial_register (struct grub_serial_port *port) port->term_in = in; port->term_out = out; grub_terminfo_output_register (out, "vt100"); -#ifdef GRUB_MACHINE_MIPS_YEELOONG +#ifdef GRUB_MACHINE_MIPS_LOONGSON + if (grub_strcmp (port->name, loongson_defserial[grub_arch_machine]) == 0) + { + grub_term_register_input_active ("serial_*", in); + grub_term_register_output_active ("serial_*", out); + } + else + { + grub_term_register_input_inactive ("serial_*", in); + grub_term_register_output_inactive ("serial_*", out); + } +#elif defined (GRUB_MACHINE_MIPS_QEMU_MIPS) if (grub_strcmp (port->name, "com0") == 0) { grub_term_register_input_active ("serial_*", in); grub_term_register_output_active ("serial_*", out); } else -#endif { - grub_term_register_input ("serial_*", in); - grub_term_register_output ("serial_*", out); + grub_term_register_input_inactive ("serial_*", in); + grub_term_register_output_inactive ("serial_*", out); } +#else + grub_term_register_input ("serial_*", in); + grub_term_register_output ("serial_*", out); +#endif return GRUB_ERR_NONE; } @@ -315,7 +350,7 @@ grub_serial_unregister (struct grub_serial_port *port) if (port->term_out) grub_term_unregister_output (port->term_out); - grub_list_remove (GRUB_AS_LIST_P (&grub_serial_ports), GRUB_AS_LIST (port)); + grub_list_remove (GRUB_AS_LIST (port)); } void @@ -337,6 +372,14 @@ GRUB_MOD_INIT(serial) cmd = grub_register_extcmd ("serial", grub_cmd_serial, 0, N_("[OPTIONS...]"), N_("Configure serial port."), options); + grub_memcpy (&grub_serial_terminfo_output, + &grub_serial_terminfo_output_template, + sizeof (grub_serial_terminfo_output)); + + grub_memcpy (&grub_serial_terminfo_input, + &grub_serial_terminfo_input_template, + sizeof (grub_serial_terminfo_input)); + #ifndef GRUB_MACHINE_EMU grub_ns8250_init (); #endif diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c index d01811959..d4f5c88c6 100644 --- a/grub-core/term/terminfo.c +++ b/grub-core/term/terminfo.c @@ -34,6 +34,11 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + +#define ANSI_C0 0x9b +#define ANSI_C0_STR "\x9b" + static struct grub_term_output *terminfo_outputs; /* Get current terminfo name. */ @@ -121,6 +126,20 @@ grub_terminfo_set_current (struct grub_term_output *term, return grub_errno; } + if (grub_strcmp ("arc", str) == 0) + { + data->name = grub_strdup ("arc"); + data->gotoxy = grub_strdup (ANSI_C0_STR "%i%p1%d;%p2%dH"); + data->cls = grub_strdup (ANSI_C0_STR "2J"); + data->reverse_video_on = grub_strdup (ANSI_C0_STR "7m"); + data->reverse_video_off = grub_strdup (ANSI_C0_STR "0m"); + data->cursor_on = 0; + data->cursor_off = 0; + data->setcolor = grub_strdup (ANSI_C0_STR "3%p1%dm" + ANSI_C0_STR "4%p2%dm"); + return grub_errno; + } + if (grub_strcmp ("ieee1275", str) == 0) { data->name = grub_strdup ("ieee1275"); @@ -367,8 +386,6 @@ grub_terminfo_getwh (struct grub_term_output *term) return (data->width << 8) | data->height; } -#define ANSI_C0 0x9b - static void grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, int (*readkey) (struct grub_term_input *term)) @@ -403,6 +420,8 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, /* Backspace: Ctrl-h. */ if (c == 0x7f) c = '\b'; + if (c < 0x20 && c != '\t' && c!= '\b' && c != '\n' && c != '\r') + c = GRUB_TERM_CTRL | (c - 1 + 'a'); *len = 1; keys[0] = c; return; @@ -426,7 +445,8 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, {'K', GRUB_TERM_KEY_END}, {'P', GRUB_TERM_KEY_DC}, {'?', GRUB_TERM_KEY_PPAGE}, - {'/', GRUB_TERM_KEY_NPAGE} + {'/', GRUB_TERM_KEY_NPAGE}, + {'@', GRUB_TERM_KEY_INSERT}, }; static struct @@ -441,6 +461,14 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, {'5', GRUB_TERM_KEY_PPAGE}, {'6', GRUB_TERM_KEY_NPAGE} }; + char fx_key[] = + { 'P', 'Q', 'w', 'x', 't', 'u', + 'q', 'r', 'p', 'M', 'A', 'B' }; + unsigned fx_code[] = + { GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, + GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, + GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, + GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12 }; unsigned i; if (c == '\e') @@ -461,17 +489,53 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, return; } - for (i = 0; i < ARRAY_SIZE (four_code_table); i++) - if (four_code_table[i].key == c) + switch (c) + { + case 'O': + CONTINUE_READ; + for (i = 0; i < ARRAY_SIZE (fx_key); i++) + if (fx_key[i] == c) + { + keys[0] = fx_code[i]; + *len = 1; + return; + } + return; + + case '0': { + int num = 0; CONTINUE_READ; - if (c != '~') + if (c != '0' && c != '1') return; - keys[0] = three_code_table[i].ascii; + num = (c - '0') * 10; + CONTINUE_READ; + if (c < '0' || c > '9') + return; + num += (c - '0'); + if (num == 0 || num > 12) + return; + CONTINUE_READ; + if (c != 'q') + return; + keys[0] = fx_code[num - 1]; *len = 1; return; - } - return; + } + + default: + for (i = 0; i < ARRAY_SIZE (four_code_table); i++) + if (four_code_table[i].key == c) + { + CONTINUE_READ; + if (c != '~') + return; + keys[0] = three_code_table[i].ascii; + *len = 1; + return; + } + return; + } } #undef CONTINUE_READ } @@ -512,6 +576,13 @@ grub_terminfo_input_init (struct grub_term_input *termi) return GRUB_ERR_NONE; } +grub_err_t +grub_terminfo_output_init (struct grub_term_output *term) +{ + grub_terminfo_cls (term); + return GRUB_ERR_NONE; +} + /* GRUB Command. */ static grub_err_t @@ -535,7 +606,7 @@ print_terminfo (void) }; struct grub_term_output *cur; - grub_printf ("Current terminfo types: \n"); + grub_puts_ (N_("Current terminfo types:")); for (cur = terminfo_outputs; cur; cur = ((struct grub_terminfo_output_state *) cur->data)->next) grub_printf ("%s: %s\t%s\n", cur->name, @@ -602,7 +673,9 @@ grub_cmd_terminfo (grub_extcmd_context_t ctxt, int argc, char **args) for (cur = terminfo_outputs; cur; cur = ((struct grub_terminfo_output_state *) cur->data)->next) - if (grub_strcmp (args[0], cur->name) == 0) + if (grub_strcmp (args[0], cur->name) == 0 + || (grub_strcmp (args[0], "ofconsole") == 0 + && grub_strcmp ("console", cur->name) == 0)) { cur->flags = (cur->flags & ~GRUB_TERM_CODE_TYPE_MASK) | encoding; diff --git a/grub-core/term/tparm.c b/grub-core/term/tparm.c index 076a192a5..8c1c288a0 100644 --- a/grub-core/term/tparm.c +++ b/grub-core/term/tparm.c @@ -745,7 +745,7 @@ tparam_internal(const char *string, va_list ap) return (out_buff); } -char * +const char * grub_terminfo_tparm (const char *string, ...) { va_list ap; diff --git a/grub-core/term/usb_keyboard.c b/grub-core/term/usb_keyboard.c index 30ed8f9c2..ae00936b8 100644 --- a/grub-core/term/usb_keyboard.c +++ b/grub-core/term/usb_keyboard.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + enum @@ -435,7 +437,7 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term) return interpret_status (termdata->status) | termdata->mods; } -struct grub_usb_attach_desc attach_hook = +static struct grub_usb_attach_desc attach_hook = { .class = GRUB_USB_CLASS_HID, .hook = grub_usb_keyboard_attach diff --git a/grub-core/tests/example_functional_test.c b/grub-core/tests/example_functional_test.c index 525988145..802088791 100644 --- a/grub-core/tests/example_functional_test.c +++ b/grub-core/tests/example_functional_test.c @@ -18,6 +18,9 @@ /* All tests need to include test.h for GRUB testing framework. */ #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* Functional test main method. */ static void diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c index 521f4ad22..fd199bd63 100644 --- a/grub-core/tests/lib/functional_test.c +++ b/grub-core/tests/lib/functional_test.c @@ -20,6 +20,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static grub_err_t grub_functional_test (grub_extcmd_context_t ctxt __attribute__ ((unused)), diff --git a/grub-core/tests/lib/test.c b/grub-core/tests/lib/test.c index 06d78b7d7..da688efc0 100644 --- a/grub-core/tests/lib/test.c +++ b/grub-core/tests/lib/test.c @@ -24,6 +24,7 @@ struct grub_test_failure { /* The next failure. */ struct grub_test_failure *next; + struct grub_test_failure **prev; /* The test source file name. */ char *file; @@ -124,7 +125,7 @@ grub_test_unregister (const char *name) if (test) { - grub_list_remove (GRUB_AS_LIST_P (&grub_test_list), GRUB_AS_LIST (test)); + grub_list_remove (GRUB_AS_LIST (test)); if (test->name) grub_free (test->name); diff --git a/grub-core/tests/test_blockarg.c b/grub-core/tests/test_blockarg.c index 41460fb7e..ddd46e1f6 100644 --- a/grub-core/tests/test_blockarg.c +++ b/grub-core/tests/test_blockarg.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_err_t test_blockarg (grub_extcmd_context_t ctxt, int argc, char **args) { diff --git a/grub-core/video/bitmap.c b/grub-core/video/bitmap.c index e06a5b696..32e9358a3 100644 --- a/grub-core/video/bitmap.c +++ b/grub-core/video/bitmap.c @@ -23,6 +23,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* List of bitmap readers registered to system. */ static grub_video_bitmap_reader_t bitmap_readers_list; @@ -177,7 +179,7 @@ match_extension (const char *filename, const char *ext) pos -= ext_len; - return grub_strcmp (filename + pos, ext) == 0; + return grub_strcasecmp (filename + pos, ext) == 0; } /* Loads bitmap using registered bitmap readers. */ diff --git a/grub-core/video/bitmap_scale.c b/grub-core/video/bitmap_scale.c index 6f8ff247e..8da5697f8 100644 --- a/grub-core/video/bitmap_scale.c +++ b/grub-core/video/bitmap_scale.c @@ -23,6 +23,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); /* Prototypes for module-local functions. */ static grub_err_t scale_nn (struct grub_video_bitmap *dst, diff --git a/grub-core/video/bochs.c b/grub-core/video/bochs.c index 5def0985b..79cae6547 100644 --- a/grub-core/video/bochs.c +++ b/grub-core/video/bochs.c @@ -28,6 +28,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static struct { struct grub_video_mode_info mode_info; @@ -199,7 +201,8 @@ grub_video_bochs_set_palette (unsigned int start, unsigned int count, static grub_err_t grub_video_bochs_setup (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask) + grub_video_mode_type_t mode_type, + grub_video_mode_type_t mode_mask) { int depth; grub_err_t err; diff --git a/grub-core/video/cirrus.c b/grub-core/video/cirrus.c index b8b0142ad..7fad50e5b 100644 --- a/grub-core/video/cirrus.c +++ b/grub-core/video/cirrus.c @@ -28,6 +28,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static struct { struct grub_video_mode_info mode_info; @@ -235,7 +237,8 @@ grub_video_cirrus_set_palette (unsigned int start, unsigned int count, static grub_err_t grub_video_cirrus_setup (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask) + grub_video_mode_type_t mode_type, + grub_video_mode_type_t mode_mask) { int depth; grub_err_t err; diff --git a/grub-core/gfxmenu/named_colors.c b/grub-core/video/colors.c similarity index 71% rename from grub-core/gfxmenu/named_colors.c rename to grub-core/video/colors.c index eedbc47fb..06625183e 100644 --- a/grub-core/gfxmenu/named_colors.c +++ b/grub-core/video/colors.c @@ -21,11 +21,14 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); struct named_color { const char *name; - grub_gui_color_t color; + grub_video_rgba_color_t color; }; /* @@ -193,8 +196,8 @@ static struct named_color named_colors[] = stores the color into *COLOR. If the color was not found, returns 0 and does not modify *COLOR. */ int -grub_gui_get_named_color (const char *name, - grub_gui_color_t *color) +grub_video_get_named_color (const char *name, + grub_video_rgba_color_t *color) { int i; for (i = 0; named_colors[i].name; i++) @@ -207,3 +210,116 @@ grub_gui_get_named_color (const char *name, } return 0; } + +static int +parse_hex_color_component (const char *s, unsigned start, unsigned end) +{ + unsigned len; + char buf[3]; + + len = end - start; + /* Check the limits so we don't overrun the buffer. */ + if (len < 1 || len > 2) + return 0; + + if (len == 1) + { + buf[0] = s[start]; /* Get the first and only hex digit. */ + buf[1] = buf[0]; /* Duplicate the hex digit. */ + } + else if (len == 2) + { + buf[0] = s[start]; + buf[1] = s[start + 1]; + } + + buf[2] = '\0'; + + return grub_strtoul (buf, 0, 16); +} + +/* Parse a color string of the form "r, g, b", "#RGB", "#RGBA", + "#RRGGBB", or "#RRGGBBAA". */ +grub_err_t +grub_video_parse_color (const char *s, grub_video_rgba_color_t *color) +{ + grub_video_rgba_color_t c; + + /* Skip whitespace. */ + while (*s && grub_isspace (*s)) + s++; + + if (*s == '#') + { + /* HTML-style. Number if hex digits: + [6] #RRGGBB [3] #RGB + [8] #RRGGBBAA [4] #RGBA */ + + s++; /* Skip the '#'. */ + /* Count the hexits to determine the format. */ + int hexits = 0; + const char *end = s; + while (grub_isxdigit (*end)) + { + end++; + hexits++; + } + + /* Parse the color components based on the format. */ + if (hexits == 3 || hexits == 4) + { + c.red = parse_hex_color_component (s, 0, 1); + c.green = parse_hex_color_component (s, 1, 2); + c.blue = parse_hex_color_component (s, 2, 3); + if (hexits == 4) + c.alpha = parse_hex_color_component (s, 3, 4); + else + c.alpha = 255; + } + else if (hexits == 6 || hexits == 8) + { + c.red = parse_hex_color_component (s, 0, 2); + c.green = parse_hex_color_component (s, 2, 4); + c.blue = parse_hex_color_component (s, 4, 6); + if (hexits == 8) + c.alpha = parse_hex_color_component (s, 6, 8); + else + c.alpha = 255; + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid HTML-type color string `%s'", s); + } + else if (grub_isdigit (*s)) + { + /* Comma separated decimal values. */ + c.red = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing 1st comma separator in color `%s'", s); + s++; + c.green = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing 2nd comma separator in color `%s'", s); + s++; + c.blue = grub_strtoul (s, 0, 0); + if ((s = grub_strchr (s, ',')) == 0) + c.alpha = 255; + else + { + s++; + c.alpha = grub_strtoul (s, 0, 0); + } + } + else + { + if (! grub_video_get_named_color (s, &c)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid named color `%s'", s); + } + + if (grub_errno == GRUB_ERR_NONE) + *color = c; + return grub_errno; +} diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c index f02dc9cb6..d14ae98d2 100644 --- a/grub-core/video/efi_gop.c +++ b/grub-core/video/efi_gop.c @@ -29,6 +29,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GOP_GUID; static struct grub_efi_gop *gop; static unsigned old_mode; diff --git a/grub-core/video/efi_uga.c b/grub-core/video/efi_uga.c index a8f70edea..1e709a52d 100644 --- a/grub-core/video/efi_uga.c +++ b/grub-core/video/efi_uga.c @@ -30,6 +30,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID; static struct grub_efi_uga_draw_protocol *uga; static grub_uint32_t uga_fb; diff --git a/grub-core/video/emu/sdl.c b/grub-core/video/emu/sdl.c index d66b8b0c0..f4c1a6ab6 100644 --- a/grub-core/video/emu/sdl.c +++ b/grub-core/video/emu/sdl.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static SDL_Surface *window = 0; static struct grub_video_render_target *sdl_render_target; static struct grub_video_mode_info mode_info; diff --git a/grub-core/video/fb/fbblit.c b/grub-core/video/fb/fbblit.c index 15797be97..4d262d710 100644 --- a/grub-core/video/fb/fbblit.c +++ b/grub-core/video/fb/fbblit.c @@ -80,13 +80,14 @@ grub_video_fbblit_replace_directN (struct grub_video_fbblit_info *dst, int bpp; bpp = src->mode_info->bytes_per_pixel; + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - grub_memmove (dstptr, srcptr, width * bpp); + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, src->mode_info->pitch); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dst->mode_info->pitch); } } @@ -101,7 +102,7 @@ grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, int i; int j; grub_uint8_t *srcptr; - grub_uint8_t *dstptr; + grub_uint32_t *dstptr; grub_uint8_t srcmask; unsigned int dstrowskip; unsigned int srcrowskipbyte, srcrowskipbit; @@ -117,7 +118,7 @@ grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -134,9 +135,9 @@ grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, for (i = 0; i < width; i++) { if (*srcptr & srcmask) - *(grub_uint32_t *) dstptr = fgcolor; + *dstptr = fgcolor; else - *(grub_uint32_t *) dstptr = bgcolor; + *dstptr = bgcolor; srcmask >>= 1; if (!srcmask) { @@ -144,7 +145,7 @@ grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, srcmask = 0x80; } - dstptr += 4; + dstptr++; } srcptr += srcrowskipbyte; @@ -155,11 +156,12 @@ grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, srcptr++; srcmask <<= 8 - srcrowskipbit; } - dstptr += dstrowskip; + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } +#ifdef GRUB_HAVE_UNALIGNED_ACCESS /* Optimized replacing blitter for 1-bit to 24-bit. */ void grub_video_fbblit_replace_24bit_1bit (struct grub_video_fbblit_info *dst, @@ -187,7 +189,7 @@ grub_video_fbblit_replace_24bit_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -247,6 +249,7 @@ grub_video_fbblit_replace_24bit_1bit (struct grub_video_fbblit_info *dst, dstptr += dstrowskip; } } +#endif /* Optimized replacing blitter for 1-bit to 16-bit. */ void @@ -259,7 +262,7 @@ grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, int i; int j; grub_uint8_t *srcptr; - grub_uint8_t *dstptr; + grub_uint16_t *dstptr; grub_uint8_t srcmask; unsigned int dstrowskip; unsigned int srcrowskipbyte, srcrowskipbit; @@ -275,7 +278,7 @@ grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -292,9 +295,9 @@ grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, for (i = 0; i < width; i++) { if (*srcptr & srcmask) - *(grub_uint16_t *) dstptr = fgcolor; + *dstptr = fgcolor; else - *(grub_uint16_t *) dstptr = bgcolor; + *dstptr = bgcolor; srcmask >>= 1; if (!srcmask) { @@ -302,7 +305,7 @@ grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, srcmask = 0x80; } - dstptr += 2; + dstptr++; } srcptr += srcrowskipbyte; @@ -313,7 +316,7 @@ grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, srcptr++; srcmask <<= 8 - srcrowskipbit; } - dstptr += dstrowskip; + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -344,7 +347,7 @@ grub_video_fbblit_replace_8bit_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -361,9 +364,9 @@ grub_video_fbblit_replace_8bit_1bit (struct grub_video_fbblit_info *dst, for (i = 0; i < width; i++) { if (*srcptr & srcmask) - *(grub_uint8_t *) dstptr = fgcolor; + *dstptr = fgcolor; else - *(grub_uint8_t *) dstptr = bgcolor; + *dstptr = bgcolor; srcmask >>= 1; if (!srcmask) { @@ -406,8 +409,8 @@ grub_video_fbblit_replace_BGRX8888_RGBX8888 (struct grub_video_fbblit_info *dst, srcrowskip = src->mode_info->pitch - src->mode_info->bytes_per_pixel * width; dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; - srcptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (src, offset_x, offset_y); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -449,8 +452,8 @@ grub_video_fbblit_replace_BGRX8888_RGB888 (struct grub_video_fbblit_info *dst, srcrowskip = src->mode_info->pitch - src->mode_info->bytes_per_pixel * width; dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; - srcptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (src, offset_x, offset_y); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -493,8 +496,8 @@ grub_video_fbblit_replace_BGR888_RGBX8888 (struct grub_video_fbblit_info *dst, srcrowskip = src->mode_info->pitch - src->mode_info->bytes_per_pixel * width; dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; - srcptr = (grub_uint32_t *) grub_video_fb_get_video_ptr (src, offset_x, offset_y); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -516,7 +519,7 @@ grub_video_fbblit_replace_BGR888_RGBX8888 (struct grub_video_fbblit_info *dst, *dstptr++ = sr; } - srcptr = (grub_uint32_t *) (((grub_uint8_t *) srcptr) + srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); dstptr += dstrowskip; } } @@ -541,8 +544,8 @@ grub_video_fbblit_replace_BGR888_RGB888 (struct grub_video_fbblit_info *dst, srcrowskip = src->mode_info->pitch - src->mode_info->bytes_per_pixel * width; dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; - srcptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (src, offset_x, offset_y); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -578,12 +581,16 @@ grub_video_fbblit_replace_RGBX8888_RGB888 (struct grub_video_fbblit_info *dst, unsigned int sr; unsigned int sg; unsigned int sb; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcrowskip = src->mode_info->pitch - 3 * width; + dstrowskip = dst->mode_info->pitch - 4 * width; + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { sr = *srcptr++; @@ -595,6 +602,8 @@ grub_video_fbblit_replace_RGBX8888_RGB888 (struct grub_video_fbblit_info *dst, *dstptr++ = color; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -614,12 +623,16 @@ grub_video_fbblit_replace_RGB888_RGBX8888 (struct grub_video_fbblit_info *dst, unsigned int sr; unsigned int sg; unsigned int sb; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); + srcrowskip = src->mode_info->pitch - 4 * width; + dstrowskip = dst->mode_info->pitch - 3 * width; for (j = 0; j < height; j++) { - srcptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { color = *srcptr++; @@ -632,6 +645,8 @@ grub_video_fbblit_replace_RGB888_RGBX8888 (struct grub_video_fbblit_info *dst, *dstptr++ = sg; *dstptr++ = sb; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -651,12 +666,17 @@ grub_video_fbblit_replace_index_RGBX8888 (struct grub_video_fbblit_info *dst, unsigned int sr; unsigned int sg; unsigned int sb; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcrowskip = src->mode_info->pitch - 4 * width; + dstrowskip = dst->mode_info->pitch - width; + + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { color = *srcptr++; @@ -668,6 +688,8 @@ grub_video_fbblit_replace_index_RGBX8888 (struct grub_video_fbblit_info *dst, color = grub_video_fb_map_rgb(sr, sg, sb); *dstptr++ = color & 0xFF; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -687,12 +709,17 @@ grub_video_fbblit_replace_index_RGB888 (struct grub_video_fbblit_info *dst, unsigned int sr; unsigned int sg; unsigned int sb; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcrowskip = src->mode_info->pitch - 3 * width; + dstrowskip = dst->mode_info->pitch - width; + + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { sr = *srcptr++; @@ -703,6 +730,8 @@ grub_video_fbblit_replace_index_RGB888 (struct grub_video_fbblit_info *dst, *dstptr++ = color & 0xFF; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -787,8 +816,8 @@ grub_video_fbblit_blend_BGRA8888_RGBA8888 (struct grub_video_fbblit_info *dst, srcrowskip = src->mode_info->pitch - src->mode_info->bytes_per_pixel * width; dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; - srcptr = (grub_uint32_t *) grub_video_fb_get_video_ptr (src, offset_x, offset_y); - dstptr = (grub_uint32_t *) grub_video_fb_get_video_ptr (dst, x, y); + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -843,8 +872,8 @@ grub_video_fbblit_blend_BGRA8888_RGBA8888 (struct grub_video_fbblit_info *dst, *dstptr++ = color; } - srcptr = (grub_uint32_t *) (((grub_uint8_t *) srcptr) + srcrowskip); - dstptr = (grub_uint32_t *) (((grub_uint8_t *) dstptr) + dstrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -868,8 +897,8 @@ grub_video_fbblit_blend_BGR888_RGBA8888 (struct grub_video_fbblit_info *dst, srcrowskip = src->mode_info->pitch - src->mode_info->bytes_per_pixel * width; dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; - srcptr = (grub_uint32_t *) grub_video_fb_get_video_ptr (src, offset_x, offset_y); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -924,7 +953,7 @@ grub_video_fbblit_blend_BGR888_RGBA8888 (struct grub_video_fbblit_info *dst, *dstptr++ = dr; } - srcptr = (grub_uint32_t *) (((grub_uint8_t *) srcptr) + srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); dstptr += dstrowskip; } } @@ -949,12 +978,17 @@ grub_video_fbblit_blend_RGBA8888_RGBA8888 (struct grub_video_fbblit_info *dst, unsigned int dr; unsigned int dg; unsigned int db; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcrowskip = src->mode_info->pitch - 4 * width; + dstrowskip = dst->mode_info->pitch - 4 * width; + + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { color = *srcptr++; @@ -991,6 +1025,8 @@ grub_video_fbblit_blend_RGBA8888_RGBA8888 (struct grub_video_fbblit_info *dst, *dstptr++ = color; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -1014,12 +1050,17 @@ grub_video_fbblit_blend_RGB888_RGBA8888 (struct grub_video_fbblit_info *dst, unsigned int dr; unsigned int dg; unsigned int db; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcrowskip = src->mode_info->pitch - 4 * width; + dstrowskip = dst->mode_info->pitch - 3 * width; + + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { color = *srcptr++; @@ -1057,6 +1098,8 @@ grub_video_fbblit_blend_RGB888_RGBA8888 (struct grub_video_fbblit_info *dst, *dstptr++ = dg; *dstptr++ = db; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -1081,12 +1124,17 @@ grub_video_fbblit_blend_index_RGBA8888 (struct grub_video_fbblit_info *dst, unsigned char dg; unsigned char db; unsigned char da; + grub_size_t srcrowskip; + grub_size_t dstrowskip; + + srcrowskip = src->mode_info->pitch - 4 * width; + dstrowskip = dst->mode_info->pitch - width; + + srcptr = grub_video_fb_get_video_ptr (src, offset_x, offset_y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { - srcptr = (grub_uint32_t *)grub_video_fb_get_video_ptr (src, offset_x, j + offset_y); - dstptr = (grub_uint8_t *)grub_video_fb_get_video_ptr (dst, x, y + j); - for (i = 0; i < width; i++) { color = *srcptr++; @@ -1120,6 +1168,8 @@ grub_video_fbblit_blend_index_RGBA8888 (struct grub_video_fbblit_info *dst, *dstptr++ = color & 0xFF; } + GRUB_VIDEO_FB_ADVANCE_POINTER (srcptr, srcrowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } @@ -1134,7 +1184,7 @@ grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, int i; int j; grub_uint8_t *srcptr; - grub_uint8_t *dstptr; + grub_uint32_t *dstptr; grub_uint8_t srcmask; unsigned int dstrowskip; unsigned int srcrowskipbyte, srcrowskipbit; @@ -1150,7 +1200,7 @@ grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -1181,23 +1231,22 @@ grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, } if (a == 255) - *(grub_uint32_t *) dstptr = color; + *dstptr = color; else if (a != 0) { grub_uint8_t s1 = (color >> 0) & 0xFF; grub_uint8_t s2 = (color >> 8) & 0xFF; grub_uint8_t s3 = (color >> 16) & 0xFF; - grub_uint8_t d1 = (*(grub_uint32_t *) dstptr >> 0) & 0xFF; - grub_uint8_t d2 = (*(grub_uint32_t *) dstptr >> 8) & 0xFF; - grub_uint8_t d3 = (*(grub_uint32_t *) dstptr >> 16) & 0xFF; + grub_uint8_t d1 = (*dstptr >> 0) & 0xFF; + grub_uint8_t d2 = (*dstptr >> 8) & 0xFF; + grub_uint8_t d3 = (*dstptr >> 16) & 0xFF; d1 = (d1 * (255 - a) + s1 * a) / 255; d2 = (d2 * (255 - a) + s2 * a) / 255; d3 = (d3 * (255 - a) + s3 * a) / 255; - *(grub_uint32_t *) dstptr = (a << 24) | (d3 << 16) | (d2 << 8) - | d1; + *dstptr = (a << 24) | (d3 << 16) | (d2 << 8) | d1; } srcmask >>= 1; @@ -1207,7 +1256,7 @@ grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, srcmask = 0x80; } - dstptr += 4; + dstptr++; } srcptr += srcrowskipbyte; @@ -1218,11 +1267,12 @@ grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, srcptr++; srcmask <<= 8 - srcrowskipbit; } - dstptr += dstrowskip; + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } /* Optimized blending blitter for 1-bit to XXX888. */ +#ifdef GRUB_HAVE_UNALIGNED_ACCESS void grub_video_fbblit_blend_XXX888_1bit (struct grub_video_fbblit_info *dst, struct grub_video_fbblit_info *src, @@ -1249,7 +1299,7 @@ grub_video_fbblit_blend_XXX888_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -1320,6 +1370,7 @@ grub_video_fbblit_blend_XXX888_1bit (struct grub_video_fbblit_info *dst, dstptr += dstrowskip; } } +#endif /* Optimized blending blitter for 1-bit to XXX888. */ void @@ -1332,7 +1383,7 @@ grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, int i; int j; grub_uint8_t *srcptr; - grub_uint8_t *dstptr; + grub_uint16_t *dstptr; grub_uint8_t srcmask; unsigned int dstrowskip; unsigned int srcrowskipbyte, srcrowskipbit; @@ -1348,7 +1399,7 @@ grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, bit_index = offset_y * src->mode_info->width + offset_x; srcptr = (grub_uint8_t *) src->data + (bit_index >> 3); srcmask = 1 << (~bit_index & 7); - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, src->mode_info->fg_green, @@ -1378,23 +1429,22 @@ grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, } if (a == 255) - *(grub_uint16_t *) dstptr = color; + *dstptr = color; else if (a != 0) { grub_uint8_t s1 = (color >> 0) & 0x1F; grub_uint8_t s2 = (color >> 5) & 0x3F; grub_uint8_t s3 = (color >> 11) & 0x1F; - grub_uint8_t d1 = (*(grub_uint16_t *) dstptr >> 0) & 0x1F; - grub_uint8_t d2 = (*(grub_uint16_t *) dstptr >> 5) & 0x3F; - grub_uint8_t d3 = (*(grub_uint16_t *) dstptr >> 11) & 0x1F; + grub_uint8_t d1 = (*dstptr >> 0) & 0x1F; + grub_uint8_t d2 = (*dstptr >> 5) & 0x3F; + grub_uint8_t d3 = (*dstptr >> 11) & 0x1F; d1 = (d1 * (255 - a) + s1 * a) / 255; d2 = (d2 * (255 - a) + s2 * a) / 255; d3 = (d3 * (255 - a) + s3 * a) / 255; - *(grub_uint16_t *) dstptr = (d1 & 0x1f) | ((d2 & 0x3f) << 5) - | ((d3 & 0x1f) << 11); + *dstptr = (d1 & 0x1f) | ((d2 & 0x3f) << 5) | ((d3 & 0x1f) << 11); } srcmask >>= 1; @@ -1404,7 +1454,7 @@ grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, srcmask = 0x80; } - dstptr += 2; + dstptr++; } srcptr += srcrowskipbyte; @@ -1415,6 +1465,6 @@ grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, srcptr++; srcmask <<= 8 - srcrowskipbit; } - dstptr += dstrowskip; + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, dstrowskip); } } diff --git a/grub-core/video/fb/fbfill.c b/grub-core/video/fb/fbfill.c index a4ca7c2a1..5f3e55fae 100644 --- a/grub-core/video/fb/fbfill.c +++ b/grub-core/video/fb/fbfill.c @@ -64,7 +64,7 @@ grub_video_fbfill_direct32 (struct grub_video_fbblit_info *dst, rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; /* Get the start address. */ - dstptr = (grub_uint32_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -72,7 +72,7 @@ grub_video_fbfill_direct32 (struct grub_video_fbblit_info *dst, *dstptr++ = color; /* Advance the dest pointer to the right location on the next line. */ - dstptr = (grub_uint32_t *) (((char *) dstptr) + rowskip); + GRUB_VIDEO_FB_ADVANCE_POINTER (dstptr, rowskip); } } @@ -96,7 +96,7 @@ grub_video_fbfill_direct24 (struct grub_video_fbblit_info *dst, rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; /* Get the start address. */ - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -131,7 +131,7 @@ grub_video_fbfill_direct16 (struct grub_video_fbblit_info *dst, rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; /* Get the start address. */ - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { @@ -164,7 +164,7 @@ grub_video_fbfill_direct8 (struct grub_video_fbblit_info *dst, rowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; /* Get the start address. */ - dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + dstptr = grub_video_fb_get_video_ptr (dst, x, y); for (j = 0; j < height; j++) { diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c index 511beaafc..c7fb08702 100644 --- a/grub-core/video/fb/fbutil.c +++ b/grub-core/video/fb/fbutil.c @@ -31,7 +31,7 @@ #include #include -grub_uint8_t * +void * grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source, unsigned int x, unsigned int y) { diff --git a/grub-core/video/fb/video_fb.c b/grub-core/video/fb/video_fb.c index 69626be5c..2d9d99482 100644 --- a/grub-core/video/fb/video_fb.c +++ b/grub-core/video/fb/video_fb.c @@ -24,6 +24,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static struct { @@ -619,6 +622,7 @@ common_blitter (struct grub_video_fbblit_info *target, offset_x, offset_y); return; } +#ifdef GRUB_HAVE_UNALIGNED_ACCESS else if (target->mode_info->bpp == 24) { grub_video_fbblit_replace_24bit_1bit (target, source, @@ -626,6 +630,7 @@ common_blitter (struct grub_video_fbblit_info *target, offset_x, offset_y); return; } +#endif else if (target->mode_info->bpp == 16) { grub_video_fbblit_replace_16bit_1bit (target, source, @@ -740,6 +745,7 @@ common_blitter (struct grub_video_fbblit_info *target, offset_x, offset_y); return; } +#ifdef GRUB_HAVE_UNALIGNED_ACCESS else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_888 || target->mode_info->blit_format @@ -750,6 +756,7 @@ common_blitter (struct grub_video_fbblit_info *target, offset_x, offset_y); return; } +#endif else if (target->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_BGR_565 || target->mode_info->blit_format @@ -1192,6 +1199,15 @@ grub_video_fb_create_render_target_from_pointer (struct grub_video_fbrender_targ struct grub_video_fbrender_target *target; unsigned y; +#ifndef GRUB_HAVE_UNALIGNED_ACCESS + if (!(mode_info->bytes_per_pixel & (mode_info->bytes_per_pixel - 1)) + && ((grub_addr_t) ptr & (mode_info->bytes_per_pixel - 1))) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unaligned pointer"); + if (!(mode_info->bytes_per_pixel & (mode_info->bytes_per_pixel - 1)) + && (mode_info->pitch & (mode_info->bytes_per_pixel - 1))) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unaligned pitch"); +#endif + /* Allocate memory for render target. */ target = grub_malloc (sizeof (struct grub_video_fbrender_target)); if (! target) @@ -1445,13 +1461,16 @@ grub_video_fb_setup (unsigned int mode_type, unsigned int mode_mask, GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED, 0)) { + /* It was much nicer with the cast directly at function call but + some older gcc versions don't accept it properly.*/ + void *tmp = (void *) page0_ptr; mode_info->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED | GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); err = grub_video_fb_doublebuf_blit_init (&framebuffer.front_target, &framebuffer.back_target, *mode_info, - (void *) page0_ptr); + tmp); if (!err) { @@ -1505,6 +1524,20 @@ grub_video_fb_get_info_and_fini (struct grub_video_mode_info *mode_info, { grub_memcpy (mode_info, &(framebuffer.front_target->mode_info), sizeof (*mode_info)); + + /* We are about to load a kernel. Switch back to page zero, since some + kernel drivers expect that. */ + if ((mode_info->mode_type & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + && framebuffer.set_page && framebuffer.displayed_page != 0) + { + /* Ensure both pages are exactly in sync. */ + grub_memcpy (framebuffer.back_target->data, + framebuffer.front_target->data, + framebuffer.back_target->mode_info.pitch + * framebuffer.back_target->mode_info.height); + grub_video_swap_buffers (); + } + *framebuf = framebuffer.front_target->data; grub_video_fb_fini (); diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index 2ddb4ca80..92dd7ec07 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -20,15 +20,17 @@ #include #include -#include -#include +#include #include #include #include #include #include #include -#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); static int vbe_detected = -1; @@ -273,6 +275,56 @@ grub_vbe_bios_get_pm_interface (grub_uint16_t *segment, grub_uint16_t *offset, return regs.eax & 0xffff; } +/* Call VESA BIOS 0x4f11 to get flat panel information, return status. */ +static grub_vbe_status_t +grub_vbe_bios_get_flat_panel_info (struct grub_vbe_flat_panel_info *flat_panel_info) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f11; + regs.ebx = 0x0001; + regs.es = (((grub_addr_t) flat_panel_info) & 0xffff0000) >> 4; + regs.edi = ((grub_addr_t) flat_panel_info) & 0xffff; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f15 to get DDC availability, return status. */ +static grub_vbe_status_t +grub_vbe_bios_get_ddc_capabilities (grub_uint8_t *level) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f15; + regs.ebx = 0x0000; + regs.ecx = 0x0000; + regs.es = 0x0000; + regs.edi = 0x0000; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + *level = regs.ebx & 0xff; + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f15 to read EDID information, return status. */ +static grub_vbe_status_t +grub_vbe_bios_read_edid (struct grub_video_edid_info *edid_info) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f15; + regs.ebx = 0x0001; + regs.ecx = 0x0000; + regs.edx = 0x0000; + regs.es = (((grub_addr_t) edid_info) & 0xffff0000) >> 4; + regs.edi = ((grub_addr_t) edid_info) & 0xffff; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + grub_err_t grub_vbe_probe (struct grub_vbe_info_block *info_block) @@ -327,6 +379,61 @@ grub_vbe_probe (struct grub_vbe_info_block *info_block) return GRUB_ERR_NONE; } +static grub_err_t +grub_video_vbe_get_edid (struct grub_video_edid_info *edid_info) +{ + struct grub_video_edid_info *edid_info_lowmem; + + /* Use low memory scratch area as temporary storage for VESA BIOS calls. */ + edid_info_lowmem = + (struct grub_video_edid_info *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_memset (edid_info_lowmem, 0, sizeof (*edid_info_lowmem)); + + if (grub_vbe_bios_read_edid (edid_info_lowmem) != GRUB_VBE_STATUS_OK) + return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available"); + + grub_memcpy (edid_info, edid_info_lowmem, sizeof (*edid_info)); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_vbe_get_preferred_mode (unsigned int *width, unsigned int *height) +{ + grub_vbe_status_t status; + grub_uint8_t ddc_level; + struct grub_video_edid_info edid_info; + struct grub_vbe_flat_panel_info *flat_panel_info; + + /* Use low memory scratch area as temporary storage for VESA BIOS calls. */ + flat_panel_info = (struct grub_vbe_flat_panel_info *) + (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + sizeof (struct grub_video_edid_info)); + grub_memset (flat_panel_info, 0, sizeof (*flat_panel_info)); + + if (controller_info.version >= 0x200 + && (grub_vbe_bios_get_ddc_capabilities (&ddc_level) & 0xff) + == GRUB_VBE_STATUS_OK) + { + if (grub_video_vbe_get_edid (&edid_info) == GRUB_ERR_NONE + && grub_video_edid_checksum (&edid_info) == GRUB_ERR_NONE + && grub_video_edid_preferred_mode (&edid_info, width, height) + == GRUB_ERR_NONE) + return GRUB_ERR_NONE; + + grub_errno = GRUB_ERR_NONE; + } + + status = grub_vbe_bios_get_flat_panel_info (flat_panel_info); + if (status == GRUB_VBE_STATUS_OK) + { + *width = flat_panel_info->horizontal_size; + *height = flat_panel_info->vertical_size; + return GRUB_ERR_NONE; + } + + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot get preferred mode"); +} + grub_err_t grub_vbe_set_video_mode (grub_uint32_t vbe_mode, struct grub_vbe_mode_info_block *vbe_mode_info) @@ -375,7 +482,7 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode, if (vbe_mode < 0x100) { /* If this is not a VESA mode, guess address. */ - framebuffer.ptr = (grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR; + framebuffer.ptr = (grub_uint8_t *) 0xa0000; } else { @@ -688,18 +795,36 @@ grub_video_vbe_iterate (int (*hook) (const struct grub_video_mode_info *info)) static grub_err_t grub_video_vbe_setup (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask) + grub_video_mode_type_t mode_type, + grub_video_mode_type_t mode_mask) { grub_uint16_t *p; struct grub_vbe_mode_info_block vbe_mode_info; struct grub_vbe_mode_info_block best_vbe_mode_info; grub_uint32_t best_vbe_mode = 0; int depth; + int preferred_mode = 0; /* Decode depth from mode_type. If it is zero, then autodetect. */ depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + if (width == 0 && height == 0) + { + grub_vbe_get_preferred_mode (&width, &height); + if (grub_errno == GRUB_ERR_NONE) + preferred_mode = 1; + else + { + /* Fall back to 640x480. This is conservative, but the largest + mode supported by the graphics card may not be safe for the + display device. */ + grub_errno = GRUB_ERR_NONE; + width = 640; + height = 480; + } + } + /* Walk thru mode list and try to find matching mode. */ for (p = vbe_mode_list; *p != 0xFFFF; p++) { @@ -742,10 +867,21 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, /* Unsupported bitdepth . */ continue; - if (((vbe_mode_info.x_resolution != width) - || (vbe_mode_info.y_resolution != height)) && width != 0 && height != 0) - /* Non matching resolution. */ - continue; + if (preferred_mode) + { + if (vbe_mode_info.x_resolution > width + || vbe_mode_info.y_resolution > height) + /* Resolution exceeds that of preferred mode. */ + continue; + } + else + { + if (((vbe_mode_info.x_resolution != width) + || (vbe_mode_info.y_resolution != height)) + && width != 0 && height != 0) + /* Non matching resolution. */ + continue; + } /* Check if user requested RGB or index color mode. */ if ((mode_mask & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0) @@ -858,15 +994,15 @@ grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info, static void grub_video_vbe_print_adapter_specific_info (void) { - grub_printf (" VBE info: version: %d.%d OEM software rev: %d.%d\n", - controller_info.version >> 8, - controller_info.version & 0xFF, - controller_info.oem_software_rev >> 8, - controller_info.oem_software_rev & 0xFF); - + grub_printf_ (N_(" VBE info: version: %d.%d OEM software rev: %d.%d\n"), + controller_info.version >> 8, + controller_info.version & 0xFF, + controller_info.oem_software_rev >> 8, + controller_info.oem_software_rev & 0xFF); + /* The total_memory field is in 64 KiB units. */ - grub_printf (" total memory: %d KiB\n", - (controller_info.total_memory << 16) / 1024); + grub_printf_ (N_(" total memory: %d KiB\n"), + (controller_info.total_memory << 16) / 1024); } static struct grub_video_adapter grub_video_vbe_adapter = @@ -899,6 +1035,7 @@ static struct grub_video_adapter grub_video_vbe_adapter = .set_active_render_target = grub_video_fb_set_active_render_target, .get_active_render_target = grub_video_fb_get_active_render_target, .iterate = grub_video_vbe_iterate, + .get_edid = grub_video_vbe_get_edid, .print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info, .next = 0 diff --git a/grub-core/video/i386/pc/vga.c b/grub-core/video/i386/pc/vga.c index 41b8d3eb1..08c9ca37d 100644 --- a/grub-core/video/i386/pc/vga.c +++ b/grub-core/video/i386/pc/vga.c @@ -18,8 +18,7 @@ #define grub_video_render_target grub_video_fbrender_target -#include -#include +#include #include #include #include @@ -30,9 +29,11 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define VGA_WIDTH 640 #define VGA_HEIGHT 350 -#define VGA_MEM ((grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR) +#define VGA_MEM ((grub_uint8_t *) 0xa0000) #define PAGE_OFFSET(x) ((x) * (VGA_WIDTH * VGA_HEIGHT / 8)) static unsigned char text_mode; @@ -116,7 +117,8 @@ grub_video_vga_init (void) static grub_err_t grub_video_vga_setup (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask) + grub_video_mode_type_t mode_type, + grub_video_mode_type_t mode_mask) { grub_err_t err; diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c index 501ba7c2f..913ea8376 100644 --- a/grub-core/video/ieee1275.c +++ b/grub-core/video/ieee1275.c @@ -27,6 +27,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Only 8-bit indexed color is supported for now. */ static unsigned old_width, old_height; diff --git a/grub-core/video/radeon_fuloong2e.c b/grub-core/video/radeon_fuloong2e.c new file mode 100644 index 000000000..3a65b6720 --- /dev/null +++ b/grub-core/video/radeon_fuloong2e.c @@ -0,0 +1,231 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009,2010,2011 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 grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRUB_RADEON_FULOONG2E_TOTAL_MEMORY_SPACE 1048576 + +static struct +{ + struct grub_video_mode_info mode_info; + struct grub_video_render_target *render_target; + + grub_uint8_t *ptr; + int mapped; + grub_uint32_t base; + grub_pci_device_t dev; +} framebuffer; + +static grub_err_t +grub_video_radeon_fuloong2e_video_init (void) +{ + /* Reset frame buffer. */ + grub_memset (&framebuffer, 0, sizeof(framebuffer)); + + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_radeon_fuloong2e_video_fini (void) +{ + if (framebuffer.mapped) + grub_pci_device_unmap_range (framebuffer.dev, framebuffer.ptr, + GRUB_RADEON_FULOONG2E_TOTAL_MEMORY_SPACE); + + return grub_video_fb_fini (); +} + +static grub_err_t +grub_video_radeon_fuloong2e_setup (unsigned int width, unsigned int height, + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) +{ + int depth; + grub_err_t err; + int found = 0; + +#ifndef TEST + auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))); + int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))) + { + grub_pci_address_t addr; + grub_uint32_t class; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + class = grub_pci_read (addr); + + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != 0x515a1002) + return 0; + + found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); + framebuffer.base = grub_pci_read (addr); + framebuffer.dev = dev; + + return 1; + } + + /* Decode depth from mode_type. If it is zero, then autodetect. */ + depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + + if ((width != 640 && width != 0) || (height != 480 && height != 0) + || (depth != 16 && depth != 0)) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Only 1024x600x16 is supported"); + + grub_pci_iterate (find_card); + if (!found) + return grub_error (GRUB_ERR_IO, "Couldn't find graphics card"); +#endif + /* Fill mode info details. */ + framebuffer.mode_info.width = 640; + framebuffer.mode_info.height = 480; + framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB; + framebuffer.mode_info.bpp = 16; + framebuffer.mode_info.bytes_per_pixel = 2; + framebuffer.mode_info.pitch = 640 * 2; + framebuffer.mode_info.number_of_colors = 256; + framebuffer.mode_info.red_mask_size = 5; + framebuffer.mode_info.red_field_pos = 11; + framebuffer.mode_info.green_mask_size = 6; + framebuffer.mode_info.green_field_pos = 5; + framebuffer.mode_info.blue_mask_size = 5; + framebuffer.mode_info.blue_field_pos = 0; + framebuffer.mode_info.reserved_mask_size = 0; + framebuffer.mode_info.reserved_field_pos = 0; +#ifndef TEST + framebuffer.mode_info.blit_format + = grub_video_get_blit_format (&framebuffer.mode_info); +#endif + + /* We can safely discard volatile attribute. */ +#ifndef TEST + framebuffer.ptr + = (void *) grub_pci_device_map_range (framebuffer.dev, + framebuffer.base, + GRUB_RADEON_FULOONG2E_TOTAL_MEMORY_SPACE); +#endif + framebuffer.mapped = 1; + + /* Prevent garbage from appearing on the screen. */ + grub_memset (framebuffer.ptr, 0x55, + framebuffer.mode_info.height * framebuffer.mode_info.pitch); + +#ifndef TEST + err = grub_video_fb_create_render_target_from_pointer (&framebuffer + .render_target, + &framebuffer.mode_info, + framebuffer.ptr); + + if (err) + return err; + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); + + if (err) + return err; + + /* Copy default palette to initialize emulated palette. */ + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); +#endif + return err; +} + +static grub_err_t +grub_video_radeon_fuloong2e_swap_buffers (void) +{ + /* TODO: Implement buffer swapping. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_radeon_fuloong2e_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + target = framebuffer.render_target; + + return grub_video_fb_set_active_render_target (target); +} + +static grub_err_t +grub_video_radeon_fuloong2e_get_info_and_fini (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + grub_video_fb_fini (); + + return GRUB_ERR_NONE; +} + +static struct grub_video_adapter grub_video_radeon_fuloong2e_adapter = + { + .name = "RADEON RV100 QZ (Fuloong2E) Video Driver", + .id = GRUB_VIDEO_DRIVER_RADEON_FULOONG2E, + + .prio = GRUB_VIDEO_ADAPTER_PRIO_NATIVE, + + .init = grub_video_radeon_fuloong2e_video_init, + .fini = grub_video_radeon_fuloong2e_video_fini, + .setup = grub_video_radeon_fuloong2e_setup, + .get_info = grub_video_fb_get_info, + .get_info_and_fini = grub_video_radeon_fuloong2e_get_info_and_fini, + .set_palette = grub_video_fb_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_radeon_fuloong2e_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_radeon_fuloong2e_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(video_radeon_fuloong2e) +{ + grub_video_register (&grub_video_radeon_fuloong2e_adapter); +} + +GRUB_MOD_FINI(video_radeon_fuloong2e) +{ + grub_video_unregister (&grub_video_radeon_fuloong2e_adapter); +} diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c index 9d88163bd..f2351dee9 100644 --- a/grub-core/video/readers/jpeg.c +++ b/grub-core/video/readers/jpeg.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Uncomment following define to enable JPEG debug. */ //#define JPEG_DEBUG @@ -37,6 +39,15 @@ #define JPEG_MARKER_DQT 0xdb #define JPEG_MARKER_SOF0 0xc0 #define JPEG_MARKER_SOS 0xda +#define JPEG_MARKER_DRI 0xdd +#define JPEG_MARKER_RST0 0xd0 +#define JPEG_MARKER_RST1 0xd1 +#define JPEG_MARKER_RST2 0xd2 +#define JPEG_MARKER_RST3 0xd3 +#define JPEG_MARKER_RST4 0xd4 +#define JPEG_MARKER_RST5 0xd5 +#define JPEG_MARKER_RST6 0xd6 +#define JPEG_MARKER_RST7 0xd7 #define SHIFT_BITS 8 #define CONST(x) ((int) ((x) * (1L << SHIFT_BITS) + 0.5)) @@ -64,6 +75,7 @@ struct grub_jpeg_data { grub_file_t file; struct grub_video_bitmap **bitmap; + grub_uint8_t *bitmap_ptr; int image_width; int image_height; @@ -80,6 +92,8 @@ struct grub_jpeg_data jpeg_data_unit_t cbdu; int vs, hs; + int dri; + int r1; int dc_value[3]; @@ -313,6 +327,18 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) return grub_errno; } +static grub_err_t +grub_jpeg_decode_dri (struct grub_jpeg_data *data) +{ + if (grub_jpeg_get_word (data) != 4) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: DRI marker length must be 4"); + + data->dri = grub_jpeg_get_word (data); + + return grub_errno; +} + static void grub_jpeg_idct_transform (jpeg_data_unit_t du) { @@ -524,8 +550,7 @@ grub_jpeg_ycrcb_to_rgb (int yy, int cr, int cb, grub_uint8_t * rgb) static grub_err_t grub_jpeg_decode_sos (struct grub_jpeg_data *data) { - int i, cc, r1, c1, nr1, nc1, vb, hb; - grub_uint8_t *ptr1; + int i, cc; grub_uint32_t data_offset; data_offset = data->file->offset; @@ -561,17 +586,25 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) GRUB_VIDEO_BLIT_FORMAT_RGB_888)) return grub_errno; - data->bit_mask = 0x0; + data->bitmap_ptr = (*data->bitmap)->data; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_jpeg_decode_data (struct grub_jpeg_data *data) +{ + int c1, vb, hb, nr1, nc1; + int rst = data->dri; vb = data->vs * 8; hb = data->hs * 8; nr1 = (data->image_height + vb - 1) / vb; nc1 = (data->image_width + hb - 1) / hb; - ptr1 = (*data->bitmap)->data; - for (r1 = 0; r1 < nr1; - r1++, ptr1 += (vb * data->image_width - hb * nc1) * 3) - for (c1 = 0; c1 < nc1; c1++, ptr1 += hb * 3) + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); + c1++, rst--, data->bitmap_ptr += hb * 3) { int r2, c2, nr2, nc2; grub_uint8_t *ptr2; @@ -586,10 +619,10 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) if (grub_errno) return grub_errno; - nr2 = (r1 == nr1 - 1) ? (data->image_height - r1 * vb) : vb; + nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; - ptr2 = ptr1; + ptr2 = data->bitmap_ptr; for (r2 = 0; r2 < nr2; r2++, ptr2 += (data->image_width - nc2) * 3) for (c2 = 0; c2 < nc2; c2++, ptr2 += 3) { @@ -598,8 +631,7 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) i0 = (r2 / data->vs) * 8 + (c2 / data->hs); cr = data->crdu[i0]; cb = data->cbdu[i0]; - yy = - data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; + yy = data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; grub_jpeg_ycrcb_to_rgb (yy, cr, cb, ptr2); } @@ -608,6 +640,16 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) return grub_errno; } +static void +grub_jpeg_reset (struct grub_jpeg_data *data) +{ + data->bit_mask = 0x0; + + data->dc_value[0] = 0; + data->dc_value[1] = 0; + data->dc_value[2] = 0; +} + static grub_uint8_t grub_jpeg_get_marker (struct grub_jpeg_data *data) { @@ -653,8 +695,22 @@ grub_jpeg_decode_jpeg (struct grub_jpeg_data *data) case JPEG_MARKER_SOF0: /* Start Of Frame 0. */ grub_jpeg_decode_sof (data); break; + case JPEG_MARKER_DRI: /* Define Restart Interval. */ + grub_jpeg_decode_dri (data); + break; case JPEG_MARKER_SOS: /* Start Of Scan. */ - grub_jpeg_decode_sos (data); + if (grub_jpeg_decode_sos (data)) + break; + case JPEG_MARKER_RST0: /* Restart. */ + case JPEG_MARKER_RST1: + case JPEG_MARKER_RST2: + case JPEG_MARKER_RST3: + case JPEG_MARKER_RST4: + case JPEG_MARKER_RST5: + case JPEG_MARKER_RST6: + case JPEG_MARKER_RST7: + grub_jpeg_decode_data (data); + grub_jpeg_reset (data); break; case JPEG_MARKER_EOI: /* End Of Image. */ return grub_errno; @@ -694,8 +750,7 @@ grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, grub_jpeg_decode_jpeg (data); for (i = 0; i < 4; i++) - if (data->huff_value[i]) - grub_free (data->huff_value[i]); + grub_free (data->huff_value[i]); grub_free (data); } diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c index 2cec49e2f..ae9879b16 100644 --- a/grub-core/video/readers/png.c +++ b/grub-core/video/readers/png.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Uncomment following define to enable PNG debug. */ //#define PNG_DEBUG @@ -623,8 +625,7 @@ grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n) } } - if (blank_line) - grub_free (blank_line); + grub_free (blank_line); data->cur_column = 0; data->first_line = 0; diff --git a/grub-core/video/readers/tga.c b/grub-core/video/readers/tga.c index 6c9e9d691..84be68a0a 100644 --- a/grub-core/video/readers/tga.c +++ b/grub-core/video/readers/tga.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* Uncomment following define to enable TGA debug. */ //#define TGA_DEBUG diff --git a/grub-core/video/sis315_init.c b/grub-core/video/sis315_init.c new file mode 100644 index 000000000..ae5c1419c --- /dev/null +++ b/grub-core/video/sis315_init.c @@ -0,0 +1,158 @@ +static const struct { grub_uint8_t reg; grub_uint8_t val; } sr_dump [] = +{ + { 0x28, 0x81 }, + { 0x2a, 0x00 }, + { 0x29, 0xe1 }, + { 0x2b, 0x81 }, + { 0x2d, 0x00 }, + { 0x2c, 0xe1 }, + { 0x2e, 0x81 }, + { 0x30, 0x00 }, + { 0x2f, 0xe1 }, + { 0x28, 0x01 }, + { 0x29, 0x22 }, + { 0x28, 0x3b }, + { 0x29, 0x22 }, + { 0x2a, 0x01 }, + { 0x2e, 0x01 }, + { 0x2f, 0x22 }, + { 0x2e, 0x3b }, + { 0x2f, 0x22 }, + { 0x30, 0x01 }, + { 0x15, 0x00 }, + { 0x1b, 0x30 }, + + { 0x16, 0x0f }, + { 0x16, 0x8f }, + { 0x17, 0xba }, + { 0x16, 0x0f }, + { 0x16, 0x8f }, + { 0x1f, 0x00 }, + { 0x20, 0x20 }, + { 0x23, 0xf6 }, + { 0x24, 0x0d }, + { 0x25, 0x33 }, + { 0x21, 0x84 }, + { 0x22, 0x00 }, + { 0x27, 0x1f }, + { 0x31, 0x00 }, + { 0x33, 0x00 }, + { 0x32, 0x11 }, + + { 0x25, 0x33 }, + + { 0x05, 0x86 }, + { 0x01, 0x20 }, + { 0x32, 0x11 }, + { 0x1e, 0x00 }, + { 0x1d, 0x00 }, + { 0x00, 0x03 }, + { 0x01, 0x21 }, + { 0x02, 0x0f }, + { 0x03, 0x00 }, + { 0x04, 0x0e }, + + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x0c, 0x00 }, + { 0x0d, 0x00 }, + { 0x0e, 0x00 }, + { 0x37, 0x00 }, + + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x0c, 0x05 }, + { 0x0e, 0x00 }, + + { 0x0e, 0x00 }, + + { 0x10, 0x0b }, + { 0x31, 0x00 }, + { 0x2b, 0x01 }, + { 0x2c, 0xe1 }, + { 0x2b, 0x1b }, + { 0x2c, 0xe1 }, + { 0x2d, 0x01 }, + { 0x3d, 0x00 }, + { 0x08, 0x84 }, + { 0x09, 0x00 }, + { 0x3d, 0x01 }, + { 0x1f, 0x00 }, + { 0x06, 0x02 }, + + { 0x0f, 0x00 }, + { 0x17, 0xba }, + { 0x21, 0xa4 }, + { 0x32, 0x11 }, + { 0x07, 0x18 }, + + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + + { 0x01, 0x01 }, + { 0x21, 0x84 }, + { 0x01, 0x21 }, + { 0x16, 0x8f }, + { 0x18, 0xa9 }, + { 0x19, 0xa0 }, + { 0x1b, 0x30 }, + { 0x17, 0xb8 }, + { 0x19, 0xa3 }, + { 0x13, 0x00 }, + { 0x14, 0x00 }, + { 0x14, 0x02 }, + { 0x15, 0x00 }, + { 0x16, 0x0f }, + { 0x16, 0x8f }, + { 0x1d, 0x00 }, + { 0x14, 0x00 }, + { 0x14, 0x01 }, + { 0x15, 0x00 }, + { 0x16, 0x0f }, + { 0x16, 0x8f }, + { 0x1d, 0x00 }, + { 0x14, 0x01 }, + { 0x14, 0x01 }, + { 0x15, 0x10 }, + { 0x13, 0x35 }, + { 0x14, 0x51 }, + { 0x16, 0x0f }, + { 0x16, 0x8f }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x11 }, + { 0x1d, 0x11 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x1d, 0x00 }, + { 0x17, 0xba }, + { 0x19, 0xa0 }, + { 0x19, 0xa0 }, + { 0x01, 0x01 }, + { 0x16, 0x0f }, + { 0x18, 0xa9 }, + { 0x19, 0xa0 }, + { 0x1b, 0x30 }, + { 0x21, 0xa4 }, + { 0x05, 0x86 }, +}; + +static const grub_uint8_t gr[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/grub-core/video/sis315pro.c b/grub-core/video/sis315pro.c new file mode 100644 index 000000000..22064c91e --- /dev/null +++ b/grub-core/video/sis315pro.c @@ -0,0 +1,448 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#define grub_video_render_target grub_video_fbrender_target + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRUB_SIS315PRO_PCIID 0x03251039 +#define GRUB_SIS315PRO_TOTAL_MEMORY_SPACE 0x800000 +#define GRUB_SIS315PRO_MMIO_SPACE 0x1000 + +static struct +{ + struct grub_video_mode_info mode_info; + struct grub_video_render_target *render_target; + + grub_uint8_t *ptr; + int mapped; + grub_uint32_t base; + grub_uint32_t mmiobase; + volatile grub_uint32_t *mmioptr; + grub_pci_device_t dev; + grub_port_t io; +} framebuffer; + +static grub_uint8_t +read_sis_cmd (grub_uint8_t addr) +{ + grub_outb (addr, framebuffer.io + 0x44); + return grub_inb (framebuffer.io + 0x45); +} + +static void +write_sis_cmd (grub_uint8_t val, grub_uint8_t addr) +{ + grub_outb (addr, framebuffer.io + 0x44); + grub_outb (val, framebuffer.io + 0x45); +} + +#ifndef TEST +static grub_err_t +grub_video_sis315pro_video_init (void) +{ + /* Reset frame buffer. */ + grub_memset (&framebuffer, 0, sizeof(framebuffer)); + + return grub_video_fb_init (); +} + +static grub_err_t +grub_video_sis315pro_video_fini (void) +{ + if (framebuffer.mapped) + grub_pci_device_unmap_range (framebuffer.dev, framebuffer.ptr, + GRUB_SIS315PRO_TOTAL_MEMORY_SPACE); + + return grub_video_fb_fini (); +} +#endif + +#include "sis315_init.c" + +static grub_err_t +grub_video_sis315pro_setup (unsigned int width, unsigned int height, + unsigned int mode_type, + unsigned int mode_mask __attribute__ ((unused))) +{ + int depth; + grub_err_t err; + int found = 0; + unsigned i; + +#ifndef TEST + auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))); + int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))) + { + grub_pci_address_t addr; + grub_uint32_t class; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + class = grub_pci_read (addr); + + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != GRUB_SIS315PRO_PCIID) + return 0; + + found = 1; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); + framebuffer.base = grub_pci_read (addr) & GRUB_PCI_ADDR_MEM_MASK; + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1); + framebuffer.mmiobase = grub_pci_read (addr) & GRUB_PCI_ADDR_MEM_MASK; + addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG2); + framebuffer.io = (grub_pci_read (addr) & GRUB_PCI_ADDR_IO_MASK) + + GRUB_MACHINE_PCI_IO_BASE; + framebuffer.dev = dev; + + return 1; + } + + /* Decode depth from mode_type. If it is zero, then autodetect. */ + depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS; + + if ((width != 640 && width != 0) || (height != 480 && height != 0) + || (depth != 8 && depth != 0)) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Only 640x400x8 is supported"); + + grub_pci_iterate (find_card); + if (!found) + return grub_error (GRUB_ERR_IO, "Couldn't find graphics card"); +#endif + /* Fill mode info details. */ + framebuffer.mode_info.width = 640; + framebuffer.mode_info.height = 480; + framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + framebuffer.mode_info.bpp = 8; + framebuffer.mode_info.bytes_per_pixel = 1; + framebuffer.mode_info.pitch = 640 * 1; + framebuffer.mode_info.number_of_colors = 256; + framebuffer.mode_info.red_mask_size = 0; + framebuffer.mode_info.red_field_pos = 0; + framebuffer.mode_info.green_mask_size = 0; + framebuffer.mode_info.green_field_pos = 0; + framebuffer.mode_info.blue_mask_size = 0; + framebuffer.mode_info.blue_field_pos = 0; + framebuffer.mode_info.reserved_mask_size = 0; + framebuffer.mode_info.reserved_field_pos = 0; +#ifndef TEST + framebuffer.mode_info.blit_format + = grub_video_get_blit_format (&framebuffer.mode_info); +#endif + +#ifndef TEST + if (found && (framebuffer.base == 0 || framebuffer.mmiobase == 0)) + { + grub_pci_address_t addr; + /* FIXME: choose address dynamically if needed. */ + framebuffer.base = 0x40000000; + framebuffer.mmiobase = 0x04000000; + framebuffer.io = 0xb300; + + addr = grub_pci_make_address (framebuffer.dev, GRUB_PCI_REG_ADDRESS_REG0); + grub_pci_write (addr, framebuffer.base | GRUB_PCI_ADDR_MEM_PREFETCH); + + addr = grub_pci_make_address (framebuffer.dev, GRUB_PCI_REG_ADDRESS_REG1); + grub_pci_write (addr, framebuffer.mmiobase); + + addr = grub_pci_make_address (framebuffer.dev, GRUB_PCI_REG_ADDRESS_REG2); + grub_pci_write (addr, framebuffer.io | GRUB_PCI_ADDR_SPACE_IO); + + /* Set latency. */ + addr = grub_pci_make_address (framebuffer.dev, GRUB_PCI_REG_CACHELINE); + grub_pci_write (addr, 0x80004700); + + /* Enable address spaces. */ + addr = grub_pci_make_address (framebuffer.dev, GRUB_PCI_REG_COMMAND); + grub_pci_write (addr, 0x7); + + addr = grub_pci_make_address (framebuffer.dev, 0x30); + grub_pci_write (addr, 0x04060001); + + framebuffer.io += GRUB_MACHINE_PCI_IO_BASE; + } +#endif + + + /* We can safely discard volatile attribute. */ +#ifndef TEST + framebuffer.ptr + = (void *) grub_pci_device_map_range (framebuffer.dev, + framebuffer.base, + GRUB_SIS315PRO_TOTAL_MEMORY_SPACE); + framebuffer.mmioptr = grub_pci_device_map_range (framebuffer.dev, + framebuffer.mmiobase, + GRUB_SIS315PRO_MMIO_SPACE); +#endif + framebuffer.mapped = 1; + +#ifndef TEST + /* Prevent garbage from appearing on the screen. */ + grub_memset (framebuffer.ptr, 0, + framebuffer.mode_info.height * framebuffer.mode_info.pitch); +#endif + + grub_outb (GRUB_VGA_IO_MISC_NEGATIVE_VERT_POLARITY + | GRUB_VGA_IO_MISC_NEGATIVE_HORIZ_POLARITY + | GRUB_VGA_IO_MISC_UPPER_64K + | GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 + | GRUB_VGA_IO_MISC_28MHZ + | GRUB_VGA_IO_MISC_ENABLE_VRAM_ACCESS + | GRUB_VGA_IO_MISC_COLOR, + GRUB_VGA_IO_MISC_WRITE + GRUB_MACHINE_PCI_IO_BASE); + + grub_vga_sr_write (0x86, 5); + for (i = 6; i <= 0x27; i++) + grub_vga_sr_write (0, i); + + for (i = 0x31; i <= 0x3d; i++) + grub_vga_sr_write (0, i); + + for (i = 0; i < ARRAY_SIZE (sr_dump); i++) + grub_vga_sr_write (sr_dump[i].val, sr_dump[i].reg); + + for (i = 0x30; i < 0x40; i++) + grub_vga_cr_write (0, i); + + grub_vga_cr_write (0x77, 0x40); + grub_vga_cr_write (0x77, 0x41); + grub_vga_cr_write (0x00, 0x42); + grub_vga_cr_write (0x5b, 0x43); + grub_vga_cr_write (0x00, 0x44); + grub_vga_cr_write (0x23, 0x48); + grub_vga_cr_write (0xaa, 0x49); + grub_vga_cr_write (0x02, 0x37); + grub_vga_cr_write (0x20, 0x5b); + grub_vga_cr_write (0x00, 0x83); + grub_vga_cr_write (0x80, 0x63); + + grub_vga_cr_write (0x0c, GRUB_VGA_CR_VSYNC_END); + grub_vga_cr_write (0x5f, GRUB_VGA_CR_HTOTAL); + grub_vga_cr_write (0x4f, GRUB_VGA_CR_HORIZ_END); + grub_vga_cr_write (0x50, GRUB_VGA_CR_HBLANK_START); + grub_vga_cr_write (0x82, GRUB_VGA_CR_HBLANK_END); + grub_vga_cr_write (0x54, GRUB_VGA_CR_HORIZ_SYNC_PULSE_START); + grub_vga_cr_write (0x80, GRUB_VGA_CR_HORIZ_SYNC_PULSE_END); + grub_vga_cr_write (0x0b, GRUB_VGA_CR_VERT_TOTAL); + grub_vga_cr_write (0x3e, GRUB_VGA_CR_OVERFLOW); + grub_vga_cr_write (0x00, GRUB_VGA_CR_BYTE_PANNING); + grub_vga_cr_write (0x40, GRUB_VGA_CR_CELL_HEIGHT); + grub_vga_cr_write (0x00, GRUB_VGA_CR_CURSOR_START); + grub_vga_cr_write (0x00, GRUB_VGA_CR_CURSOR_END); + grub_vga_cr_write (0x00, GRUB_VGA_CR_START_ADDR_HIGH_REGISTER); + grub_vga_cr_write (0x00, GRUB_VGA_CR_START_ADDR_LOW_REGISTER); + grub_vga_cr_write (0x00, GRUB_VGA_CR_CURSOR_ADDR_HIGH); + grub_vga_cr_write (0x00, GRUB_VGA_CR_CURSOR_ADDR_LOW); + grub_vga_cr_write (0xea, GRUB_VGA_CR_VSYNC_START); + grub_vga_cr_write (0x8c, GRUB_VGA_CR_VSYNC_END); + grub_vga_cr_write (0xdf, GRUB_VGA_CR_VDISPLAY_END); + grub_vga_cr_write (0x28, GRUB_VGA_CR_PITCH); + grub_vga_cr_write (0x40, GRUB_VGA_CR_UNDERLINE_LOCATION); + grub_vga_cr_write (0xe7, GRUB_VGA_CR_VERTICAL_BLANK_START); + grub_vga_cr_write (0x04, GRUB_VGA_CR_VERTICAL_BLANK_END); + grub_vga_cr_write (0xa3, GRUB_VGA_CR_MODE); + grub_vga_cr_write (0xff, GRUB_VGA_CR_LINE_COMPARE); + + grub_vga_cr_write (0x0c, GRUB_VGA_CR_VSYNC_END); + grub_vga_cr_write (0x5f, GRUB_VGA_CR_HTOTAL); + grub_vga_cr_write (0x4f, GRUB_VGA_CR_HORIZ_END); + grub_vga_cr_write (0x50, GRUB_VGA_CR_HBLANK_START); + grub_vga_cr_write (0x82, GRUB_VGA_CR_HBLANK_END); + grub_vga_cr_write (0x55, GRUB_VGA_CR_HORIZ_SYNC_PULSE_START); + grub_vga_cr_write (0x81, GRUB_VGA_CR_HORIZ_SYNC_PULSE_END); + grub_vga_cr_write (0x0b, GRUB_VGA_CR_VERT_TOTAL); + grub_vga_cr_write (0x3e, GRUB_VGA_CR_OVERFLOW); + grub_vga_cr_write (0xe9, GRUB_VGA_CR_VSYNC_START); + grub_vga_cr_write (0x8b, GRUB_VGA_CR_VSYNC_END); + grub_vga_cr_write (0xdf, GRUB_VGA_CR_VDISPLAY_END); + grub_vga_cr_write (0xe7, GRUB_VGA_CR_VERTICAL_BLANK_START); + grub_vga_cr_write (0x04, GRUB_VGA_CR_VERTICAL_BLANK_END); + grub_vga_cr_write (0x40, GRUB_VGA_CR_CELL_HEIGHT); + grub_vga_cr_write (0x50, GRUB_VGA_CR_PITCH); + + grub_vga_cr_write (0x00, 0x19); + grub_vga_cr_write (0x00, 0x1a); + grub_vga_cr_write (0x6c, 0x52); + grub_vga_cr_write (0x2e, 0x34); + grub_vga_cr_write (0x00, 0x31); + + + grub_vga_cr_write (0, GRUB_VGA_CR_START_ADDR_HIGH_REGISTER); + grub_vga_cr_write (0, GRUB_VGA_CR_START_ADDR_LOW_REGISTER); + + for (i = 0; i < 16; i++) + grub_vga_write_arx (i, i); + grub_vga_write_arx (1, GRUB_VGA_ARX_MODE); + grub_vga_write_arx (0, GRUB_VGA_ARX_OVERSCAN); + grub_vga_write_arx (0, GRUB_VGA_ARX_COLOR_PLANE_ENABLE); + grub_vga_write_arx (0, GRUB_VGA_ARX_HORIZONTAL_PANNING); + grub_vga_write_arx (0, GRUB_VGA_ARX_COLOR_SELECT); + + grub_outb (0xff, GRUB_VGA_IO_PIXEL_MASK + GRUB_MACHINE_PCI_IO_BASE); + + for (i = 0; i < ARRAY_SIZE (gr); i++) + grub_vga_gr_write (gr[i], i); + + for (i = 0; i < GRUB_VIDEO_FBSTD_NUMCOLORS; i++) + grub_vga_palette_write (i, grub_video_fbstd_colors[i].r, + grub_video_fbstd_colors[i].g, + grub_video_fbstd_colors[i].b); + +#if 1 + { + if (read_sis_cmd (0x5) != 0xa1) + write_sis_cmd (0x86, 0x5); + + write_sis_cmd (read_sis_cmd (0x20) | 0xa1, 0x20); + write_sis_cmd (read_sis_cmd (0x1e) | 0xda, 0x1e); + +#define IND_SIS_CMDQUEUE_SET 0x26 +#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 + +#define COMMAND_QUEUE_THRESHOLD 0x1F +#define SIS_CMD_QUEUE_RESET 0x01 + +#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315/330/340 series SR26 */ +#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 +#define SIS_MMIO_CMD_ENABLE 0x20 +#define SIS_CMD_QUEUE_SIZE_512k 0x00 +#define SIS_CMD_QUEUE_SIZE_1M 0x04 +#define SIS_CMD_QUEUE_SIZE_2M 0x08 +#define SIS_CMD_QUEUE_SIZE_4M 0x0C +#define SIS_CMD_QUEUE_RESET 0x01 +#define SIS_CMD_AUTO_CORR 0x02 + + + write_sis_cmd (COMMAND_QUEUE_THRESHOLD, IND_SIS_CMDQUEUE_THRESHOLD); + write_sis_cmd (SIS_CMD_QUEUE_RESET, IND_SIS_CMDQUEUE_SET); + framebuffer.mmioptr[0x85C4 / 4] = framebuffer.mmioptr[0x85C8 / 4]; + write_sis_cmd (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR, IND_SIS_CMDQUEUE_SET); + framebuffer.mmioptr[0x85C0 / 4] = (0x1000000 - (512 * 1024)); + } +#endif + +#ifndef TEST + err = grub_video_fb_create_render_target_from_pointer (&framebuffer + .render_target, + &framebuffer.mode_info, + framebuffer.ptr); + + if (err) + return err; + + err = grub_video_fb_set_active_render_target (framebuffer.render_target); + + if (err) + return err; + + /* Copy default palette to initialize emulated palette. */ + err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); +#endif + return err; +} + +#ifndef TEST + +static grub_err_t +grub_video_sis315pro_swap_buffers (void) +{ + /* TODO: Implement buffer swapping. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_video_sis315pro_set_active_render_target (struct grub_video_render_target *target) +{ + if (target == GRUB_VIDEO_RENDER_TARGET_DISPLAY) + target = framebuffer.render_target; + + return grub_video_fb_set_active_render_target (target); +} + +static grub_err_t +grub_video_sis315pro_get_info_and_fini (struct grub_video_mode_info *mode_info, + void **framebuf) +{ + grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info)); + *framebuf = (char *) framebuffer.ptr; + + grub_video_fb_fini (); + + return GRUB_ERR_NONE; +} + +static struct grub_video_adapter grub_video_sis315pro_adapter = + { + .name = "SIS315PRO Video Driver", + .id = GRUB_VIDEO_DRIVER_SIS315PRO, + + .prio = GRUB_VIDEO_ADAPTER_PRIO_NATIVE, + + .init = grub_video_sis315pro_video_init, + .fini = grub_video_sis315pro_video_fini, + .setup = grub_video_sis315pro_setup, + .get_info = grub_video_fb_get_info, + .get_info_and_fini = grub_video_sis315pro_get_info_and_fini, + .set_palette = grub_video_fb_set_palette, + .get_palette = grub_video_fb_get_palette, + .set_viewport = grub_video_fb_set_viewport, + .get_viewport = grub_video_fb_get_viewport, + .map_color = grub_video_fb_map_color, + .map_rgb = grub_video_fb_map_rgb, + .map_rgba = grub_video_fb_map_rgba, + .unmap_color = grub_video_fb_unmap_color, + .fill_rect = grub_video_fb_fill_rect, + .blit_bitmap = grub_video_fb_blit_bitmap, + .blit_render_target = grub_video_fb_blit_render_target, + .scroll = grub_video_fb_scroll, + .swap_buffers = grub_video_sis315pro_swap_buffers, + .create_render_target = grub_video_fb_create_render_target, + .delete_render_target = grub_video_fb_delete_render_target, + .set_active_render_target = grub_video_sis315pro_set_active_render_target, + .get_active_render_target = grub_video_fb_get_active_render_target, + + .next = 0 + }; + +GRUB_MOD_INIT(video_sis315pro) +{ + grub_video_register (&grub_video_sis315pro_adapter); +} + +GRUB_MOD_FINI(video_sis315pro) +{ + grub_video_unregister (&grub_video_sis315pro_adapter); +} +#else +int +main () +{ + grub_video_sis315pro_setup (640, 400, 0, 0); +} +#endif diff --git a/grub-core/video/video.c b/grub-core/video/video.c index 7a1a446e4..ad87a69ff 100644 --- a/grub-core/video/video.c +++ b/grub-core/video/video.c @@ -22,6 +22,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + /* The list of video adapters registered to system. */ grub_video_adapter_t grub_video_adapter_list = NULL; @@ -374,6 +376,50 @@ grub_video_get_active_render_target (struct grub_video_render_target **target) return grub_video_adapter_active->get_active_render_target (target); } +grub_err_t +grub_video_edid_checksum (struct grub_video_edid_info *edid_info) +{ + const char *edid_bytes = (const char *) edid_info; + int i; + char checksum = 0; + + /* Check EDID checksum. */ + for (i = 0; i < 128; ++i) + checksum += edid_bytes[i]; + + if (checksum != 0) + return grub_error (GRUB_ERR_BAD_DEVICE, + "invalid EDID checksum %d", checksum); + + grub_errno = GRUB_ERR_NONE; + return grub_errno; +} + +grub_err_t +grub_video_edid_preferred_mode (struct grub_video_edid_info *edid_info, + unsigned int *width, unsigned int *height) +{ + /* Bit 1 in the Feature Support field indicates that the first + Detailed Timing Description is the preferred timing mode. */ + if (edid_info->version == 1 /* we don't understand later versions */ + && (edid_info->feature_support + & GRUB_VIDEO_EDID_FEATURE_PREFERRED_TIMING_MODE) + && edid_info->detailed_timings[0].pixel_clock) + { + *width = edid_info->detailed_timings[0].horizontal_active_lo + | (((unsigned int) + (edid_info->detailed_timings[0].horizontal_hi & 0xf0)) + << 4); + *height = edid_info->detailed_timings[0].vertical_active_lo + | (((unsigned int) + (edid_info->detailed_timings[0].vertical_hi & 0xf0)) + << 4); + return GRUB_ERR_NONE; + } + + return grub_error (GRUB_ERR_BAD_DEVICE, "no preferred mode available"); +} + /* Parse x[x]*/ static grub_err_t parse_modespec (const char *current_mode, int *width, int *height, int *depth) diff --git a/include/grub/acpi.h b/include/grub/acpi.h index aebc8dd4f..c843a0621 100644 --- a/include/grub/acpi.h +++ b/include/grub/acpi.h @@ -19,8 +19,10 @@ #ifndef GRUB_ACPI_HEADER #define GRUB_ACPI_HEADER 1 +#ifndef GRUB_DSDT_TEST #include #include +#endif struct grub_acpi_rsdp_v10 { @@ -139,6 +141,7 @@ enum GRUB_ACPI_MADT_ENTRY_SAPIC_FLAGS_ENABLED = 1 }; +#ifndef GRUB_DSDT_TEST struct grub_acpi_rsdp_v10 *grub_acpi_get_rsdpv1 (void); struct grub_acpi_rsdp_v20 *grub_acpi_get_rsdpv2 (void); struct grub_acpi_rsdp_v10 *grub_machine_acpi_get_rsdpv1 (void); @@ -148,6 +151,7 @@ grub_uint8_t grub_byte_checksum (void *base, grub_size_t size); grub_err_t grub_acpi_create_ebda (void); void grub_acpi_halt (void); +#endif #define GRUB_ACPI_SLP_EN (1 << 13) #define GRUB_ACPI_SLP_TYP_OFFSET 10 @@ -165,7 +169,8 @@ enum { GRUB_ACPI_EXTOPCODE_MUTEX = 0x01, GRUB_ACPI_EXTOPCODE_OPERATION_REGION = 0x80, - GRUB_ACPI_EXTOPCODE_FIELD_OP = 0x81 + GRUB_ACPI_EXTOPCODE_FIELD_OP = 0x81, + GRUB_ACPI_EXTOPCODE_INDEX_FIELD_OP = 0x86, }; #endif /* ! GRUB_ACPI_HEADER */ diff --git a/include/grub/arc/arc.h b/include/grub/arc/arc.h new file mode 100644 index 000000000..a825a9877 --- /dev/null +++ b/include/grub/arc/arc.h @@ -0,0 +1,266 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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_ARC_HEADER +#define GRUB_ARC_HEADER 1 + +#include +#include + +typedef unsigned grub_arc_enum_t; +typedef grub_uint64_t grub_arc_ularge_t; +typedef unsigned long grub_arc_ulong_t; +typedef long grub_arc_long_t; +typedef unsigned short grub_arc_ushort_t; +typedef unsigned char grub_arc_uchar_t; + +typedef grub_arc_long_t grub_arc_err_t; +typedef grub_arc_ulong_t grub_arc_fileno_t; + +struct grub_arc_memory_descriptor +{ + grub_arc_enum_t type; + grub_arc_ulong_t start_page; + grub_arc_ulong_t num_pages; +}; + +enum grub_arc_memory_type + { + GRUB_ARC_MEMORY_EXCEPTION_BLOCK, + GRUB_ARC_MEMORY_SYSTEM_PARAMETER_BLOCK, +#ifdef GRUB_CPU_WORDS_BIGENDIAN + GRUB_ARC_MEMORY_FREE_CONTIGUOUS, +#endif + GRUB_ARC_MEMORY_FREE, + GRUB_ARC_MEMORY_BADRAM, + GRUB_ARC_MEMORY_LOADED, GRUB_ARC_MEMORY_FW_TEMPORARY, + GRUB_ARC_MEMORY_FW_PERMANENT, +#ifndef GRUB_CPU_WORDS_BIGENDIAN + GRUB_ARC_MEMORY_FREE_CONTIGUOUS, +#endif + } grub_arc_memory_type_t; + +struct grub_arc_timeinfo +{ + grub_arc_ushort_t y; + grub_arc_ushort_t m; + grub_arc_ushort_t d; + grub_arc_ushort_t h; + grub_arc_ushort_t min; + grub_arc_ushort_t s; + grub_arc_ushort_t ms; +}; + +struct grub_arc_display_status +{ + grub_arc_ushort_t x; + grub_arc_ushort_t y; + grub_arc_ushort_t w; + grub_arc_ushort_t h; + grub_arc_uchar_t fgcolor; + grub_arc_uchar_t bgcolor; + grub_arc_uchar_t high_intensity; + grub_arc_uchar_t underscored; + grub_arc_uchar_t reverse_video; +}; + +struct grub_arc_component +{ + grub_arc_enum_t class; + grub_arc_enum_t type; + grub_arc_enum_t flags; + grub_arc_ushort_t version; + grub_arc_ushort_t rev; + grub_arc_ulong_t key; + grub_arc_ulong_t affinity; + grub_arc_ulong_t configdatasize; + grub_arc_ulong_t idlen; + const char *idstr; +}; + +enum + { +#ifdef GRUB_CPU_WORDS_BIGENDIAN + GRUB_ARC_COMPONENT_TYPE_ARC = 1, +#else + GRUB_ARC_COMPONENT_TYPE_ARC, +#endif + GRUB_ARC_COMPONENT_TYPE_CPU, + GRUB_ARC_COMPONENT_TYPE_FPU, + GRUB_ARC_COMPONENT_TYPE_PRI_I_CACHE, + GRUB_ARC_COMPONENT_TYPE_PRI_D_CACHE, + GRUB_ARC_COMPONENT_TYPE_SEC_I_CACHE, + GRUB_ARC_COMPONENT_TYPE_SEC_D_CACHE, + GRUB_ARC_COMPONENT_TYPE_SEC_CACHE, + GRUB_ARC_COMPONENT_TYPE_EISA, + GRUB_ARC_COMPONENT_TYPE_TCA, + GRUB_ARC_COMPONENT_TYPE_SCSI, + GRUB_ARC_COMPONENT_TYPE_DTIA, + GRUB_ARC_COMPONENT_TYPE_MULTIFUNC, + GRUB_ARC_COMPONENT_TYPE_DISK_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_TAPE_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_CDROM_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_WORM_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_SERIAL_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_NET_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_DISPLAY_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_PARALLEL_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_POINTER_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_KBD_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_AUDIO_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_OTHER_CONTROLLER, + GRUB_ARC_COMPONENT_TYPE_DISK, + GRUB_ARC_COMPONENT_TYPE_FLOPPY, + GRUB_ARC_COMPONENT_TYPE_TAPE, + GRUB_ARC_COMPONENT_TYPE_MODEM, + GRUB_ARC_COMPONENT_TYPE_MONITOR, + GRUB_ARC_COMPONENT_TYPE_PRINTER, + GRUB_ARC_COMPONENT_TYPE_POINTER, + GRUB_ARC_COMPONENT_TYPE_KBD, + GRUB_ARC_COMPONENT_TYPE_TERMINAL, + GRUB_ARC_COMPONENT_TYPE_OTHER_PERIPHERAL, + GRUB_ARC_COMPONENT_TYPE_LINE, + GRUB_ARC_COMPONENT_TYPE_NET, + GRUB_ARC_COMPONENT_TYPE_MEMORY_UNIT, + }; + +enum grub_arc_file_access + { + GRUB_ARC_FILE_ACCESS_OPEN_RO, + GRUB_ARC_FILE_ACCESS_OPEN_WO, + GRUB_ARC_FILE_ACCESS_OPEN_RW, + }; + +struct grub_arc_fileinfo +{ + grub_arc_ularge_t start; + grub_arc_ularge_t end; + grub_arc_ularge_t current; + grub_arc_enum_t type; + grub_arc_ulong_t fnamelength; + grub_arc_uchar_t attr; + char filename[32]; +}; + +struct grub_arc_firmware_vector +{ + /* 0x00. */ + void *load; + void *invoke; + void *execute; + void *halt; + + /* 0x10. */ + void (*powerdown) (void); + void (*restart) (void); + void (*reboot) (void); + void (*exit) (void); + + /* 0x20. */ + void *reserved1; + const struct grub_arc_component * (*getpeer) (const struct grub_arc_component *comp); + const struct grub_arc_component * (*getchild) (const struct grub_arc_component *comp); + void *getparent; + + /* 0x30. */ + void *getconfigurationdata; + void *addchild; + void *deletecomponent; + void *getcomponent; + + /* 0x40. */ + void *saveconfiguration; + void *getsystemid; + struct grub_arc_memory_descriptor *(*getmemorydescriptor) (struct grub_arc_memory_descriptor *current); + void *reserved2; + + /* 0x50. */ + struct grub_arc_timeinfo *(*gettime) (void); + void *getrelativetime; + void *getdirectoryentry; + grub_arc_err_t (*open) (const char *path, grub_arc_enum_t mode, + grub_arc_fileno_t *fileno); + + /* 0x60. */ + grub_arc_err_t (*close) (grub_arc_fileno_t fileno); + grub_arc_err_t (*read) (grub_arc_fileno_t fileno, void *buf, + grub_arc_ulong_t n, + grub_arc_ulong_t *count); + grub_arc_err_t (*get_read_status) (grub_arc_fileno_t fileno); + grub_arc_err_t (*write) (grub_arc_fileno_t fileno, const void *buf, + grub_arc_ulong_t n, + grub_arc_ulong_t *count); + + /* 0x70. */ + grub_arc_err_t (*seek) (grub_arc_fileno_t fileno, + grub_arc_ularge_t *pos, grub_arc_enum_t mode); + void *mount; + void *getenvironmentvariable; + void *setenvironmentvariable; + + /* 0x80. */ + grub_arc_err_t (*getfileinformation) (grub_arc_fileno_t fileno, + struct grub_arc_fileinfo *info); + void *setfileinformation; + void *flushallcaches; + void *testunicodecharacter; + + /* 0x90. */ + struct grub_arc_display_status * (*getdisplaystatus) (grub_arc_fileno_t fileno); +}; + +struct grub_arc_adapter +{ + grub_arc_ulong_t adapter_type; + grub_arc_ulong_t adapter_vector_length; + void *adapter_vector; +}; + +struct grub_arc_system_parameter_block +{ + grub_arc_ulong_t signature; + grub_arc_ulong_t length; + grub_arc_ushort_t version; + grub_arc_ushort_t revision; + void *restartblock; + void *debugblock; + void *gevector; + void *utlbmissvector; + grub_arc_ulong_t firmware_vector_length; + struct grub_arc_firmware_vector *firmwarevector; + grub_arc_ulong_t private_vector_length; + void *private_vector; + grub_arc_ulong_t adapter_count; + struct grub_arc_adapter adapters[0]; +}; + + +#define GRUB_ARC_SYSTEM_PARAMETER_BLOCK ((struct grub_arc_system_parameter_block *) 0xa0001000) +#define GRUB_ARC_FIRMWARE_VECTOR (GRUB_ARC_SYSTEM_PARAMETER_BLOCK->firmwarevector) +#define GRUB_ARC_STDIN 0 +#define GRUB_ARC_STDOUT 1 + +int EXPORT_FUNC (grub_arc_iterate_devs) (int (*hook) (const char *name, const struct grub_arc_component *comp), int alt_names); + +#define FOR_ARC_CHILDREN(comp, parent) for (comp = GRUB_ARC_FIRMWARE_VECTOR->getchild (parent); comp; comp = GRUB_ARC_FIRMWARE_VECTOR->getpeer (comp)) + +extern void grub_arcdisk_init (void); +extern void grub_arcdisk_fini (void); + + +#endif diff --git a/include/grub/arc/console.h b/include/grub/arc/console.h new file mode 100644 index 000000000..e054f54f5 --- /dev/null +++ b/include/grub/arc/console.h @@ -0,0 +1,31 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_CONSOLE_MACHINE_HEADER +#define GRUB_CONSOLE_MACHINE_HEADER 1 + +#include + +/* Initialize the console system. */ +void grub_console_init_early (void); +void grub_console_init_lately (void); + +/* Finish the console system. */ +void grub_console_fini (void); + +#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */ diff --git a/include/grub/ata.h b/include/grub/ata.h index 9e3aaf0e6..efba7b71d 100644 --- a/include/grub/ata.h +++ b/include/grub/ata.h @@ -22,6 +22,7 @@ #include #include +#include /* XXX: For now this only works on i386. */ #include @@ -82,6 +83,9 @@ enum grub_ata_commands GRUB_ATA_CMD_PACKET = 0xa0, GRUB_ATA_CMD_READ_SECTORS = 0x20, GRUB_ATA_CMD_READ_SECTORS_EXT = 0x24, + GRUB_ATA_CMD_READ_SECTORS_DMA = 0xc8, + GRUB_ATA_CMD_READ_SECTORS_DMA_EXT = 0x25, + GRUB_ATA_CMD_SECURITY_FREEZE_LOCK = 0xf5, GRUB_ATA_CMD_SET_FEATURES = 0xef, GRUB_ATA_CMD_SLEEP = 0xe6, @@ -89,29 +93,76 @@ enum grub_ata_commands GRUB_ATA_CMD_STANDBY_IMMEDIATE = 0xe0, GRUB_ATA_CMD_WRITE_SECTORS = 0x30, GRUB_ATA_CMD_WRITE_SECTORS_EXT = 0x34, + GRUB_ATA_CMD_WRITE_SECTORS_DMA_EXT = 0x35, + GRUB_ATA_CMD_WRITE_SECTORS_DMA = 0xca, }; enum grub_ata_timeout_milliseconds { GRUB_ATA_TOUT_STD = 1000, /* 1s standard timeout. */ - GRUB_ATA_TOUT_DATA = 10000 /* 10s DATA I/O timeout. */ + GRUB_ATA_TOUT_DATA = 10000, /* 10s DATA I/O timeout. */ + GRUB_ATA_TOUT_SPINUP = 10000, /* Give the device 10s on first try to spinon. */ }; -struct grub_ata_device +typedef union { - /* IDE port to use. */ - int port; + grub_uint8_t raw[11]; + struct + { + union + { + grub_uint8_t features; + grub_uint8_t error; + }; + union + { + grub_uint8_t sectors; + grub_uint8_t atapi_ireason; + }; + union + { + grub_uint8_t lba_low; + grub_uint8_t sectnum; + }; + union + { + grub_uint8_t lba_mid; + grub_uint8_t cyllsb; + grub_uint8_t atapi_cntlow; + }; + union + { + grub_uint8_t lba_high; + grub_uint8_t cylmsb; + grub_uint8_t atapi_cnthigh; + }; + grub_uint8_t disk; + union + { + grub_uint8_t cmd; + grub_uint8_t status; + }; + grub_uint8_t sectors48; + grub_uint8_t lba48_low; + grub_uint8_t lba48_mid; + grub_uint8_t lba48_high; + }; +} grub_ata_regs_t; - /* IO addresses on which the registers for this device can be - found. */ - grub_port_t ioaddress; - grub_port_t ioaddress2; - - /* Two devices can be connected to a single cable. Use this field - to select device 0 (commonly known as "master") or device 1 - (commonly known as "slave"). */ - int device; +/* ATA pass through parameters and function. */ +struct grub_disk_ata_pass_through_parms +{ + grub_ata_regs_t taskfile; + void * buffer; + grub_size_t size; + int write; + void *cmd; + int cmdsize; + int dma; +}; +struct grub_ata +{ /* Addressing methods available for accessing this device. If CHS is only available, use that. Otherwise use LBA, except for the high sectors. In that case use LBA48. */ @@ -119,6 +170,7 @@ struct grub_ata_device /* Sector count. */ grub_uint64_t size; + grub_uint32_t log_sector_size; /* CHS maximums. */ grub_uint16_t cylinders; @@ -128,47 +180,44 @@ struct grub_ata_device /* Set to 0 for ATA, set to 1 for ATAPI. */ int atapi; - struct grub_ata_device *next; + int dma; + + grub_size_t maxbuffer; + + int *present; + + void *data; + + struct grub_ata_dev *dev; }; -grub_err_t EXPORT_FUNC(grub_ata_wait_not_busy) (struct grub_ata_device *dev, - int milliseconds); -grub_err_t EXPORT_FUNC(grub_ata_wait_drq) (struct grub_ata_device *dev, - int rw, int milliseconds); -void EXPORT_FUNC(grub_ata_pio_read) (struct grub_ata_device *dev, - char *buf, grub_size_t size); +typedef struct grub_ata *grub_ata_t; -static inline void -grub_ata_regset (struct grub_ata_device *dev, int reg, int val) +struct grub_ata_dev { - grub_outb (val, dev->ioaddress + reg); -} + /* Call HOOK with each device name, until HOOK returns non-zero. */ + int (*iterate) (int (*hook) (int id, int bus), + grub_disk_pull_t pull); -static inline grub_uint8_t -grub_ata_regget (struct grub_ata_device *dev, int reg) -{ - return grub_inb (dev->ioaddress + reg); -} + /* Open the device named NAME, and set up SCSI. */ + grub_err_t (*open) (int id, int bus, struct grub_ata *scsi); -static inline void -grub_ata_regset2 (struct grub_ata_device *dev, int reg, int val) -{ - grub_outb (val, dev->ioaddress2 + reg); -} + /* Close the scsi device SCSI. */ + void (*close) (struct grub_ata *ata); -static inline grub_uint8_t -grub_ata_regget2 (struct grub_ata_device *dev, int reg) -{ - return grub_inb (dev->ioaddress2 + reg); -} + /* Read SIZE bytes from the device SCSI into BUF after sending the + command CMD of size CMDSIZE. */ + grub_err_t (*readwrite) (struct grub_ata *ata, + struct grub_disk_ata_pass_through_parms *parms, + int spinup); -static inline grub_err_t -grub_ata_check_ready (struct grub_ata_device *dev) -{ - if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY) - return grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_STD); + /* The next scsi device. */ + struct grub_ata_dev *next; +}; - return GRUB_ERR_NONE; -} +typedef struct grub_ata_dev *grub_ata_dev_t; + +void grub_ata_dev_register (grub_ata_dev_t dev); +void grub_ata_dev_unregister (grub_ata_dev_t dev); #endif /* ! GRUB_ATA_HEADER */ diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h index 636bd41a1..b10336c01 100644 --- a/include/grub/bsdlabel.h +++ b/include/grub/bsdlabel.h @@ -80,7 +80,10 @@ struct grub_partition_bsd_entry struct grub_partition_bsd_disk_label { grub_uint32_t magic; - grub_uint8_t padding[128]; + grub_uint16_t type; + grub_uint8_t unused1[18]; + grub_uint8_t packname[16]; + grub_uint8_t unused2[92]; grub_uint32_t magic2; grub_uint16_t checksum; grub_uint16_t num_partitions; diff --git a/include/grub/cache.h b/include/grub/cache.h index 4f913f5c8..292830566 100644 --- a/include/grub/cache.h +++ b/include/grub/cache.h @@ -37,4 +37,14 @@ grub_arch_sync_caches (void *address __attribute__ ((unused)), void EXPORT_FUNC(grub_arch_sync_caches) (void *address, grub_size_t len); #endif +#ifdef _mips +void EXPORT_FUNC(grub_arch_sync_dma_caches) (void *address, grub_size_t len); +#else +static inline void +grub_arch_sync_dma_caches (void *address __attribute__ ((unused)), + grub_size_t len __attribute__ ((unused))) +{ +} +#endif + #endif /* ! GRUB_CACHE_HEADER */ diff --git a/include/grub/charset.h b/include/grub/charset.h index 1d79d5d2c..4f9e8099f 100644 --- a/include/grub/charset.h +++ b/include/grub/charset.h @@ -36,6 +36,8 @@ #define GRUB_UINT8_5_TRAILINGBITS 0x1f #define GRUB_UINT8_6_TRAILINGBITS 0x3f +#define GRUB_MAX_UTF8_PER_UTF16 4 + #define GRUB_UCS2_LIMIT 0x10000 #define GRUB_UTF16_UPPER_SURROGATE(code) \ (0xD800 + ((((code) - GRUB_UCS2_LIMIT) >> 12) & 0xfff)) @@ -47,9 +49,35 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, const grub_uint8_t **srcend); +/* Determine the last position where the UTF-8 string [beg, end) can + be safely cut. */ +static inline grub_size_t +grub_getend (const char *beg, const char *end) +{ + const char *ptr; + for (ptr = end - 1; ptr >= beg; ptr--) + if ((*ptr & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) + break; + if (ptr < beg) + return 0; + if ((*ptr & GRUB_UINT8_1_LEADINGBIT) == 0) + return ptr + 1 - beg; + if ((*ptr & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS + && ptr + 2 <= end) + return ptr + 2 - beg; + if ((*ptr & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS + && ptr + 3 <= end) + return ptr + 3 - beg; + if ((*ptr & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS + && ptr + 4 <= end) + return ptr + 4 - beg; + /* Invalid character or incomplete. Cut before it. */ + return ptr - beg; +} + /* Convert UTF-16 to UTF-8. */ static inline grub_uint8_t * -grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, +grub_utf16_to_utf8 (grub_uint8_t *dest, const grub_uint16_t *src, grub_size_t size) { grub_uint32_t code_high = 0; @@ -74,6 +102,8 @@ grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, { /* Error... */ *dest++ = '?'; + /* *src may be valid. Don't eat it. */ + src--; } code_high = 0; @@ -97,31 +127,71 @@ grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, /* Error... */ *dest++ = '?'; } - else + else if (code < 0x10000) { *dest++ = (code >> 12) | 0xE0; *dest++ = ((code >> 6) & 0x3F) | 0x80; *dest++ = (code & 0x3F) | 0x80; } + else + { + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } } } return dest; } +#define GRUB_MAX_UTF8_PER_LATIN1 2 + +/* Convert Latin1 to UTF-8. */ +static inline grub_uint8_t * +grub_latin1_to_utf8 (grub_uint8_t *dest, const grub_uint8_t *src, + grub_size_t size) +{ + while (size--) + { + if (!(*src & 0x80)) + *dest++ = *src; + else + { + *dest++ = (*src >> 6) | 0xC0; + *dest++ = (*src & 0x3F) | 0x80; + } + src++; + } + + return dest; +} + /* Convert UCS-4 to UTF-8. */ -char *grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size); +char *grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size); int grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize); int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, grub_uint32_t **last_position); + +/* Process one character from UTF8 sequence. + At beginning set *code = 0, *count = 0. Returns 0 on failure and + 1 on success. *count holds the number of trailing bytes. */ +int +grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count); + void -grub_ucs4_to_utf8 (grub_uint32_t *src, grub_size_t size, +grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size, grub_uint8_t *dest, grub_size_t destsize); grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, const grub_uint8_t **srcend); +/* Returns -2 if not enough space, -1 on invalid character. */ +grub_ssize_t +grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend, + grub_uint32_t code); #endif diff --git a/include/grub/cmos.h b/include/grub/cmos.h index f508e3bf6..331513cd7 100644 --- a/include/grub/cmos.h +++ b/include/grub/cmos.h @@ -20,8 +20,10 @@ #define GRUB_CMOS_H 1 #include +#if !defined (__powerpc__) && !defined (__sparc__) #include #include +#endif #define GRUB_CMOS_INDEX_SECOND 0 #define GRUB_CMOS_INDEX_SECOND_ALARM 1 @@ -55,18 +57,56 @@ grub_num_to_bcd (grub_uint8_t a) return (((a / 10) << 4) + (a % 10)); } -static inline grub_uint8_t -grub_cmos_read (grub_uint8_t index) +#if !defined (__powerpc__) && !defined (__sparc__) +static inline grub_err_t +grub_cmos_read (grub_uint8_t index, grub_uint8_t *val) { grub_outb (index, GRUB_CMOS_ADDR_REG); - return grub_inb (GRUB_CMOS_DATA_REG); + *val = grub_inb (GRUB_CMOS_DATA_REG); + return GRUB_ERR_NONE; } -static inline void +static inline grub_err_t grub_cmos_write (grub_uint8_t index, grub_uint8_t value) { grub_outb (index, GRUB_CMOS_ADDR_REG); grub_outb (value, GRUB_CMOS_DATA_REG); + return GRUB_ERR_NONE; +} +#else +grub_err_t grub_cmos_find_port (void); +extern volatile grub_uint8_t *grub_cmos_port; + +static inline grub_err_t +grub_cmos_read (grub_uint8_t index, grub_uint8_t *val) +{ + if (!grub_cmos_port) + { + grub_err_t err; + err = grub_cmos_find_port (); + if (err) + return err; + } + grub_cmos_port[0] = index; + *val = grub_cmos_port[1]; + return GRUB_ERR_NONE; } +static inline grub_err_t +grub_cmos_write (grub_uint8_t index, grub_uint8_t val) +{ + if (!grub_cmos_port) + { + grub_err_t err; + err = grub_cmos_find_port (); + if (err) + return err; + } + grub_cmos_port[0] = index; + grub_cmos_port[1] = val; + return GRUB_ERR_NONE; +} + +#endif + #endif /* GRUB_CMOS_H */ diff --git a/include/grub/command.h b/include/grub/command.h index 19622752e..57c06da46 100644 --- a/include/grub/command.h +++ b/include/grub/command.h @@ -49,6 +49,7 @@ struct grub_command { /* The next element. */ struct grub_command *next; + struct grub_command **prev; /* The name. */ const char *name; diff --git a/include/grub/crypto.h b/include/grub/crypto.h index ebe78e7a1..9a67c5e11 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -26,6 +26,7 @@ #include #include #include +#include typedef enum { @@ -126,6 +127,9 @@ typedef struct gcry_cipher_spec gcry_cipher_decrypt_t decrypt; gcry_cipher_stencrypt_t stencrypt; gcry_cipher_stdecrypt_t stdecrypt; +#ifdef GRUB_UTIL + const char *modname; +#endif struct gcry_cipher_spec *next; } gcry_cipher_spec_t; @@ -161,6 +165,9 @@ typedef struct gcry_md_spec grub_size_t contextsize; /* allocate this amount of context */ /* Block size, needed for HMAC. */ grub_size_t blocksize; +#ifdef GRUB_UTIL + const char *modname; +#endif struct gcry_md_spec *next; } gcry_md_spec_t; @@ -185,26 +192,61 @@ grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, const unsigned char *key, unsigned keylen); -void -grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher); +static inline void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} -void -grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size); +static inline void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) +{ + const grub_uint8_t *in1ptr = in1, *in2ptr = in2; + grub_uint8_t *outptr = out; + while (size && (((grub_addr_t) in1ptr & (sizeof (grub_uint64_t) - 1)) + || ((grub_addr_t) in2ptr & (sizeof (grub_uint64_t) - 1)) + || ((grub_addr_t) outptr & (sizeof (grub_uint64_t) - 1)))) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + size--; + } + while (size >= sizeof (grub_uint64_t)) + { + *(grub_uint64_t *) (void *) outptr + = (*(grub_uint64_t *) (void *) in1ptr + ^ *(grub_uint64_t *) (void *) in2ptr); + in1ptr += sizeof (grub_uint64_t); + in2ptr += sizeof (grub_uint64_t); + outptr += sizeof (grub_uint64_t); + size -= sizeof (grub_uint64_t); + } + while (size) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + size--; + } +} gcry_err_code_t grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size); + void *out, const void *in, grub_size_t size); gcry_err_code_t grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size); + void *out, const void *in, grub_size_t size); gcry_err_code_t grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, void *iv_in); gcry_err_code_t grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size, + void *out, const void *in, grub_size_t size, void *iv); void grub_cipher_register (gcry_cipher_spec_t *cipher); @@ -229,7 +271,8 @@ struct grub_crypto_hmac_handle * grub_crypto_hmac_init (const struct gcry_md_spec *md, const void *key, grub_size_t keylen); void -grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, + const void *data, grub_size_t datalen); gcry_err_code_t grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out); @@ -237,18 +280,20 @@ grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out); gcry_err_code_t grub_crypto_hmac_buffer (const struct gcry_md_spec *md, const void *key, grub_size_t keylen, - void *data, grub_size_t datalen, void *out); + const void *data, grub_size_t datalen, void *out); 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; +extern gcry_cipher_spec_t _gcry_cipher_spec_aes; #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) +#define GRUB_CIPHER_AES ((const gcry_cipher_spec_t *) &_gcry_cipher_spec_aes) /* 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, @@ -274,4 +319,10 @@ grub_password_get (char buf[], unsigned buf_size); extern void (*grub_crypto_autoload_hook) (const char *name); +#ifdef GRUB_UTIL +void grub_gcry_init_all (void); +void grub_gcry_fini_all (void); +#endif + + #endif diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h new file mode 100644 index 000000000..0bb5d444e --- /dev/null +++ b/include/grub/cryptodisk.h @@ -0,0 +1,149 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_CRYPTODISK_HEADER +#define GRUB_CRYPTODISK_HEADER 1 + +#include +#include +#include + +typedef enum + { + GRUB_CRYPTODISK_MODE_ECB, + GRUB_CRYPTODISK_MODE_CBC, + GRUB_CRYPTODISK_MODE_PCBC, + GRUB_CRYPTODISK_MODE_XTS, + GRUB_CRYPTODISK_MODE_LRW + } grub_cryptodisk_mode_t; + +typedef enum + { + GRUB_CRYPTODISK_MODE_IV_NULL, + GRUB_CRYPTODISK_MODE_IV_PLAIN, + GRUB_CRYPTODISK_MODE_IV_PLAIN64, + GRUB_CRYPTODISK_MODE_IV_ESSIV, + GRUB_CRYPTODISK_MODE_IV_BENBI, + GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64, + GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH + } grub_cryptodisk_mode_iv_t; + +#define GRUB_CRYPTODISK_MAX_UUID_LENGTH 71 + +#define GRUB_CRYPTODISK_GF_LOG_SIZE 7 +#define GRUB_CRYPTODISK_GF_SIZE (1U << GRUB_CRYPTODISK_GF_LOG_SIZE) +#define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3) +#define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES) + +struct grub_cryptodisk; + +typedef gcry_err_code_t +(*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, + grub_uint64_t zoneno); + +struct grub_cryptodisk +{ + struct grub_cryptodisk *next; + struct grub_cryptodisk **prev; + + char *source; + grub_disk_addr_t offset; + grub_disk_addr_t total_length; + grub_disk_t source_disk; + int ref; + grub_crypto_cipher_handle_t cipher; + grub_crypto_cipher_handle_t secondary_cipher; + grub_crypto_cipher_handle_t essiv_cipher; + const gcry_md_spec_t *essiv_hash, *hash, *iv_hash; + grub_cryptodisk_mode_t mode; + grub_cryptodisk_mode_iv_t mode_iv; + int benbi_log; + unsigned long id, source_id; + enum grub_disk_dev_id source_dev_id; + char uuid[GRUB_CRYPTODISK_MAX_UUID_LENGTH + 1]; + grub_uint8_t lrw_key[GRUB_CRYPTODISK_GF_BYTES]; + grub_uint8_t *lrw_precalc; + grub_uint8_t iv_prefix[64]; + grub_size_t iv_prefix_len; +#ifdef GRUB_UTIL + char *cheat; + const char *modname; + int cheat_fd; +#endif + int log_sector_size; + grub_cryptodisk_rekey_func_t rekey; + int rekey_shift; + grub_uint8_t rekey_key[64]; + grub_uint64_t last_rekey; + int rekey_derived_size; +}; +typedef struct grub_cryptodisk *grub_cryptodisk_t; + +struct grub_cryptodisk_dev +{ + struct grub_cryptodisk_dev *next; + struct grub_cryptodisk_dev **prev; + + grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, + int boot_only); + grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev); +}; +typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; + +extern grub_cryptodisk_dev_t EXPORT_VAR (grub_cryptodisk_list); + +#ifndef GRUB_LST_GENERATOR +static inline void +grub_cryptodisk_dev_register (grub_cryptodisk_dev_t cr) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_cryptodisk_list), GRUB_AS_LIST (cr)); +} +#endif + +static inline void +grub_cryptodisk_dev_unregister (grub_cryptodisk_dev_t cr) +{ + grub_list_remove (GRUB_AS_LIST (cr)); +} + +#define FOR_CRYPTODISK_DEVS(var) FOR_LIST_ELEMENTS((var), (grub_cryptodisk_list)) + +gcry_err_code_t +grub_cryptodisk_setkey (grub_cryptodisk_t dev, + grub_uint8_t *key, grub_size_t keysize); +gcry_err_code_t +grub_cryptodisk_decrypt (struct grub_cryptodisk *dev, + grub_uint8_t * data, grub_size_t len, + grub_disk_addr_t sector); +grub_err_t +grub_cryptodisk_insert (grub_cryptodisk_t newdev, const char *name, + grub_disk_t source); +#ifdef GRUB_UTIL +grub_err_t +grub_cryptodisk_cheat_insert (grub_cryptodisk_t newdev, const char *name, + grub_disk_t source, const char *cheat); +void +grub_util_cryptodisk_print_abstraction (grub_disk_t disk); +char * +grub_util_get_geli_uuid (const char *dev); +#endif + +grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid); +grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk); + +#endif diff --git a/include/grub/cs5536.h b/include/grub/cs5536.h index cd17e11fc..6b5b424c8 100644 --- a/include/grub/cs5536.h +++ b/include/grub/cs5536.h @@ -26,9 +26,11 @@ #endif #define GRUB_CS5536_PCIID 0x208f1022 -#define GRUB_CS5536_MSR_MAILBOX_ADDR 0xf4 -#define GRUB_CS5536_MSR_MAILBOX_DATA0 0xf8 -#define GRUB_CS5536_MSR_MAILBOX_DATA1 0xfc +#define GRUB_CS5536_MSR_MAILBOX_CONFIG_ENABLED 0x1 +#define GRUB_CS5536_MSR_MAILBOX_CONFIG 0xf0 +#define GRUB_CS5536_MSR_MAILBOX_ADDR 0xf4 +#define GRUB_CS5536_MSR_MAILBOX_DATA0 0xf8 +#define GRUB_CS5536_MSR_MAILBOX_DATA1 0xfc #define GRUB_CS5536_MSR_IRQ_MAP_BAR 0x80000008 #define GRUB_CS5536_MSR_SMB_BAR 0x8000000b @@ -73,17 +75,23 @@ #define GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1 0x00000002 #define GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86 0x10000000 #define GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP 0x04000000 +#define GRUB_CS5536_MSR_DIVIL_LEG_IO_UART1_COM1 0x00070000 +#define GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3 0x00500000 +#define GRUB_CS5536_MSR_DIVIL_RESET 0x80000017 #define GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_PRIMARY_MASK 0x80000024 #define GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_LPC_MASK 0x80000025 #define GRUB_CS5536_DIVIL_LPC_INTERRUPTS 0x1002 #define GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL 0x8000004e #define GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL_ENABLE 0x80 +#define GRUB_CS5536_MSR_DIVIL_UART1_CONF 0x8000003a +#define GRUB_CS5536_MSR_DIVIL_UART2_CONF 0x8000003e #define GRUB_CS5536_MSR_USB_OHCI_BASE 0x40000008 #define GRUB_CS5536_MSR_USB_EHCI_BASE 0x40000009 #define GRUB_CS5536_MSR_USB_CONTROLLER_BASE 0x4000000a #define GRUB_CS5536_MSR_USB_OPTION_CONTROLLER_BASE 0x4000000b #define GRUB_CS5536_MSR_USB_BASE_ADDR_MASK 0x00ffffff00ULL +#define GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE 0x3f000000000000ULL #define GRUB_CS5536_MSR_USB_BASE_BUS_MASTER 0x0400000000ULL #define GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE 0x0200000000ULL #define GRUB_CS5536_MSR_USB_BASE_PME_ENABLED 0x0800000000ULL diff --git a/include/grub/datetime.h b/include/grub/datetime.h index e721e89af..4accd9cbd 100644 --- a/include/grub/datetime.h +++ b/include/grub/datetime.h @@ -46,10 +46,90 @@ grub_err_t grub_set_datetime (struct grub_datetime *datetime); #endif int grub_get_weekday (struct grub_datetime *datetime); -char *grub_get_weekday_name (struct grub_datetime *datetime); +const char *grub_get_weekday_name (struct grub_datetime *datetime); void grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime); +static inline int +grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int32_t *nix) +{ + grub_int32_t ret; + int y4, ay; + const grub_uint16_t monthssum[12] + = { 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30}; + const grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + const int SECPERMIN = 60; + const int SECPERHOUR = 60 * SECPERMIN; + const int SECPERDAY = 24 * SECPERHOUR; + const int SECPERYEAR = 365 * SECPERDAY; + const int SECPER4YEARS = 4 * SECPERYEAR + SECPERDAY; + + if (datetime->year > 2038 || datetime->year < 1901) + return 0; + if (datetime->month > 12 || datetime->month < 1) + return 0; + + /* In the period of validity of unixtime all years divisible by 4 + are bissextile*/ + /* Convenience: let's have 3 consecutive non-bissextile years + at the beginning of the epoch. So count from 1973 instead of 1970 */ + ret = 3 * SECPERYEAR + SECPERDAY; + + /* Transform C divisions and modulos to mathematical ones */ + y4 = (datetime->year - 1973) / 4; + if (datetime->year < 1973) + y4--; + ay = datetime->year - 1973 - 4 * y4; + ret += y4 * SECPER4YEARS; + ret += ay * SECPERYEAR; + + ret += monthssum[datetime->month - 1] * SECPERDAY; + if (ay == 0 && datetime->month >= 3) + ret += SECPERDAY; + + ret += (datetime->day - 1) * SECPERDAY; + if ((datetime->day > months[datetime->month - 1] + && (!ay || datetime->month != 2 || datetime->day != 29)) + || datetime->day < 1) + return 0; + + ret += datetime->hour * SECPERHOUR; + if (datetime->hour > 23) + return 0; + ret += datetime->minute * 60; + if (datetime->minute > 59) + return 0; + + ret += datetime->second; + /* Accept leap seconds. */ + if (datetime->second > 60) + return 0; + + if ((datetime->year > 1980 && ret < 0) + || (datetime->year < 1960 && ret > 0)) + return 0; + *nix = ret; + return 1; +} + +#if (defined (__powerpc__) || defined (__sparc__)) && !defined (GRUB_UTIL) +grub_err_t +grub_get_datetime_cmos (struct grub_datetime *datetime); +grub_err_t +grub_set_datetime_cmos (struct grub_datetime *datetime); +#endif #endif /* ! KERNEL_DATETIME_HEADER */ diff --git a/include/grub/util/raid.h b/include/grub/deflate.h similarity index 72% rename from include/grub/util/raid.h rename to include/grub/deflate.h index 67020bb86..6ec4eaa99 100644 --- a/include/grub/util/raid.h +++ b/include/grub/deflate.h @@ -1,7 +1,6 @@ -/* raid.h - RAID support for GRUB utils. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,11 +16,11 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_RAID_UTIL_HEADER -#define GRUB_RAID_UTIL_HEADER 1 +#ifndef GRUB_DEFLATE_HEADER +#define GRUB_DEFLATE_HEADER 1 + +grub_ssize_t +grub_zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize); -#ifdef __linux__ -char** grub_util_raid_getmembers (char *name); #endif - -#endif /* ! GRUB_RAID_UTIL_HEADER */ diff --git a/include/grub/device.h b/include/grub/device.h index f0e8a8ca8..f3e43bf60 100644 --- a/include/grub/device.h +++ b/include/grub/device.h @@ -25,7 +25,6 @@ struct grub_disk; struct grub_net; -struct grub_fs; struct grub_device { diff --git a/include/grub/disk.h b/include/grub/disk.h index 9c5653e00..ca46f031e 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -32,17 +32,15 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_OFDISK_ID, GRUB_DISK_DEVICE_LOOPBACK_ID, GRUB_DISK_DEVICE_EFIDISK_ID, - GRUB_DISK_DEVICE_RAID_ID, - GRUB_DISK_DEVICE_LVM_ID, + GRUB_DISK_DEVICE_DISKFILTER_ID, GRUB_DISK_DEVICE_HOST_ID, GRUB_DISK_DEVICE_ATA_ID, GRUB_DISK_DEVICE_MEMDISK_ID, GRUB_DISK_DEVICE_NAND_ID, - GRUB_DISK_DEVICE_UUID_ID, - GRUB_DISK_DEVICE_PXE_ID, GRUB_DISK_DEVICE_SCSI_ID, - GRUB_DISK_DEVICE_FILE_ID, - GRUB_DISK_DEVICE_LUKS_ID + GRUB_DISK_DEVICE_CRYPTODISK_ID, + GRUB_DISK_DEVICE_ARCDISK_ID, + GRUB_DISK_DEVICE_HOSTDISK_ID, }; struct grub_disk; @@ -50,6 +48,14 @@ struct grub_disk; struct grub_disk_memberlist; #endif +typedef enum + { + GRUB_DISK_PULL_NONE, + GRUB_DISK_PULL_REMOVABLE, + GRUB_DISK_PULL_RESCAN, + GRUB_DISK_PULL_MAX + } grub_disk_pull_t; + /* Disk device. */ struct grub_disk_dev { @@ -60,7 +66,8 @@ struct grub_disk_dev enum grub_disk_dev_id id; /* Call HOOK with each device name, until HOOK returns non-zero. */ - int (*iterate) (int (*hook) (const char *name)); + int (*iterate) (int (*hook) (const char *name), + grub_disk_pull_t pull); /* Open the device named NAME, and set up DISK. */ grub_err_t (*open) (const char *name, struct grub_disk *disk); @@ -78,6 +85,7 @@ struct grub_disk_dev #ifdef GRUB_UTIL struct grub_disk_memberlist *(*memberlist) (struct grub_disk *disk); + const char * (*raidname) (struct grub_disk *disk); #endif /* The next disk device. */ @@ -85,6 +93,8 @@ struct grub_disk_dev }; typedef struct grub_disk_dev *grub_disk_dev_t; +extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list); + struct grub_partition; /* Disk. */ @@ -99,6 +109,9 @@ struct grub_disk /* The total number of sectors. */ grub_uint64_t total_sectors; + /* Logarithm of sector size. */ + unsigned int log_sector_size; + /* The id used by the disk cache manager. */ unsigned long id; @@ -131,9 +144,10 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t; /* The maximum number of disk caches. */ #define GRUB_DISK_CACHE_NUM 1021 -/* The size of a disk cache in sector units. */ -#define GRUB_DISK_CACHE_SIZE 8 -#define GRUB_DISK_CACHE_BITS 3 +/* The size of a disk cache in 512B units. Must be at least as big as the + largest supported sector size, currently 16K. */ +#define GRUB_DISK_CACHE_BITS 6 +#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS) /* Return value of grub_disk_get_size() in case disk size is unknown. */ #define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL @@ -143,7 +157,19 @@ void grub_disk_cache_invalidate_all (void); void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev); void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev); -int EXPORT_FUNC(grub_disk_dev_iterate) (int (*hook) (const char *name)); +static inline int +grub_disk_dev_iterate (int (*hook) (const char *name)) +{ + grub_disk_dev_t p; + grub_disk_pull_t pull; + + for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++) + for (p = grub_disk_dev_list; p; p = p->next) + if (p->iterate && (p->iterate) (hook, pull)) + return 1; + + return 0; +} grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name); void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk); @@ -160,29 +186,25 @@ grub_err_t EXPORT_FUNC(grub_disk_write) (grub_disk_t disk, grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk); +#if DISK_CACHE_STATS +void +EXPORT_FUNC(grub_disk_cache_get_performance) (unsigned long *hits, unsigned long *misses); +#endif + extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void); extern int EXPORT_VAR(grub_disk_firmware_is_tainted); -/* ATA pass through parameters and function. */ -struct grub_disk_ata_pass_through_parms -{ - grub_uint8_t taskfile[8]; - void * buffer; - int size; -}; - -extern grub_err_t (* EXPORT_VAR(grub_disk_ata_pass_through)) (grub_disk_t, - struct grub_disk_ata_pass_through_parms *); - #if defined (GRUB_UTIL) || defined (GRUB_MACHINE_EMU) void grub_lvm_init (void); +void grub_ldm_init (void); void grub_mdraid09_init (void); void grub_mdraid1x_init (void); -void grub_raid_init (void); +void grub_diskfilter_init (void); void grub_lvm_fini (void); +void grub_ldm_fini (void); void grub_mdraid09_fini (void); void grub_mdraid1x_fini (void); -void grub_raid_fini (void); +void grub_diskfilter_fini (void); #endif #endif /* ! GRUB_DISK_HEADER */ diff --git a/include/grub/diskfilter.h b/include/grub/diskfilter.h new file mode 100644 index 000000000..ed2ac2829 --- /dev/null +++ b/include/grub/diskfilter.h @@ -0,0 +1,191 @@ +/* diskfilter.h - On disk structures for RAID. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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_DISKFILTER_H +#define GRUB_DISKFILTER_H 1 + +#include +#include + +enum + { + GRUB_RAID_LAYOUT_RIGHT_MASK = 1, + GRUB_RAID_LAYOUT_SYMMETRIC_MASK = 2, + GRUB_RAID_LAYOUT_MUL_FROM_POS = 4, + + GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC = 0, + GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC = GRUB_RAID_LAYOUT_RIGHT_MASK, + GRUB_RAID_LAYOUT_LEFT_SYMMETRIC = GRUB_RAID_LAYOUT_SYMMETRIC_MASK, + GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC = (GRUB_RAID_LAYOUT_RIGHT_MASK + | GRUB_RAID_LAYOUT_SYMMETRIC_MASK) + }; + + +struct grub_diskfilter_vg { + char *uuid; + grub_size_t uuid_len; + /* Optional. */ + char *name; + int extent_size; + struct grub_diskfilter_pv *pvs; + struct grub_diskfilter_lv *lvs; + struct grub_diskfilter_vg *next; + +#ifdef GRUB_UTIL + struct grub_diskfilter *driver; +#endif +}; + +struct grub_diskfilter_pv_id { + union + { + char *uuid; + int id; + }; + grub_size_t uuidlen; +}; + +struct grub_diskfilter_pv { + struct grub_diskfilter_pv_id id; + /* Optional. */ + char *name; + grub_disk_t disk; + grub_disk_addr_t part_start; + grub_disk_addr_t part_size; + grub_disk_addr_t start_sector; /* Sector number where the data area starts. */ + struct grub_diskfilter_pv *next; + /* Optional. */ + grub_uint8_t *internal_id; +}; + +struct grub_diskfilter_lv { + /* Name used for disk. */ + char *fullname; + /* Optional. */ + char *name; + int number; + unsigned int segment_count; + grub_size_t segment_alloc; + grub_uint64_t size; + int became_readable_at; + + int visible; + + /* Pointer to segment_count segments. */ + struct grub_diskfilter_segment *segments; + struct grub_diskfilter_vg *vg; + struct grub_diskfilter_lv *next; + + /* Optional. */ + char *internal_id; +}; + +struct grub_diskfilter_segment { + unsigned int start_extent; + unsigned int extent_count; + enum + { + GRUB_DISKFILTER_STRIPED = 0, + GRUB_DISKFILTER_MIRROR = 1, + GRUB_DISKFILTER_RAID4 = 4, + GRUB_DISKFILTER_RAID5 = 5, + GRUB_DISKFILTER_RAID6 = 6, + GRUB_DISKFILTER_RAID10 = 10, + } type; + int layout; + /* valid only for raid10. */ + grub_uint64_t raid_member_size; + + unsigned int node_count; + unsigned int node_alloc; + struct grub_diskfilter_node *nodes; + + unsigned int stripe_size; +}; + +struct grub_diskfilter_node { + grub_disk_addr_t start; + /* Optional. */ + char *name; + struct grub_diskfilter_pv *pv; + struct grub_diskfilter_lv *lv; +}; + +struct grub_diskfilter_vg * +grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid); + +struct grub_diskfilter +{ + struct grub_diskfilter *next; + struct grub_diskfilter **prev; + + const char *name; + + struct grub_diskfilter_vg * (*detect) (grub_disk_t disk, + struct grub_diskfilter_pv_id *id, + grub_disk_addr_t *start_sector); +}; +typedef struct grub_diskfilter *grub_diskfilter_t; + +extern grub_diskfilter_t grub_diskfilter_list; +static inline void +grub_diskfilter_register (grub_diskfilter_t diskfilter) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_diskfilter_list), + GRUB_AS_LIST (diskfilter)); +} +static inline void +grub_diskfilter_unregister (grub_diskfilter_t diskfilter) +{ + grub_list_remove (GRUB_AS_LIST (diskfilter)); +} + +struct grub_diskfilter_vg * +grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, + char *name, grub_uint64_t disk_size, + grub_uint64_t stripe_size, + int layout, int level); + +typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_diskfilter_segment *array, + int disknr, char *buf, + grub_disk_addr_t sector, + int size); + +typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_diskfilter_segment *array, + int disknr, int p, char *buf, + grub_disk_addr_t sector, + int size); + +extern grub_raid5_recover_func_t grub_raid5_recover_func; +extern grub_raid6_recover_func_t grub_raid6_recover_func; + +grub_err_t grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg); + +grub_err_t +grub_diskfilter_read_node (const struct grub_diskfilter_node *node, + grub_disk_addr_t sector, + grub_size_t size, char *buf); + +#ifdef GRUB_UTIL +struct grub_diskfilter_pv * +grub_diskfilter_get_pv_from_disk (grub_disk_t disk, + struct grub_diskfilter_vg **vg); +#endif + +#endif /* ! GRUB_RAID_H */ diff --git a/include/grub/dl.h b/include/grub/dl.h index afc4af41a..d5f009829 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -21,15 +21,18 @@ #define GRUB_DL_H 1 #include +#ifndef ASM_FILE #include #include #include +#endif /* * Macros GRUB_MOD_INIT and GRUB_MOD_FINI are also used by build rules * to collect module names, so we define them only when they are not * defined already. */ +#ifndef ASM_FILE #ifndef GRUB_MOD_INIT #define GRUB_MOD_INIT(name) \ @@ -51,20 +54,61 @@ static void \ grub_mod_fini (void) #endif -#ifdef APPLE_CC -#define GRUB_MOD_NAME(name) \ -static char grub_modname[] __attribute__ ((section ("_modname, _modname"), used)) = #name; - -#define GRUB_MOD_DEP(name) \ -__asm__ (".section _moddeps, _moddeps\n.asciz \"" #name "\"\n") -#else -#define GRUB_MOD_NAME(name) \ -__asm__ (".section .modname\n.asciz \"" #name "\"\n") - -#define GRUB_MOD_DEP(name) \ -__asm__ (".section .moddeps\n.asciz \"" #name "\"\n") #endif +#ifndef ASM_FILE +#ifdef APPLE_CC +#define GRUB_MOD_SECTION(x) "_" #x ", _" #x "" +#else +#define GRUB_MOD_SECTION(x) "." #x +#endif +#else +#ifdef APPLE_CC +#define GRUB_MOD_SECTION(x) _ ## x , _ ##x +#else +#define GRUB_MOD_SECTION(x) . ## x +#endif +#endif + +#ifndef ASM_FILE +#define GRUB_MOD_DEP(name) \ +static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), __used__)) = #name +#define GRUB_MOD_NAME(name) \ +static const char grub_module_name_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(modname)), __used__)) = #name +#endif + +/* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally + multi-licensed under other licences as well) independently of the + presence of this check and solely by linking (module loading in GRUB + constitutes linking) and GRUB core being licensed under GPLv3+. + Be sure to understand your license obligations. +*/ +#ifndef ASM_FILE +#define GRUB_MOD_LICENSE(license) \ + static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), used)) = "LICENSE=" license; +#define GRUB_MOD_DEP(name) \ +static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), __used__)) = #name +#else +#define GRUB_MOD_LICENSE(license) \ + .section GRUB_MOD_SECTION(module_license), "a"; \ + .ascii "LICENSE="; \ + .ascii license; \ + .byte 0 +#endif + +/* Under GPL license obligations you have to distribute your module + under GPLv3(+). However, you can also distribute the same code under + another license as long as GPLv3(+) version is provided. +*/ +#define GRUB_MOD_DUAL_LICENSE(x) + +#ifndef ASM_FILE + struct grub_dl_segment { struct grub_dl_segment *next; @@ -92,6 +136,12 @@ struct grub_dl Elf_Sym *symtab; void (*init) (struct grub_dl *mod); void (*fini) (void); +#if defined (__ia64__) || defined (__powerpc__) + void *got; + void *tramp; +#endif + void *base; + grub_size_t sz; struct grub_dl *next; }; typedef struct grub_dl *grub_dl_t; @@ -109,7 +159,7 @@ extern grub_dl_t EXPORT_VAR(grub_dl_head); grub_dl_t EXPORT_FUNC(grub_dl_get) (const char *name); grub_err_t grub_dl_register_symbol (const char *name, void *addr, - grub_dl_t mod); + int isfunc, grub_dl_t mod); grub_err_t grub_arch_dl_check_header (void *ehdr); grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr); @@ -119,4 +169,31 @@ grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr); void grub_arch_dl_init_linker (void); #endif +#define GRUB_IA64_DL_TRAMP_ALIGN 16 +#define GRUB_IA64_DL_TRAMP_SIZE 48 +#define GRUB_IA64_DL_GOT_ALIGN 16 + +void +grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); + +#if defined (__ia64__) +#define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN +#define GRUB_ARCH_DL_GOT_ALIGN GRUB_IA64_DL_GOT_ALIGN +#define GRUB_ARCH_DL_TRAMP_SIZE GRUB_IA64_DL_TRAMP_SIZE +#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size +#else +void +grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); +#endif + +#ifdef __powerpc__ +#define GRUB_ARCH_DL_TRAMP_SIZE 16 +#define GRUB_ARCH_DL_TRAMP_ALIGN 4 +#define GRUB_ARCH_DL_GOT_ALIGN 4 +#endif + +#endif + #endif /* ! GRUB_DL_H */ diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index cb6b1113b..b3ec6636b 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -84,6 +84,16 @@ { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ } +#define GRUB_EFI_SIMPLE_NETWORK_GUID \ + { 0xa19832b9, 0xac25, 0x11d3, \ + { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_PXE_GUID \ + { 0x03c4e603, 0xac28, 0x11d3, \ + { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + #define GRUB_EFI_DEVICE_PATH_GUID \ { 0x09576e91, 0x6d3f, 0x11d2, \ { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ @@ -361,7 +371,7 @@ struct grub_efi_memory_descriptor grub_efi_virtual_address_t virtual_start; grub_efi_uint64_t num_pages; grub_efi_uint64_t attribute; -}; +} __attribute__ ((packed)); typedef struct grub_efi_memory_descriptor grub_efi_memory_descriptor_t; /* Device Path definitions. */ @@ -406,7 +416,7 @@ struct grub_efi_pci_device_path grub_efi_device_path_t header; grub_efi_uint8_t function; grub_efi_uint8_t device; -}; +} __attribute__ ((packed)); typedef struct grub_efi_pci_device_path grub_efi_pci_device_path_t; #define GRUB_EFI_PCCARD_DEVICE_PATH_SUBTYPE 2 @@ -415,7 +425,7 @@ struct grub_efi_pccard_device_path { grub_efi_device_path_t header; grub_efi_uint8_t function; -}; +} __attribute__ ((packed)); typedef struct grub_efi_pccard_device_path grub_efi_pccard_device_path_t; #define GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE 3 @@ -423,10 +433,10 @@ typedef struct grub_efi_pccard_device_path grub_efi_pccard_device_path_t; struct grub_efi_memory_mapped_device_path { grub_efi_device_path_t header; - grub_efi_memory_type_t memory_type; + grub_efi_uint32_t memory_type; grub_efi_physical_address_t start_address; grub_efi_physical_address_t end_address; -}; +} __attribute__ ((packed)); typedef struct grub_efi_memory_mapped_device_path grub_efi_memory_mapped_device_path_t; #define GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE 4 @@ -436,7 +446,7 @@ struct grub_efi_vendor_device_path grub_efi_device_path_t header; grub_efi_guid_t vendor_guid; grub_efi_uint8_t vendor_defined_data[0]; -}; +} __attribute__ ((packed)); typedef struct grub_efi_vendor_device_path grub_efi_vendor_device_path_t; #define GRUB_EFI_CONTROLLER_DEVICE_PATH_SUBTYPE 5 @@ -445,7 +455,7 @@ struct grub_efi_controller_device_path { grub_efi_device_path_t header; grub_efi_uint32_t controller_number; -}; +} __attribute__ ((packed)); typedef struct grub_efi_controller_device_path grub_efi_controller_device_path_t; /* ACPI Device Path. */ @@ -458,7 +468,7 @@ struct grub_efi_acpi_device_path grub_efi_device_path_t header; grub_efi_uint32_t hid; grub_efi_uint32_t uid; -}; +} __attribute__ ((packed)); typedef struct grub_efi_acpi_device_path grub_efi_acpi_device_path_t; #define GRUB_EFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE 2 @@ -469,8 +479,8 @@ struct grub_efi_expanded_acpi_device_path grub_efi_uint32_t hid; grub_efi_uint32_t uid; grub_efi_uint32_t cid; - char hidstr[1]; -}; + char hidstr[0]; +} __attribute__ ((packed)); typedef struct grub_efi_expanded_acpi_device_path grub_efi_expanded_acpi_device_path_t; #define GRUB_EFI_EXPANDED_ACPI_HIDSTR(dp) \ @@ -493,7 +503,7 @@ struct grub_efi_atapi_device_path grub_efi_uint8_t primary_secondary; grub_efi_uint8_t slave_master; grub_efi_uint16_t lun; -}; +} __attribute__ ((packed)); typedef struct grub_efi_atapi_device_path grub_efi_atapi_device_path_t; #define GRUB_EFI_SCSI_DEVICE_PATH_SUBTYPE 2 @@ -503,7 +513,7 @@ struct grub_efi_scsi_device_path grub_efi_device_path_t header; grub_efi_uint16_t pun; grub_efi_uint16_t lun; -}; +} __attribute__ ((packed)); typedef struct grub_efi_scsi_device_path grub_efi_scsi_device_path_t; #define GRUB_EFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE 3 @@ -514,7 +524,7 @@ struct grub_efi_fibre_channel_device_path grub_efi_uint32_t reserved; grub_efi_uint64_t wwn; grub_efi_uint64_t lun; -}; +} __attribute__ ((packed)); typedef struct grub_efi_fibre_channel_device_path grub_efi_fibre_channel_device_path_t; #define GRUB_EFI_1394_DEVICE_PATH_SUBTYPE 4 @@ -524,7 +534,7 @@ struct grub_efi_1394_device_path grub_efi_device_path_t header; grub_efi_uint32_t reserved; grub_efi_uint64_t guid; -}; +} __attribute__ ((packed)); typedef struct grub_efi_1394_device_path grub_efi_1394_device_path_t; #define GRUB_EFI_USB_DEVICE_PATH_SUBTYPE 5 @@ -534,7 +544,7 @@ struct grub_efi_usb_device_path grub_efi_device_path_t header; grub_efi_uint8_t parent_port_number; grub_efi_uint8_t interface; -}; +} __attribute__ ((packed)); typedef struct grub_efi_usb_device_path grub_efi_usb_device_path_t; #define GRUB_EFI_USB_CLASS_DEVICE_PATH_SUBTYPE 15 @@ -547,7 +557,7 @@ struct grub_efi_usb_class_device_path grub_efi_uint8_t device_class; grub_efi_uint8_t device_subclass; grub_efi_uint8_t device_protocol; -}; +} __attribute__ ((packed)); typedef struct grub_efi_usb_class_device_path grub_efi_usb_class_device_path_t; #define GRUB_EFI_I2O_DEVICE_PATH_SUBTYPE 6 @@ -556,7 +566,7 @@ struct grub_efi_i2o_device_path { grub_efi_device_path_t header; grub_efi_uint32_t tid; -}; +} __attribute__ ((packed)); typedef struct grub_efi_i2o_device_path grub_efi_i2o_device_path_t; #define GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE 11 @@ -566,7 +576,7 @@ struct grub_efi_mac_address_device_path grub_efi_device_path_t header; grub_efi_mac_address_t mac_address; grub_efi_uint8_t if_type; -}; +} __attribute__ ((packed)); typedef struct grub_efi_mac_address_device_path grub_efi_mac_address_device_path_t; #define GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE 12 @@ -580,7 +590,7 @@ struct grub_efi_ipv4_device_path grub_efi_uint16_t remote_port; grub_efi_uint16_t protocol; grub_efi_uint8_t static_ip_address; -}; +} __attribute__ ((packed)); typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; #define GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE 13 @@ -594,7 +604,7 @@ struct grub_efi_ipv6_device_path grub_efi_uint16_t remote_port; grub_efi_uint16_t protocol; grub_efi_uint8_t static_ip_address; -}; +} __attribute__ ((packed)); typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; #define GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE 9 @@ -607,7 +617,7 @@ struct grub_efi_infiniband_device_path grub_efi_uint64_t remote_id; grub_efi_uint64_t target_port_id; grub_efi_uint64_t device_id; -}; +} __attribute__ ((packed)); typedef struct grub_efi_infiniband_device_path grub_efi_infiniband_device_path_t; #define GRUB_EFI_UART_DEVICE_PATH_SUBTYPE 14 @@ -620,7 +630,7 @@ struct grub_efi_uart_device_path grub_efi_uint8_t data_bits; grub_efi_uint8_t parity; grub_efi_uint8_t stop_bits; -}; +} __attribute__ ((packed)); typedef struct grub_efi_uart_device_path grub_efi_uart_device_path_t; #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 @@ -630,7 +640,7 @@ struct grub_efi_vendor_messaging_device_path grub_efi_device_path_t header; grub_efi_guid_t vendor_guid; grub_efi_uint8_t vendor_defined_data[0]; -}; +} __attribute__ ((packed)); typedef struct grub_efi_vendor_messaging_device_path grub_efi_vendor_messaging_device_path_t; /* Media Device Path. */ @@ -647,7 +657,7 @@ struct grub_efi_hard_drive_device_path grub_efi_uint8_t partition_signature[8]; grub_efi_uint8_t mbr_type; grub_efi_uint8_t signature_type; -}; +} __attribute__ ((packed)); typedef struct grub_efi_hard_drive_device_path grub_efi_hard_drive_device_path_t; #define GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE 2 @@ -658,7 +668,7 @@ struct grub_efi_cdrom_device_path grub_efi_uint32_t boot_entry; grub_efi_lba_t partition_start; grub_efi_lba_t partition_size; -}; +} __attribute__ ((packed)); typedef struct grub_efi_cdrom_device_path grub_efi_cdrom_device_path_t; #define GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE 3 @@ -668,7 +678,7 @@ struct grub_efi_vendor_media_device_path grub_efi_device_path_t header; grub_efi_guid_t vendor_guid; grub_efi_uint8_t vendor_defined_data[0]; -}; +} __attribute__ ((packed)); typedef struct grub_efi_vendor_media_device_path grub_efi_vendor_media_device_path_t; #define GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE 4 @@ -677,7 +687,7 @@ struct grub_efi_file_path_device_path { grub_efi_device_path_t header; grub_efi_char16_t path_name[0]; -}; +} __attribute__ ((packed)); typedef struct grub_efi_file_path_device_path grub_efi_file_path_device_path_t; #define GRUB_EFI_PROTOCOL_DEVICE_PATH_SUBTYPE 5 @@ -686,7 +696,7 @@ struct grub_efi_protocol_device_path { grub_efi_device_path_t header; grub_efi_guid_t guid; -}; +} __attribute__ ((packed)); typedef struct grub_efi_protocol_device_path grub_efi_protocol_device_path_t; #define GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE 6 @@ -695,7 +705,7 @@ struct grub_efi_piwg_device_path { grub_efi_device_path_t header; grub_efi_guid_t guid __attribute__ ((packed)); -}; +} __attribute__ ((packed)); typedef struct grub_efi_piwg_device_path grub_efi_piwg_device_path_t; @@ -710,7 +720,7 @@ struct grub_efi_bios_device_path grub_efi_uint16_t device_type; grub_efi_uint16_t status_flags; char description[0]; -}; +} __attribute__ ((packed)); typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; struct grub_efi_open_protocol_information_entry @@ -1113,6 +1123,36 @@ struct grub_efi_simple_text_output_interface }; typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t; +typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; + +typedef struct grub_efi_pxe_mode +{ + grub_uint8_t unused[52]; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; +} grub_efi_pxe_mode_t; + +typedef struct grub_efi_pxe +{ + grub_uint64_t rev; + void (*start) (void); + void (*stop) (void); + void (*dhcp) (void); + void (*discover) (void); + void (*mftp) (void); + void (*udpwrite) (void); + void (*udpread) (void); + void (*setipfilter) (void); + void (*arp) (void); + void (*setparams) (void); + void (*setstationip) (void); + void (*setpackets) (void); + struct grub_efi_pxe_mode *mode; +} grub_efi_pxe_t; + #define GRUB_EFI_BLACK 0x00 #define GRUB_EFI_BLUE 0x01 #define GRUB_EFI_GREEN 0x02 @@ -1214,6 +1254,76 @@ struct grub_efi_block_io_media }; typedef struct grub_efi_block_io_media grub_efi_block_io_media_t; +typedef grub_uint8_t grub_efi_mac_t[32]; + +struct grub_efi_simple_network_mode +{ + grub_uint32_t state; + grub_uint32_t hwaddr_size; + grub_uint32_t media_header_size; + grub_uint32_t max_packet_size; + grub_uint32_t nvram_size; + grub_uint32_t nvram_access_size; + grub_uint32_t receive_filter_mask; + grub_uint32_t receive_filter_setting; + grub_uint32_t max_mcast_filter_count; + grub_uint32_t mcast_filter_count; + grub_efi_mac_t mcast_filter[16]; + grub_efi_mac_t current_address; + grub_efi_mac_t broadcast_address; + grub_efi_mac_t permanent_address; + grub_uint8_t if_type; + grub_uint8_t mac_changeable; + grub_uint8_t multitx_supported; + grub_uint8_t media_present_supported; + grub_uint8_t media_present; +}; + +enum + { + GRUB_EFI_NETWORK_STOPPED, + GRUB_EFI_NETWORK_STARTED, + GRUB_EFI_NETWORK_INITIALIZED, + }; + +struct grub_efi_simple_network +{ + grub_uint64_t revision; + grub_efi_status_t (*start) (struct grub_efi_simple_network *this); + void (*stop) (void); + grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this, + grub_efi_uintn_t extra_rx, + grub_efi_uintn_t extra_tx); + void (*reset) (void); + void (*shutdown) (void); + void (*receive_filters) (void); + void (*station_address) (void); + void (*statistics) (void); + void (*mcastiptomac) (void); + void (*nvdata) (void); + grub_efi_status_t (*get_status) (struct grub_efi_simple_network *this, + grub_uint32_t *int_status, + void **txbuf); + grub_efi_status_t (*transmit) (struct grub_efi_simple_network *this, + grub_efi_uintn_t header_size, + grub_efi_uintn_t buffer_size, + void *buffer, + grub_efi_mac_t *src_addr, + grub_efi_mac_t *dest_addr, + grub_efi_uint16_t *protocol); + grub_efi_status_t (*receive) (struct grub_efi_simple_network *this, + grub_efi_uintn_t *header_size, + grub_efi_uintn_t *buffer_size, + void *buffer, + grub_efi_mac_t *src_addr, + grub_efi_mac_t *dest_addr, + grub_uint16_t *protocol); + void (*waitforpacket) (void); + struct grub_efi_simple_network_mode *mode; +}; +typedef struct grub_efi_simple_network grub_efi_simple_network_t; + + struct grub_efi_block_io { grub_efi_uint64_t revision; @@ -1234,7 +1344,7 @@ struct grub_efi_block_io }; typedef struct grub_efi_block_io grub_efi_block_io_t; -#if GRUB_TARGET_SIZEOF_VOID_P == 4 +#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) #define efi_call_0(func) func() #define efi_call_1(func, a) func(a) @@ -1243,6 +1353,7 @@ typedef struct grub_efi_block_io grub_efi_block_io_t; #define efi_call_4(func, a, b, c, d) func(a, b, c, d) #define efi_call_5(func, a, b, c, d, e) func(a, b, c, d, e) #define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f) +#define efi_call_7(func, a, b, c, d, e, f, g) func(a, b, c, d, e, f, g) #define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) func(a, b, c, d, e, f, g, h, i, j) #else @@ -1250,24 +1361,31 @@ typedef struct grub_efi_block_io grub_efi_block_io_t; #define efi_call_0(func) \ efi_wrap_0(func) #define efi_call_1(func, a) \ - efi_wrap_1(func, (grub_uint64_t) a) + efi_wrap_1(func, (grub_uint64_t) (a)) #define efi_call_2(func, a, b) \ - efi_wrap_2(func, (grub_uint64_t) a, (grub_uint64_t) b) + efi_wrap_2(func, (grub_uint64_t) (a), (grub_uint64_t) (b)) #define efi_call_3(func, a, b, c) \ - efi_wrap_3(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c) + efi_wrap_3(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c)) #define efi_call_4(func, a, b, c, d) \ - efi_wrap_4(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \ - (grub_uint64_t) d) + efi_wrap_4(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d)) #define efi_call_5(func, a, b, c, d, e) \ - efi_wrap_5(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \ - (grub_uint64_t) d, (grub_uint64_t) e) + efi_wrap_5(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e)) #define efi_call_6(func, a, b, c, d, e, f) \ - efi_wrap_6(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \ - (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f) + efi_wrap_6(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \ + (grub_uint64_t) (f)) +#define efi_call_7(func, a, b, c, d, e, f, g) \ + efi_wrap_7(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \ + (grub_uint64_t) (f), (grub_uint64_t) (g)) #define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) \ - efi_wrap_10(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \ - (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f, (grub_uint64_t) g, \ - (grub_uint64_t) h, (grub_uint64_t) i, (grub_uint64_t) j) + efi_wrap_10(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \ + (grub_uint64_t) (f), (grub_uint64_t) (g), (grub_uint64_t) (h), \ + (grub_uint64_t) (i), (grub_uint64_t) (j)) grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func); grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1); @@ -1285,6 +1403,10 @@ grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1, grub_uint64_t arg2, grub_uint64_t arg3, grub_uint64_t arg4, grub_uint64_t arg5, grub_uint64_t arg6); +grub_uint64_t EXPORT_FUNC(efi_wrap_7) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5, + grub_uint64_t arg6, grub_uint64_t arg7); grub_uint64_t EXPORT_FUNC(efi_wrap_10) (void *func, grub_uint64_t arg1, grub_uint64_t arg2, grub_uint64_t arg3, grub_uint64_t arg4, grub_uint64_t arg5, diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index e9c57dd11..7ecda58ab 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -62,6 +62,16 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo grub_efi_uint32_t descriptor_version, grub_efi_memory_descriptor_t *virtual_map); +int +EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2); + +extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + char **device, + char **path); + +grub_addr_t grub_efi_modules_addr (void); + void grub_efi_mm_init (void); void grub_efi_mm_fini (void); void grub_efi_init (void); diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h index 133f9504c..20526b146 100644 --- a/include/grub/efi/memory.h +++ b/include/grub/efi/memory.h @@ -24,15 +24,8 @@ #define GRUB_MMAP_REGISTER_BY_FIRMWARE 1 -grub_err_t grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, - grub_uint32_t)); grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, int type, int handle); grub_err_t grub_machine_mmap_unregister (int handle); -grub_uint64_t grub_mmap_get_post64 (void); -grub_uint64_t grub_mmap_get_upper (void); -grub_uint64_t grub_mmap_get_lower (void); - #endif /* ! GRUB_MEMORY_MACHINE_HEADER */ diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index 81a1a5797..c3efa9b3d 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -64,6 +64,7 @@ struct grub_pe32_coff_header }; #define GRUB_PE32_MACHINE_I386 0x14c +#define GRUB_PE32_MACHINE_IA64 0x200 #define GRUB_PE32_MACHINE_X86_64 0x8664 #define GRUB_PE32_RELOCS_STRIPPED 0x0001 diff --git a/include/grub/efi/time.h b/include/grub/efi/time.h index 540f6fc04..51b337309 100644 --- a/include/grub/efi/time.h +++ b/include/grub/efi/time.h @@ -21,8 +21,7 @@ #include -/* This is destined to overflow when one hour passes by. */ -#define GRUB_TICKS_PER_SECOND ((1UL << 31) / 60 / 60 * 2) +#define GRUB_TICKS_PER_SECOND 1000 /* Return the real time in ticks. */ grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 8eee98b61..530e18c82 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -21,6 +21,7 @@ #include #include +#include #define GRUB_EFIEMU_PAGESIZE 4096 @@ -113,9 +114,9 @@ extern grub_efi_system_table64_t *grub_efiemu_system_table64; : (grub_efiemu_system_table32->x \ = (y))) #define GRUB_EFIEMU_SYSTEM_TABLE_PTR(x) ((grub_efiemu_sizeof_uintn_t () == 8)\ - ? UINT_TO_PTR \ + ? (void *) (grub_addr_t) \ (grub_efiemu_system_table64->x) \ - : UINT_TO_PTR \ + : (void *) (grub_addr_t) \ (grub_efiemu_system_table32->x)) #define GRUB_EFIEMU_SYSTEM_TABLE_VAR(x) ((grub_efiemu_sizeof_uintn_t () == 8) \ ? (void *) \ @@ -199,15 +200,9 @@ grub_efiemu_register_configuration_table (grub_efi_guid_t guid, int grub_efiemu_request_memalign (grub_size_t align, grub_size_t size, grub_efi_memory_type_t type); void *grub_efiemu_mm_obtain_request (int handle); -int grub_efiemu_get_memory_map (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_mm_unload (void); grub_err_t grub_efiemu_mm_do_alloc (void); grub_err_t grub_efiemu_mm_init (void); -void *grub_efiemu_mm_obtain_request (int handle); void grub_efiemu_mm_return_request (int handle); grub_efi_memory_type_t grub_efiemu_mm_get_type (int handle); @@ -227,9 +222,7 @@ grub_efiemu_finish_boot_services (grub_efi_uintn_t *memory_map_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)); +grub_efiemu_mmap_iterate (grub_memory_hook_t hook); int grub_efiemu_sizeof_uintn_t (void); grub_err_t grub_efiemu_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper); @@ -272,8 +265,7 @@ grub_err_t grub_efiemu_write_value (void * addr, grub_uint32_t value, int minus_handle, int ptv_needed, int size); grub_err_t grub_efiemu_write_sym_markers (void); grub_err_t grub_efiemu_pnvram (void); -grub_err_t grub_efiemu_prepare (void); -char *grub_efiemu_get_default_core_name (void); +const char *grub_efiemu_get_default_core_name (void); void grub_efiemu_pnvram_cmd_unregister (void); grub_err_t grub_efiemu_autocore (void); grub_err_t grub_efiemu_crc32 (void); diff --git a/include/grub/elf.h b/include/grub/elf.h index b9401f241..a02b90238 100644 --- a/include/grub/elf.h +++ b/include/grub/elf.h @@ -2348,6 +2348,8 @@ typedef Elf32_Xword Elf_Xword; #define ELF_ST_BIND(val) ELF32_ST_BIND(val) #define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +#define ELF_ST_INFO(a,b) ELF32_ST_INFO(a,b) + #define ELF_R_SYM(val) ELF32_R_SYM(val) #define ELF_R_TYPE(val) ELF32_R_TYPE(val) #define ELF_R_INFO(sym, type) ELF32_R_INFO(sym, type) @@ -2369,6 +2371,7 @@ typedef Elf64_Xword Elf_Xword; #define ELF_ST_BIND(val) ELF64_ST_BIND (val) #define ELF_ST_TYPE(val) ELF64_ST_TYPE (val) +#define ELF_ST_INFO(a,b) ELF64_ST_INFO(a,b) #define ELF_R_SYM(val) ELF64_R_SYM(val) #define ELF_R_TYPE(val) ELF64_R_TYPE(val) #define ELF_R_INFO(sym, type) ELF64_R_INFO(sym, type) diff --git a/include/grub/elfload.h b/include/grub/elfload.h index 83fb9128a..579656f23 100644 --- a/include/grub/elfload.h +++ b/include/grub/elfload.h @@ -46,12 +46,12 @@ grub_elf_t grub_elf_file (grub_file_t); grub_err_t grub_elf_close (grub_elf_t); int grub_elf_is_elf32 (grub_elf_t); -grub_size_t grub_elf32_size (grub_elf_t, Elf32_Addr *); +grub_size_t grub_elf32_size (grub_elf_t, Elf32_Addr *, grub_uint32_t *); grub_err_t grub_elf32_load (grub_elf_t, grub_elf32_load_hook_t, grub_addr_t *, grub_size_t *); int grub_elf_is_elf64 (grub_elf_t); -grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *); +grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *, grub_uint64_t *); grub_err_t grub_elf64_load (grub_elf_t, grub_elf64_load_hook_t, grub_addr_t *, grub_size_t *); grub_err_t diff --git a/include/grub/emu/export.h b/include/grub/emu/export.h new file mode 100644 index 000000000..1e2f0432b --- /dev/null +++ b/include/grub/emu/export.h @@ -0,0 +1,6 @@ +void EXPORT_FUNC (open64) (void); +void EXPORT_FUNC (close) (void); +void EXPORT_FUNC (read) (void); +void EXPORT_FUNC (write) (void); +void EXPORT_FUNC (ioctl) (void); + diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h index 581ea8056..6921e567c 100644 --- a/include/grub/emu/getroot.h +++ b/include/grub/emu/getroot.h @@ -25,6 +25,8 @@ enum grub_dev_abstraction_types { GRUB_DEV_ABSTRACTION_NONE, GRUB_DEV_ABSTRACTION_LVM, GRUB_DEV_ABSTRACTION_RAID, + GRUB_DEV_ABSTRACTION_LUKS, + GRUB_DEV_ABSTRACTION_GELI, }; char *grub_find_device (const char *dir, dev_t dev); @@ -34,5 +36,12 @@ char *grub_util_get_grub_dev (const char *os_dev); char *grub_make_system_path_relative_to_its_root (const char *path); const char *grub_util_check_block_device (const char *blk_dev); const char *grub_util_check_char_device (const char *blk_dev); +#ifdef __linux__ +char **grub_util_raid_getmembers (const char *name, int bootable); +#endif +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) +void grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, + char **name_out); +#endif #endif /* ! GRUB_UTIL_GETROOT_HEADER */ diff --git a/include/grub/emu/hostdisk.h b/include/grub/emu/hostdisk.h index d8cc02e14..e8df694a6 100644 --- a/include/grub/emu/hostdisk.h +++ b/include/grub/emu/hostdisk.h @@ -21,6 +21,8 @@ #define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1 #include +#include +#include void grub_util_biosdisk_init (const char *dev_map); void grub_util_biosdisk_fini (void); @@ -28,5 +30,35 @@ char *grub_util_biosdisk_get_grub_dev (const char *os_dev); const char *grub_util_biosdisk_get_osdev (grub_disk_t disk); int grub_util_biosdisk_is_present (const char *name); int grub_util_biosdisk_is_floppy (grub_disk_t disk); +const char * +grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk); +grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk); +void grub_util_pull_device (const char *osname); +grub_err_t +grub_util_fd_seek (int fd, const char *name, grub_uint64_t sector); +ssize_t grub_util_fd_read (int fd, char *buf, size_t len); +ssize_t grub_util_fd_write (int fd, const char *buf, size_t len); +grub_err_t +grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat); +void grub_util_cryptodisk_print_uuid (grub_disk_t disk); +char * +grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start); +int +grub_util_is_ldm (grub_disk_t disk); +#ifdef GRUB_UTIL +grub_err_t +grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors); +#endif +grub_disk_addr_t +grub_hostdisk_find_partition_start (const char *dev); +const char * +grub_hostdisk_os_dev_to_grub_drive (const char *os_dev, int add); + +#if !defined(__MINGW32__) +grub_uint64_t +grub_util_get_fd_sectors (int fd, unsigned *log_secsize); +#endif #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index 47a80d3d7..a9365f6a1 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -24,7 +24,6 @@ #include #include -#include #ifdef __CYGWIN__ # include @@ -55,11 +54,13 @@ void grub_find_zpool_from_dir (const char *dir, char *grub_make_system_path_relative_to_its_root (const char *path) __attribute__ ((warn_unused_result)); +int +grub_util_device_is_mapped (const char *dev); void * EXPORT_FUNC(xmalloc) (grub_size_t size) __attribute__ ((warn_unused_result)); void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size) __attribute__ ((warn_unused_result)); char * EXPORT_FUNC(xstrdup) (const char *str) __attribute__ ((warn_unused_result)); -char * EXPORT_FUNC(xasprintf) (const char *fmt, ...) __attribute__ ((warn_unused_result)); +char * EXPORT_FUNC(xasprintf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((warn_unused_result)); void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...); void EXPORT_FUNC(grub_util_info) (const char *fmt, ...); @@ -79,6 +80,6 @@ extern char * canonicalize_file_name (const char *path); int grub_device_mapper_supported (void); #endif -libzfs_handle_t *grub_get_libzfs_handle (void); +char *grub_find_root_device_from_mountinfo (const char *dir, char **relroot); #endif /* GRUB_EMU_MISC_H */ diff --git a/include/grub/env.h b/include/grub/env.h index 6d1f0de6e..1ef11ecad 100644 --- a/include/grub/env.h +++ b/include/grub/env.h @@ -26,8 +26,8 @@ struct grub_env_var; -typedef char *(*grub_env_read_hook_t) (struct grub_env_var *var, - const char *val); +typedef const char *(*grub_env_read_hook_t) (struct grub_env_var *var, + const char *val); typedef char *(*grub_env_write_hook_t) (struct grub_env_var *var, const char *val); @@ -43,7 +43,7 @@ struct grub_env_var }; grub_err_t EXPORT_FUNC(grub_env_set) (const char *name, const char *val); -char *EXPORT_FUNC(grub_env_get) (const char *name); +const char *EXPORT_FUNC(grub_env_get) (const char *name); void EXPORT_FUNC(grub_env_unset) (const char *name); void EXPORT_FUNC(grub_env_iterate) (int (*func) (struct grub_env_var *var)); struct grub_env_var *EXPORT_FUNC(grub_env_find) (const char *name); @@ -53,7 +53,7 @@ grub_err_t EXPORT_FUNC(grub_register_variable_hook) (const char *name, grub_err_t grub_env_context_open (void); grub_err_t grub_env_context_close (void); -grub_err_t grub_env_export (const char *name); +grub_err_t EXPORT_FUNC(grub_env_export) (const char *name); void grub_env_unset_menu (void); grub_menu_t grub_env_get_menu (void); diff --git a/include/grub/err.h b/include/grub/err.h index 22334038d..3a75f5698 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -55,7 +55,18 @@ typedef enum GRUB_ERR_TIMEOUT, GRUB_ERR_IO, GRUB_ERR_ACCESS_DENIED, - GRUB_ERR_EXTRACTOR + GRUB_ERR_EXTRACTOR, + GRUB_ERR_NET_BAD_ADDRESS, + GRUB_ERR_NET_ROUTE_LOOP, + GRUB_ERR_NET_NO_ROUTE, + GRUB_ERR_NET_NO_ANSWER, + GRUB_ERR_WAIT, + GRUB_ERR_BUG, + GRUB_ERR_NET_PORT_CLOSED, + GRUB_ERR_NET_INVALID_RESPONSE, + GRUB_ERR_NET_UNKNOWN_ERROR, + GRUB_ERR_NET_PACKET_TOO_BIG, + GRUB_ERR_NET_NO_DOMAIN } grub_err_t; diff --git a/include/grub/fat.h b/include/grub/fat.h new file mode 100644 index 000000000..7d8e51ad5 --- /dev/null +++ b/include/grub/fat.h @@ -0,0 +1,70 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2001,2002,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 + * 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_FAT_H +#define GRUB_FAT_H 1 + +#include + +struct grub_fat_bpb +{ + grub_uint8_t jmp_boot[3]; + grub_uint8_t oem_name[8]; + grub_uint16_t bytes_per_sector; + grub_uint8_t sectors_per_cluster; + grub_uint16_t num_reserved_sectors; + grub_uint8_t num_fats; + grub_uint16_t num_root_entries; + grub_uint16_t num_total_sectors_16; + grub_uint8_t media; + grub_uint16_t sectors_per_fat_16; + grub_uint16_t sectors_per_track; + grub_uint16_t num_heads; + grub_uint32_t num_hidden_sectors; + grub_uint32_t num_total_sectors_32; + union + { + struct + { + grub_uint8_t num_ph_drive; + grub_uint8_t reserved; + grub_uint8_t boot_sig; + grub_uint32_t num_serial; + grub_uint8_t label[11]; + grub_uint8_t fstype[8]; + } __attribute__ ((packed)) fat12_or_fat16; + struct + { + grub_uint32_t sectors_per_fat_32; + grub_uint16_t extended_flags; + grub_uint16_t fs_version; + grub_uint32_t root_cluster; + grub_uint16_t fs_info; + grub_uint16_t backup_boot_sector; + grub_uint8_t reserved[12]; + grub_uint8_t num_ph_drive; + grub_uint8_t reserved1; + grub_uint8_t boot_sig; + grub_uint32_t num_serial; + grub_uint8_t label[11]; + grub_uint8_t fstype[8]; + } __attribute__ ((packed)) fat32; + } __attribute__ ((packed)) version_specific; +} __attribute__ ((packed)); + +#endif diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h index 065ccf9e3..f68db43b1 100644 --- a/include/grub/fbutil.h +++ b/include/grub/fbutil.h @@ -31,8 +31,17 @@ struct grub_video_fbblit_info grub_uint8_t *data; }; -grub_uint8_t *grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source, - unsigned int x, unsigned int y); +void *grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source, + unsigned int x, unsigned int y); + +/* Advance pointer by VAL bytes. If there is no unaligned access available, + VAL has to be divisible by size of pointed type. + */ +#ifdef GRUB_HAVE_UNALIGNED_ACCESS +#define GRUB_VIDEO_FB_ADVANCE_POINTER(ptr, val) ((ptr) = (typeof (ptr)) ((char *) ptr + val)) +#else +#define GRUB_VIDEO_FB_ADVANCE_POINTER(ptr, val) ((ptr) += (val) / sizeof (*(ptr))) +#endif grub_video_color_t get_pixel (struct grub_video_fbblit_info *source, unsigned int x, unsigned int y); diff --git a/include/grub/file.h b/include/grub/file.h index 72cd45468..e08ac2e26 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -39,8 +39,8 @@ 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; + /* If file is not easily seekable. Should be set by underlying layer. */ + int not_easily_seekable; /* Filesystem-specific data. */ void *data; @@ -56,9 +56,10 @@ typedef enum grub_file_filter_id { GRUB_FILE_FILTER_GZIO, GRUB_FILE_FILTER_XZIO, + GRUB_FILE_FILTER_LZOPIO, 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_COMPRESSION_LAST = GRUB_FILE_FILTER_LZOPIO, } grub_file_filter_id_t; typedef grub_file_t (*grub_file_filter_t) (grub_file_t in); @@ -123,7 +124,7 @@ grub_file_tell (const grub_file_t file) static inline int grub_file_seekable (const grub_file_t file) { - return !file->not_easly_seekable; + return !file->not_easily_seekable; } #endif /* ! GRUB_FILE_HEADER */ diff --git a/include/grub/fs.h b/include/grub/fs.h index 994eb8080..10374ed90 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -25,15 +25,19 @@ #include #include +/* For embedding types. */ +#ifdef GRUB_UTIL +#include +#endif /* Forward declaration is required, because of mutual reference. */ struct grub_file; struct grub_dirhook_info { - int dir:1; - int mtimeset:1; - int case_insensitive:1; + unsigned dir:1; + unsigned mtimeset:1; + unsigned case_insensitive:1; grub_int32_t mtime; }; @@ -42,6 +46,7 @@ struct grub_fs { /* The next filesystem. */ struct grub_fs *next; + struct grub_fs **prev; /* My name. */ const char *name; @@ -74,6 +79,11 @@ struct grub_fs grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf); #ifdef GRUB_UTIL + /* Determine sectors available for embedding. */ + grub_err_t (*embed) (grub_device_t device, unsigned int *nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors); + /* Whether this filesystem reserves first sector for DOS-style boot. */ int reserved_first_sector; #endif @@ -102,7 +112,7 @@ grub_fs_register (grub_fs_t fs) static inline void grub_fs_unregister (grub_fs_t fs) { - grub_list_remove (GRUB_AS_LIST_P (&grub_fs_list), GRUB_AS_LIST (fs)); + grub_list_remove (GRUB_AS_LIST (fs)); } #define FOR_FILESYSTEMS(var) FOR_LIST_ELEMENTS((var), (grub_fs_list)) diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h index c52a3c71c..f858e9d49 100644 --- a/include/grub/gfxmenu_view.h +++ b/include/grub/gfxmenu_view.h @@ -87,11 +87,11 @@ struct grub_gfxmenu_view grub_font_t title_font; grub_font_t message_font; char *terminal_font_name; - grub_gui_color_t title_color; - grub_gui_color_t message_color; - grub_gui_color_t message_bg_color; + grub_video_rgba_color_t title_color; + grub_video_rgba_color_t message_color; + grub_video_rgba_color_t message_bg_color; struct grub_video_bitmap *desktop_image; - grub_gui_color_t desktop_color; + grub_video_rgba_color_t desktop_color; grub_gfxmenu_box_t terminal_box; char *title_text; char *progress_message_text; diff --git a/include/grub/gfxwidgets.h b/include/grub/gfxwidgets.h index f9678bf9e..8ce666c5c 100644 --- a/include/grub/gfxwidgets.h +++ b/include/grub/gfxwidgets.h @@ -36,6 +36,7 @@ struct grub_gfxmenu_box void (*draw) (grub_gfxmenu_box_t self, int x, int y); void (*set_content_size) (grub_gfxmenu_box_t self, int width, int height); + int (*get_border_width) (grub_gfxmenu_box_t self); int (*get_left_pad) (grub_gfxmenu_box_t self); int (*get_top_pad) (grub_gfxmenu_box_t self); int (*get_right_pad) (grub_gfxmenu_box_t self); diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h index 428ceb166..83e3b3192 100644 --- a/include/grub/gpt_partition.h +++ b/include/grub/gpt_partition.h @@ -20,6 +20,7 @@ #define GRUB_GPT_PARTITION_HEADER 1 #include +#include struct grub_gpt_part_type { @@ -36,10 +37,19 @@ typedef struct grub_gpt_part_type grub_gpt_part_type_t; } #define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \ - { grub_cpu_to_le32 (0x21686148), grub_cpu_to_le16 (0x6449), grub_cpu_to_le16 (0x6e6f), \ + { grub_cpu_to_le32_compile_time (0x21686148), \ + grub_cpu_to_le16_compile_time (0x6449), \ + grub_cpu_to_le16_compile_time (0x6e6f), \ { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \ } +#define GRUB_GPT_PARTITION_TYPE_LDM \ + { grub_cpu_to_le32_compile_time (0x5808C8AAU),\ + grub_cpu_to_le16_compile_time (0x7E8F), \ + grub_cpu_to_le16_compile_time (0x42E0), \ + { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \ + } + struct grub_gpt_header { grub_uint8_t magic[8]; @@ -68,4 +78,10 @@ struct grub_gpt_partentry char name[72]; } __attribute__ ((packed)); +grub_err_t +grub_gpt_partition_map_iterate (grub_disk_t disk, + int (*hook) (grub_disk_t disk, + const grub_partition_t partition)); + + #endif /* ! GRUB_GPT_PARTITION_HEADER */ diff --git a/include/grub/gui.h b/include/grub/gui.h index 6e4a11cbe..ef0795cf7 100644 --- a/include/grub/gui.h +++ b/include/grub/gui.h @@ -31,16 +31,6 @@ status changes. */ #define GRUB_GFXMENU_TIMEOUT_COMPONENT_ID "__timeout__" -/* A representation of a color. Unlike grub_video_color_t, this - representation is independent of any video mode specifics. */ -typedef struct grub_gui_color -{ - grub_uint8_t red; - grub_uint8_t green; - grub_uint8_t blue; - grub_uint8_t alpha; -} grub_gui_color_t; - typedef struct grub_gui_component *grub_gui_component_t; typedef struct grub_gui_container *grub_gui_container_t; typedef struct grub_gui_list *grub_gui_list_t; @@ -242,23 +232,6 @@ grub_gui_set_viewport (const grub_video_rect_t *r, grub_video_rect_t *old) r->height); } -static __inline grub_gui_color_t -grub_gui_color_rgb (int r, int g, int b) -{ - grub_gui_color_t c; - c.red = r; - c.green = g; - c.blue = b; - c.alpha = 255; - return c; -} - -static __inline grub_video_color_t -grub_gui_map_color (grub_gui_color_t c) -{ - return grub_video_map_rgba (c.red, c.green, c.blue, c.alpha); -} - static inline int grub_video_have_common_points (const grub_video_rect_t *a, const grub_video_rect_t *b) diff --git a/include/grub/gui_string_util.h b/include/grub/gui_string_util.h index 1baa2eede..34f9a090d 100644 --- a/include/grub/gui_string_util.h +++ b/include/grub/gui_string_util.h @@ -30,8 +30,4 @@ char *grub_resolve_relative_path (const char *base, const char *path); char *grub_get_dirname (const char *file_path); -int grub_gui_get_named_color (const char *name, grub_gui_color_t *color); - -grub_err_t grub_gui_parse_color (const char *s, grub_gui_color_t *color); - #endif /* GRUB_GUI_STRING_UTIL_HEADER */ diff --git a/include/grub/hfs.h b/include/grub/hfs.h index d93b9a2c9..bf98610d9 100644 --- a/include/grub/hfs.h +++ b/include/grub/hfs.h @@ -39,7 +39,9 @@ typedef struct grub_hfs_extent grub_hfs_datarecord_t[3]; struct grub_hfs_sblock { grub_uint16_t magic; - grub_uint8_t unused[18]; + grub_uint32_t ctime; + grub_uint32_t mtime; + grub_uint8_t unused[10]; grub_uint32_t blksz; grub_uint8_t unused2[4]; grub_uint16_t first_block; diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h index 53008cdaf..c9e8b7dd2 100644 --- a/include/grub/i386/bsd.h +++ b/include/grub/i386/bsd.h @@ -94,8 +94,8 @@ grub_err_t grub_netbsd_load_elf_meta64 (struct grub_relocator *relocator, 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, + const void *data, grub_uint32_t len); +grub_err_t grub_freebsd_add_meta_module (const char *filename, const char *type, int argc, char **argv, grub_addr_t addr, grub_uint32_t size); diff --git a/include/grub/i386/coreboot/memory.h b/include/grub/i386/coreboot/memory.h index 0642280b9..2859b1d7c 100644 --- a/include/grub/i386/coreboot/memory.h +++ b/include/grub/i386/coreboot/memory.h @@ -28,6 +28,10 @@ #include #endif +#define GRUB_MEMORY_MACHINE_SCRATCH_ADDR 0x68000 +#define GRUB_MEMORY_MACHINE_SCRATCH_SEG (GRUB_MEMORY_MACHINE_SCRATCH_ADDR >> 4) +#define GRUB_MEMORY_MACHINE_SCRATCH_SIZE 0x10000 + #define GRUB_MEMORY_MACHINE_LOWER_USABLE 0x9fc00 /* 640 kiB - 1 kiB */ #define GRUB_MEMORY_MACHINE_UPPER_START 0x100000 /* 1 MiB */ diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index 63f99db62..6aa239103 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -41,7 +41,6 @@ #define GRUB_LINUX_VID_MODE_ASK 0xFFFD #define GRUB_LINUX_VID_MODE_VESA_START 0x0300 -#define GRUB_LINUX_SETUP_MOVE_SIZE 0x9100 #define GRUB_LINUX_CL_MAGIC 0xA33F #ifdef __x86_64__ @@ -68,7 +67,7 @@ #define GRUB_E820_RESERVED 2 #define GRUB_E820_ACPI 3 #define GRUB_E820_NVS 4 -#define GRUB_E820_EXEC_CODE 5 +#define GRUB_E820_BADRAM 5 #define GRUB_E820_MAX_ENTRY 128 @@ -79,9 +78,13 @@ struct grub_e820_mmap grub_uint32_t type; } __attribute__((packed)); -#define GRUB_VIDEO_LINUX_TYPE_TEXT 0x01 -#define GRUB_VIDEO_LINUX_TYPE_VESA 0x23 /* VESA VGA in graphic mode. */ -#define GRUB_VIDEO_LINUX_TYPE_SIMPLE 0x70 /* Linear framebuffer without any additional functions. */ +enum + { + GRUB_VIDEO_LINUX_TYPE_TEXT = 0x01, + GRUB_VIDEO_LINUX_TYPE_VESA = 0x23, /* VESA VGA in graphic mode. */ + GRUB_VIDEO_LINUX_TYPE_EFIFB = 0x70, /* EFI Framebuffer. */ + GRUB_VIDEO_LINUX_TYPE_SIMPLE = 0x70 /* Linear framebuffer without any additional functions. */ + }; /* For the Linux/i386 boot protocol version 2.03. */ struct linux_kernel_header @@ -126,6 +129,10 @@ struct linux_kernel_header grub_uint16_t pad1; /* Unused */ grub_uint32_t cmd_line_ptr; /* Points to the kernel command line */ grub_uint32_t initrd_addr_max; /* Highest address for initrd */ + grub_uint32_t kernel_alignment; + grub_uint8_t relocatable; + grub_uint8_t pad[3]; + grub_uint32_t cmdline_size; } __attribute__ ((packed)); /* Boot parameters for Linux based on 2.6.12. This is used by the setup diff --git a/include/grub/i386/netbsd_bootinfo.h b/include/grub/i386/netbsd_bootinfo.h index fd429a251..24e145b01 100644 --- a/include/grub/i386/netbsd_bootinfo.h +++ b/include/grub/i386/netbsd_bootinfo.h @@ -51,9 +51,11 @@ #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_BOOTWEDGE 10 #define NETBSD_BTINFO_MODULES 11 #define NETBSD_BTINFO_FRAMEBUF 12 @@ -83,6 +85,15 @@ struct grub_netbsd_btinfo_bootdisk grub_uint32_t partition; }; +struct grub_netbsd_btinfo_bootwedge { + grub_uint32_t biosdev; + grub_disk_addr_t startblk; + grub_uint64_t nblks; + grub_disk_addr_t matchblk; + grub_uint64_t matchnblks; + grub_uint8_t matchhash[16]; /* MD5 hash */ +} __attribute__ ((packed)); + struct grub_netbsd_btinfo_symtab { grub_uint32_t nsyms; diff --git a/include/grub/i386/pc/chainloader.h b/include/grub/i386/pc/chainloader.h index ca1da23a7..4776b181b 100644 --- a/include/grub/i386/pc/chainloader.h +++ b/include/grub/i386/pc/chainloader.h @@ -21,10 +21,7 @@ #include -/* Common function for normal and rescue mode commands. */ -typedef enum - { - GRUB_CHAINLOADER_FORCE = 0x1 - } grub_chainloader_flags_t; +void +grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl); #endif /* GRUB_CHAINLOADER_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/console.h b/include/grub/i386/pc/console.h index 1631a40ad..f752b9a25 100644 --- a/include/grub/i386/pc/console.h +++ b/include/grub/i386/pc/console.h @@ -26,16 +26,6 @@ #include #include -/* These are global to share code between C and asm. */ -int grub_console_getkey (struct grub_term_input *term); -grub_uint16_t grub_console_getxy (struct grub_term_output *term); -void grub_console_gotoxy (struct grub_term_output *term, - grub_uint8_t x, grub_uint8_t y); -void grub_console_cls (struct grub_term_output *term); -void grub_console_setcursor (struct grub_term_output *term, int on); -void grub_console_putchar (struct grub_term_output *term, - const struct grub_unicode_glyph *c); - /* Initialize the console system. */ void grub_console_init (void); diff --git a/include/grub/i386/pc/int.h b/include/grub/i386/pc/int.h index de23775d0..337752587 100644 --- a/include/grub/i386/pc/int.h +++ b/include/grub/i386/pc/int.h @@ -45,7 +45,12 @@ struct grub_bios_int_registers #define GRUB_CPU_INT_FLAGS_INTERRUPT 0x200 #define GRUB_CPU_INT_FLAGS_DIRECTION 0x400 #define GRUB_CPU_INT_FLAGS_OVERFLOW 0x800 +#ifdef GRUB_MACHINE_PCBIOS #define GRUB_CPU_INT_FLAGS_DEFAULT GRUB_CPU_INT_FLAGS_INTERRUPT +#else +#define GRUB_CPU_INT_FLAGS_DEFAULT 0 +#endif + void EXPORT_FUNC (grub_bios_interrupt) (grub_uint8_t intno, struct grub_bios_int_registers *regs); diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h index 1de37a5d5..4f05b74e3 100644 --- a/include/grub/i386/pc/kernel.h +++ b/include/grub/i386/pc/kernel.h @@ -29,20 +29,12 @@ #include #include -/* The size of kernel image. */ -extern grub_int32_t grub_kernel_image_size; - /* The total size of module images following the kernel. */ extern grub_int32_t grub_total_module_size; -/* The DOS partition number of the installed partition. */ -extern grub_int32_t grub_install_dos_part; +extern grub_uint32_t EXPORT_VAR(grub_boot_device); -/* The BSD partition number of the installed partition. */ -extern grub_int32_t grub_install_bsd_part; - -/* The boot BIOS drive number. */ -extern grub_uint8_t EXPORT_VAR(grub_boot_drive); +extern void (*EXPORT_VAR(grub_pc_net_config)) (char **device, char **path); #endif /* ! ASM_FILE */ diff --git a/include/grub/i386/pc/pxe.h b/include/grub/i386/pc/pxe.h index 62ece21b0..925631d04 100644 --- a/include/grub/i386/pc/pxe.h +++ b/include/grub/i386/pc/pxe.h @@ -152,18 +152,13 @@ #define GRUB_PXE_BOOTP_BCAST 0x8000 #if 1 -#define GRUB_PXE_BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size. */ +#define GRUB_PXE_BOOTP_SIZE (1024 + 236) /* DHCP extended vendor field size. */ #else -#define GRUB_PXE_BOOTP_DHCPVEND 312 /* DHCP standard vendor field size. */ +#define GRUB_PXE_BOOTP_SIZE (312 + 236) /* DHCP standard vendor field size. */ #endif -#define GRUB_PXE_MIN_BLKSIZE 512 -#define GRUB_PXE_MAX_BLKSIZE 1432 - #define GRUB_PXE_TFTP_PORT 69 -#define GRUB_PXE_VM_RFC1048 0x63825363L - #define GRUB_PXE_ERR_LEN 0xFFFFFFFF #ifndef ASM_FILE @@ -214,38 +209,6 @@ struct grub_pxenv_get_cached_info grub_uint16_t buffer_limit; } __attribute__ ((packed)); -#define GRUB_PXE_MAC_ADDR_LEN 16 - -typedef grub_uint8_t grub_pxe_mac_addr_t[GRUB_PXE_MAC_ADDR_LEN]; - -struct grub_pxenv_boot_player -{ - grub_uint8_t opcode; - grub_uint8_t hw_type; /* hardware type. */ - grub_uint8_t hw_len; /* hardware addr len. */ - grub_uint8_t gate_hops; /* zero it. */ - grub_uint32_t ident; /* random number chosen by client. */ - grub_uint16_t seconds; /* seconds since did initial bootstrap. */ - grub_uint16_t flags; - grub_uint32_t client_ip; - grub_uint32_t your_ip; - grub_uint32_t server_ip; - grub_uint32_t gateway_ip; - grub_pxe_mac_addr_t mac_addr; - grub_uint8_t server_name[64]; - grub_uint8_t boot_file[128]; - union - { - grub_uint8_t d[GRUB_PXE_BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options. */ - struct - { - grub_uint32_t magic; /* DHCP magic cookie. */ - grub_uint32_t flags; /* bootp flags/opcodes. */ - grub_uint8_t padding[56]; - } v; - } vendor; -} __attribute__ ((packed)); - struct grub_pxenv_tftp_open { grub_uint16_t status; @@ -321,8 +284,6 @@ int EXPORT_FUNC(grub_pxe_call) (int func, void * data, grub_uint32_t pxe_rm_entr extern struct grub_pxe_bangpxe *grub_pxe_pxenv; -void grub_pxe_unload (void); - #endif #endif /* GRUB_CPU_PXE_H */ diff --git a/include/grub/i386/pc/vbe.h b/include/grub/i386/pc/vbe.h index fba3ee642..09ad7eb64 100644 --- a/include/grub/i386/pc/vbe.h +++ b/include/grub/i386/pc/vbe.h @@ -19,6 +19,8 @@ #ifndef GRUB_VBE_MACHINE_HEADER #define GRUB_VBE_MACHINE_HEADER 1 +#include + /* Default video mode to be used. */ #define GRUB_VBE_DEFAULT_VIDEO_MODE 0x101 @@ -169,6 +171,21 @@ struct grub_vbe_palette_data grub_uint8_t alignment; } __attribute__ ((packed)); +struct grub_vbe_flat_panel_info +{ + grub_uint16_t horizontal_size; + grub_uint16_t vertical_size; + grub_uint16_t panel_type; + grub_uint8_t red_bpp; + grub_uint8_t green_bpp; + grub_uint8_t blue_bpp; + grub_uint8_t reserved_bpp; + grub_uint32_t reserved_offscreen_mem_size; + grub_vbe_farptr_t reserved_offscreen_mem_ptr; + + grub_uint8_t reserved[14]; +} __attribute__ ((packed)); + /* Prototypes for helper functions. */ /* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status. */ grub_vbe_status_t diff --git a/include/grub/i386/qemu/kernel.h b/include/grub/i386/qemu/kernel.h index df06e6731..f34206b3a 100644 --- a/include/grub/i386/qemu/kernel.h +++ b/include/grub/i386/qemu/kernel.h @@ -28,12 +28,6 @@ extern grub_addr_t grub_core_entry_addr; -/* The size of kernel image. */ -extern grub_int32_t grub_kernel_image_size; - -/* The total size of module images following the kernel. */ -extern grub_int32_t grub_total_module_size; - void grub_qemu_init_cirrus (void); #endif /* ! ASM_FILE */ diff --git a/include/grub/i386/qemu/memory.h b/include/grub/i386/qemu/memory.h index 2003e4934..f152cd782 100644 --- a/include/grub/i386/qemu/memory.h +++ b/include/grub/i386/qemu/memory.h @@ -33,10 +33,4 @@ #define GRUB_MEMORY_MACHINE_UPPER_START 0x100000 /* 1 MiB */ #define GRUB_MEMORY_MACHINE_LOWER_SIZE GRUB_MEMORY_MACHINE_UPPER_START -#ifndef ASM_FILE - -void grub_machine_mmap_init (void); - -#endif - #endif /* ! _GRUB_MEMORY_MACHINE_HEADER */ diff --git a/include/grub/mips/yeeloong/serial.h b/include/grub/i386/reboot.h similarity index 70% rename from include/grub/mips/yeeloong/serial.h rename to include/grub/i386/reboot.h index ebe3638a1..c2716f3fa 100644 --- a/include/grub/mips/yeeloong/serial.h +++ b/include/grub/i386/reboot.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 2011 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,15 +16,13 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_SERIAL_HEADER -#define GRUB_MACHINE_SERIAL_HEADER 1 - -#define GRUB_MACHINE_SERIAL_DIVISOR_115200 2 -#define GRUB_MACHINE_SERIAL_PORT 0xbff003f8 +#ifndef GRUB_REBOOT_H +#define GRUB_REBOOT_H 1 #ifndef ASM_FILE -#define GRUB_MACHINE_SERIAL_PORTS { GRUB_MACHINE_SERIAL_PORT } -#else + +extern grub_uint8_t grub_reboot_end[], grub_reboot_start[]; + #endif -#endif +#endif diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h index 6ff5c6631..b2fe900b6 100644 --- a/include/grub/i386/relocator.h +++ b/include/grub/i386/relocator.h @@ -46,7 +46,10 @@ struct grub_relocator16_state grub_uint16_t ss; grub_uint16_t sp; grub_uint16_t ip; + grub_uint32_t ebx; grub_uint32_t edx; + grub_uint32_t esi; + int a20; }; struct grub_relocator64_state diff --git a/include/grub/i386/types.h b/include/grub/i386/types.h index 0ac64734c..c20063f31 100644 --- a/include/grub/i386/types.h +++ b/include/grub/i386/types.h @@ -28,4 +28,6 @@ /* i386 is little-endian. */ #undef GRUB_TARGET_WORDS_BIGENDIAN +#define GRUB_HAVE_UNALIGNED_ACCESS 1 + #endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h new file mode 100644 index 000000000..c9a61bb77 --- /dev/null +++ b/include/grub/ia64/efi/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/ia64/efi/time.h b/include/grub/ia64/efi/time.h new file mode 100644 index 000000000..897ce9c00 --- /dev/null +++ b/include/grub/ia64/efi/time.h @@ -0,0 +1,23 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +#ifndef GRUB_MACHINE_TIME_HEADER +#define GRUB_MACHINE_TIME_HEADER 1 + +#include + +#endif /* ! GRUB_MACHINE_TIME_HEADER */ diff --git a/include/grub/boot.h b/include/grub/ia64/kernel.h similarity index 69% rename from include/grub/boot.h rename to include/grub/ia64/kernel.h index 235774863..c5496a00b 100644 --- a/include/grub/boot.h +++ b/include/grub/ia64/kernel.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2007 Free Software Foundation, Inc. + * Copyright (C) 2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,12 +16,10 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_BOOT_HEADER -#define GRUB_BOOT_HEADER 1 +#ifndef GRUB_CPU_KERNEL_HEADER +#define GRUB_CPU_KERNEL_HEADER 1 -#define GRUB_BOOT_VERSION_MAJOR 4 -#define GRUB_BOOT_VERSION_MINOR 0 -#define GRUB_BOOT_VERSION ((GRUB_BOOT_VERSION_MINOR << 8) \ - | GRUB_BOOT_VERSION_MAJOR) +#define GRUB_MOD_ALIGN 0x1 +#define GRUB_MOD_GAP 0x0 -#endif /* ! GRUB_BOOT_HEADER */ +#endif /* ! GRUB_CPU_KERNEL_HEADER */ diff --git a/include/grub/ia64/setjmp.h b/include/grub/ia64/setjmp.h new file mode 100644 index 000000000..a71c9c56d --- /dev/null +++ b/include/grub/ia64/setjmp.h @@ -0,0 +1,28 @@ +/* Define the machine-dependent type `jmp_buf'. Linux/IA-64 version. + Copyright (C) 1999, 2000, 2008 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* User code must not depend on the internal representation of jmp_buf. */ + +#define _JBLEN 70 + +/* the __jmp_buf element type should be __float80 per ABI... */ +typedef long grub_jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128-bit alignment! */ + +int grub_setjmp (grub_jmp_buf env); +void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); diff --git a/include/grub/ia64/time.h b/include/grub/ia64/time.h new file mode 100644 index 000000000..03ee79fa4 --- /dev/null +++ b/include/grub/ia64/time.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#ifndef KERNEL_CPU_TIME_HEADER +#define KERNEL_CPU_TIME_HEADER 1 + +static __inline void +grub_cpu_idle (void) +{ + /* FIXME: not implemented */ +} + +#endif /* ! KERNEL_CPU_TIME_HEADER */ diff --git a/include/grub/ia64/types.h b/include/grub/ia64/types.h new file mode 100644 index 000000000..91a546dd2 --- /dev/null +++ b/include/grub/ia64/types.h @@ -0,0 +1,32 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_TYPES_CPU_HEADER +#define GRUB_TYPES_CPU_HEADER 1 + +/* The size of void *. */ +#define GRUB_TARGET_SIZEOF_VOID_P 8 + +/* The size of long. */ +#define GRUB_TARGET_SIZEOF_LONG 8 + +/* ia64 is little-endian (usually). */ +#undef GRUB_TARGET_WORDS_BIGENDIAN + + +#endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index 2592dd348..647374d0e 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -24,7 +24,6 @@ #include #include -/* Maps a device alias to a pathname. */ struct grub_ieee1275_devalias { char *name; @@ -65,6 +64,11 @@ struct grub_ieee1275_common_hdr typedef grub_uint32_t grub_ieee1275_ihandle_t; typedef grub_uint32_t grub_ieee1275_phandle_t; +extern void (*EXPORT_VAR(grub_ieee1275_net_config)) (const char *dev, + char **device, + char **path); + +/* Maps a device alias to a pathname. */ extern grub_ieee1275_phandle_t EXPORT_VAR(grub_ieee1275_chosen); extern grub_ieee1275_ihandle_t EXPORT_VAR(grub_ieee1275_mmu); extern int (* EXPORT_VAR(grub_ieee1275_entry_fn)) (void *); @@ -106,6 +110,12 @@ enum grub_ieee1275_flag /* OLPC / XO firmware has the cursor ON/OFF routines. */ GRUB_IEEE1275_FLAG_HAS_CURSORONOFF, + + /* Some PowerMacs claim to use 2 address cells but in fact use only 1. + Other PowerMacs claim to use only 1 and really do so. Always assume + 1 address cell is used on PowerMacs. + */ + GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS, }; extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); @@ -115,7 +125,7 @@ extern void EXPORT_FUNC(grub_ieee1275_set_flag) (enum grub_ieee1275_flag flag); void EXPORT_FUNC(grub_ieee1275_init) (void); -int EXPORT_FUNC(grub_ieee1275_finddevice) (char *name, +int EXPORT_FUNC(grub_ieee1275_finddevice) (const char *name, grub_ieee1275_phandle_t *phandlep); int EXPORT_FUNC(grub_ieee1275_get_property) (grub_ieee1275_phandle_t phandle, const char *property, void *buf, @@ -138,7 +148,7 @@ int EXPORT_FUNC(grub_ieee1275_instance_to_path) (grub_ieee1275_ihandle_t ihandle, char *path, grub_size_t len, grub_ssize_t *actual); int EXPORT_FUNC(grub_ieee1275_write) (grub_ieee1275_ihandle_t ihandle, - void *buffer, grub_size_t len, + const void *buffer, grub_size_t len, grub_ssize_t *actualp); int EXPORT_FUNC(grub_ieee1275_read) (grub_ieee1275_ihandle_t ihandle, void *buffer, grub_size_t len, @@ -163,7 +173,8 @@ int EXPORT_FUNC(grub_ieee1275_claim) (grub_addr_t addr, grub_size_t size, unsigned int align, grub_addr_t *result); int EXPORT_FUNC(grub_ieee1275_release) (grub_addr_t addr, grub_size_t size); int EXPORT_FUNC(grub_ieee1275_set_property) (grub_ieee1275_phandle_t phandle, - const char *propname, void *buf, + const char *propname, + const void *buf, grub_size_t size, grub_ssize_t *actual); int EXPORT_FUNC(grub_ieee1275_set_color) (grub_ieee1275_ihandle_t ihandle, @@ -173,10 +184,8 @@ int EXPORT_FUNC(grub_ieee1275_milliseconds) (grub_uint32_t *msecs); int EXPORT_FUNC(grub_devalias_iterate) (int (*hook) (struct grub_ieee1275_devalias *alias)); -int EXPORT_FUNC(grub_children_iterate) (char *devpath, +int EXPORT_FUNC(grub_children_iterate) (const char *devpath, int (*hook) (struct grub_ieee1275_devalias *alias)); -grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) - (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); int EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size); int @@ -185,11 +194,11 @@ EXPORT_FUNC(grub_ieee1275_map) (grub_addr_t phys, grub_addr_t virt, char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path); char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path); - int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook) (struct grub_ieee1275_devalias * alias)); - +char *EXPORT_FUNC(grub_ieee1275_get_aliasdevname) (const char *path); char *EXPORT_FUNC(grub_ieee1275_canonicalise_devname) (const char *path); +char *EXPORT_FUNC(grub_ieee1275_get_device_type) (const char *path); #endif /* ! GRUB_IEEE1275_HEADER */ diff --git a/include/grub/kernel.h b/include/grub/kernel.h index 2ecc73df4..4c8b29c8b 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -26,14 +26,15 @@ enum { OBJ_TYPE_ELF, OBJ_TYPE_MEMDISK, - OBJ_TYPE_CONFIG + OBJ_TYPE_CONFIG, + OBJ_TYPE_PREFIX }; /* The module header. */ struct grub_module_header { /* The type of object. */ - grub_uint8_t type; + grub_uint32_t type; /* The size of object (including this header). */ grub_uint32_t size; }; @@ -68,14 +69,20 @@ struct grub_module_info64 #define grub_module_info grub_module_info32 #endif -extern grub_addr_t grub_arch_modules_addr (void); +extern grub_addr_t EXPORT_VAR (grub_modbase); -extern void EXPORT_FUNC(grub_module_iterate) (int (*hook) (struct grub_module_header *)); +#define FOR_MODULES(var) for (\ + var = grub_modbase ? (struct grub_module_header *) \ + (grub_modbase + (((struct grub_module_info *) grub_modbase)->offset)) : 0;\ + var && (grub_addr_t) var \ + < (grub_modbase + (((struct grub_module_info *) grub_modbase)->size)); \ + var = (struct grub_module_header *) \ + ((grub_uint32_t *) var + ((struct grub_module_header *) var)->size / 4)) grub_addr_t grub_modules_get_end (void); /* The start point of the C code. */ -void grub_main (void); +void grub_main (void) __attribute__ ((noreturn)); /* The machine-specific initialization. This must initialize memory. */ void grub_machine_init (void); @@ -84,13 +91,12 @@ void grub_machine_init (void); void EXPORT_FUNC(grub_machine_fini) (void); /* The machine-specific prefix initialization. */ -void grub_machine_set_prefix (void); +void +grub_machine_get_bootlocation (char **device, char **path); /* Register all the exported symbols. This is automatically generated. */ void grub_register_exported_symbols (void); -#if ! defined (ASM_FILE) && !defined (GRUB_MACHINE_EMU) -extern char grub_prefix[]; -#endif +extern void (*EXPORT_VAR(grub_net_poll_cards_idle)) (void); #endif /* ! GRUB_KERNEL_HEADER */ diff --git a/include/grub/lib/arg.h b/include/grub/lib/arg.h index b61f6f30e..f81af85ee 100644 --- a/include/grub/lib/arg.h +++ b/include/grub/lib/arg.h @@ -53,8 +53,8 @@ struct grub_arg_option const char *longarg; int shortarg; int flags; - char *doc; - char *arg; + const char *doc; + const char *arg; grub_arg_type_t type; }; diff --git a/include/grub/lib/cmdline.h b/include/grub/lib/cmdline.h new file mode 100644 index 000000000..1fe8d0179 --- /dev/null +++ b/include/grub/lib/cmdline.h @@ -0,0 +1,31 @@ +/* cmdline.h - linux command line handling */ +/* + * 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_CMDLINE_HEADER +#define GRUB_CMDLINE_HEADER 1 + +#include + +#define LINUX_IMAGE "BOOT_IMAGE=" + +unsigned int grub_loader_cmdline_size (int argc, char *argv[]); +int grub_create_loader_cmdline (int argc, char *argv[], char *buf, + grub_size_t size); + +#endif /* ! GRUB_CMDLINE_HEADER */ diff --git a/include/grub/lib/crc.h b/include/grub/lib/crc.h new file mode 100644 index 000000000..c5098a8c3 --- /dev/null +++ b/include/grub/lib/crc.h @@ -0,0 +1,25 @@ +/* crc.h - prototypes for crc */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_CRC_H +#define GRUB_CRC_H 1 + +grub_uint32_t grub_getcrc32c (grub_uint32_t crc, const void *buf, int size); + +#endif /* ! GRUB_CRC_H */ diff --git a/include/grub/libgcc.h b/include/grub/libgcc.h index 8c4c19d8c..7a433dc68 100644 --- a/include/grub/libgcc.h +++ b/include/grub/libgcc.h @@ -39,8 +39,42 @@ void EXPORT_FUNC (__bswapsi2) (void); # ifdef HAVE___BSWAPDI2 void EXPORT_FUNC (__bswapdi2) (void); # endif +# ifdef HAVE___UDIVSI3 +void EXPORT_FUNC (__udivsi3) (void); +# endif +# ifdef HAVE___UMODSI3 +void EXPORT_FUNC (__umodsi3) (void); +# endif +# ifdef HAVE___UMODDI3 +void EXPORT_FUNC (__umoddi3) (void); +# endif +# ifdef HAVE___UDIVDI3 +void EXPORT_FUNC (__udivdi3) (void); +# endif +# ifdef HAVE___MODDI3 +void EXPORT_FUNC (__moddi3) (void); +# endif +# ifdef HAVE___DIVDI3 +void EXPORT_FUNC (__divdi3) (void); +# endif +# ifdef HAVE___DIVSI3 +void EXPORT_FUNC (__divsi3) (void); +# endif +# ifdef HAVE___MODSI3 +void EXPORT_FUNC (__modsi3) (void); +# endif +# ifdef HAVE___CTZDI2 +void EXPORT_FUNC (__ctzdi2) (void); +# endif +# ifdef HAVE___CTZSI2 +void EXPORT_FUNC (__ctzsi2) (void); +# endif #endif +# ifdef HAVE___IA64_TRAMPOLINE +void EXPORT_FUNC (__ia64_trampoline) (void); +# endif + #ifdef HAVE___TRAMPOLINE_SETUP void EXPORT_FUNC (__trampoline_setup) (void); #endif diff --git a/include/grub/list.h b/include/grub/list.h index 75353010c..54f528a05 100644 --- a/include/grub/list.h +++ b/include/grub/list.h @@ -27,11 +27,30 @@ struct grub_list { struct grub_list *next; + struct grub_list **prev; }; typedef struct grub_list *grub_list_t; -void EXPORT_FUNC(grub_list_push) (grub_list_t *head, grub_list_t item); -void EXPORT_FUNC(grub_list_remove) (grub_list_t *head, grub_list_t item); +static inline void +grub_list_push (grub_list_t *head, grub_list_t item) +{ + item->prev = head; + if (*head) + (*head)->prev = &item->next; + item->next = *head; + *head = item; +} + +static inline void +grub_list_remove (grub_list_t item) +{ + if (item->prev) + *item->prev = item->next; + if (item->next) + item->next->prev = item->prev; + item->next = 0; + item->prev = 0; +} #define FOR_LIST_ELEMENTS(var, list) for ((var) = (list); (var); (var) = (var)->next) @@ -53,16 +72,17 @@ grub_bad_type_cast_real (int line, const char *file) ((char *) &(ptr)->field == (char *) &((type) (ptr))->field) #define GRUB_AS_LIST(ptr) \ - (GRUB_FIELD_MATCH (ptr, grub_list_t, next) ? \ - (grub_list_t) ptr : grub_bad_type_cast ()) + (GRUB_FIELD_MATCH (ptr, grub_list_t, next) && GRUB_FIELD_MATCH (ptr, grub_list_t, prev) ? \ + (grub_list_t) ptr : (grub_list_t) grub_bad_type_cast ()) #define GRUB_AS_LIST_P(pptr) \ - (GRUB_FIELD_MATCH (*pptr, grub_list_t, next) ? \ - (grub_list_t *) (void *) pptr : grub_bad_type_cast ()) + (GRUB_FIELD_MATCH (*pptr, grub_list_t, next) && GRUB_FIELD_MATCH (*pptr, grub_list_t, prev) ? \ + (grub_list_t *) (void *) pptr : (grub_list_t *) grub_bad_type_cast ()) struct grub_named_list { struct grub_named_list *next; + struct grub_named_list **prev; char *name; }; typedef struct grub_named_list *grub_named_list_t; @@ -71,14 +91,16 @@ void * EXPORT_FUNC(grub_named_list_find) (grub_named_list_t head, const char *name); #define GRUB_AS_NAMED_LIST(ptr) \ - ((GRUB_FIELD_MATCH (ptr, grub_named_list_t, next) && \ - GRUB_FIELD_MATCH (ptr, grub_named_list_t, name))? \ - (grub_named_list_t) ptr : grub_bad_type_cast ()) + ((GRUB_FIELD_MATCH (ptr, grub_named_list_t, next) \ + && GRUB_FIELD_MATCH (ptr, grub_named_list_t, prev) \ + && GRUB_FIELD_MATCH (ptr, grub_named_list_t, name))? \ + (grub_named_list_t) ptr : (grub_named_list_t) grub_bad_type_cast ()) #define GRUB_AS_NAMED_LIST_P(pptr) \ - ((GRUB_FIELD_MATCH (*pptr, grub_named_list_t, next) && \ - GRUB_FIELD_MATCH (*pptr, grub_named_list_t, name))? \ - (grub_named_list_t *) (void *) pptr : grub_bad_type_cast ()) + ((GRUB_FIELD_MATCH (*pptr, grub_named_list_t, next) \ + && GRUB_FIELD_MATCH (*pptr, grub_named_list_t, prev) \ + && GRUB_FIELD_MATCH (*pptr, grub_named_list_t, name))? \ + (grub_named_list_t *) (void *) pptr : (grub_named_list_t *) grub_bad_type_cast ()) #define GRUB_PRIO_LIST_PRIO_MASK 0xff #define GRUB_PRIO_LIST_FLAG_ACTIVE 0x100 @@ -86,6 +108,7 @@ void * EXPORT_FUNC(grub_named_list_find) (grub_named_list_t head, struct grub_prio_list { struct grub_prio_list *next; + struct grub_prio_list **prev; char *name; int prio; }; @@ -95,23 +118,27 @@ void EXPORT_FUNC(grub_prio_list_insert) (grub_prio_list_t *head, grub_prio_list_t item); static inline void -grub_prio_list_remove (grub_prio_list_t *head, grub_prio_list_t item) +grub_prio_list_remove (grub_prio_list_t item) { if ((item->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) && (item->next)) item->next->prio |= GRUB_PRIO_LIST_FLAG_ACTIVE; - grub_list_remove (GRUB_AS_LIST_P (head), GRUB_AS_LIST (item)); + grub_list_remove (GRUB_AS_LIST (item)); } #define GRUB_AS_PRIO_LIST(ptr) \ - ((GRUB_FIELD_MATCH (ptr, grub_prio_list_t, next) && \ - GRUB_FIELD_MATCH (ptr, grub_prio_list_t, name) && \ - GRUB_FIELD_MATCH (ptr, grub_prio_list_t, prio))? \ - (grub_prio_list_t) ptr : grub_bad_type_cast ()) + ((GRUB_FIELD_MATCH (ptr, grub_prio_list_t, next) \ + && GRUB_FIELD_MATCH (ptr, grub_prio_list_t, prev) \ + && GRUB_FIELD_MATCH (ptr, grub_prio_list_t, name) \ + && GRUB_FIELD_MATCH (ptr, grub_prio_list_t, prio))? \ + (grub_prio_list_t) ptr \ + : (grub_prio_list_t) grub_bad_type_cast ()) #define GRUB_AS_PRIO_LIST_P(pptr) \ - ((GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, next) && \ - GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, name) && \ - GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, prio))? \ - (grub_prio_list_t *) (void *) pptr : grub_bad_type_cast ()) + ((GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, next) \ + && GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, prev) \ + && GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, name) \ + && GRUB_FIELD_MATCH (*pptr, grub_prio_list_t, prio)) ? \ + (grub_prio_list_t *) (void *) pptr \ + : (grub_prio_list_t *) grub_bad_type_cast ()) #endif /* ! GRUB_LIST_HEADER */ diff --git a/include/grub/loader.h b/include/grub/loader.h index c71e8dd10..1d70ef049 100644 --- a/include/grub/loader.h +++ b/include/grub/loader.h @@ -56,11 +56,13 @@ typedef enum { } grub_loader_preboot_hook_prio_t; /* Register a preboot hook. */ -void *EXPORT_FUNC(grub_loader_register_preboot_hook) (grub_err_t (*preboot_func) (int noret), - grub_err_t (*preboot_rest_func) (void), - grub_loader_preboot_hook_prio_t prio); +struct grub_preboot; + +struct grub_preboot *EXPORT_FUNC(grub_loader_register_preboot_hook) (grub_err_t (*preboot_func) (int noret), + grub_err_t (*preboot_rest_func) (void), + grub_loader_preboot_hook_prio_t prio); /* Unregister given preboot hook. */ -void grub_loader_unregister_preboot_hook (void *hnd); +void EXPORT_FUNC (grub_loader_unregister_preboot_hook) (struct grub_preboot *hnd); #endif /* ! GRUB_LOADER_HEADER */ diff --git a/include/grub/lvm.h b/include/grub/lvm.h index a4bf3b288..2d4ab6ff3 100644 --- a/include/grub/lvm.h +++ b/include/grub/lvm.h @@ -21,50 +21,11 @@ #define GRUB_LVM_H 1 #include +#include /* Length of ID string, excluding terminating zero. */ #define GRUB_LVM_ID_STRLEN 38 -struct grub_lvm_vg { - char id[GRUB_LVM_ID_STRLEN+1]; - char *name; - int extent_size; - struct grub_lvm_pv *pvs; - struct grub_lvm_lv *lvs; - struct grub_lvm_vg *next; -}; - -struct grub_lvm_pv { - char id[GRUB_LVM_ID_STRLEN+1]; - char *name; - grub_disk_t disk; - int start; /* Sector number where the data area starts. */ - struct grub_lvm_pv *next; -}; - -struct grub_lvm_lv { - char *name; - unsigned int number; - unsigned int segment_count; - grub_uint64_t size; - struct grub_lvm_segment *segments; /* Pointer to segment_count segments. */ - struct grub_lvm_vg *vg; - struct grub_lvm_lv *next; -}; - -struct grub_lvm_segment { - unsigned int start_extent; - unsigned int extent_count; - unsigned int stripe_count; - unsigned int stripe_size; - struct grub_lvm_stripe *stripes; /* Pointer to stripe_count stripes. */ -}; - -struct grub_lvm_stripe { - int start; - struct grub_lvm_pv *pv; -}; - #define GRUB_LVM_LABEL_SIZE GRUB_DISK_SECTOR_SIZE #define GRUB_LVM_LABEL_SCAN_SECTORS 4L diff --git a/include/grub/menu.h b/include/grub/menu.h index 5ff356beb..1f23a2363 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -94,11 +94,6 @@ typedef struct grub_menu_execute_callback grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no); int grub_menu_get_timeout (void); void grub_menu_set_timeout (int timeout); -void grub_menu_execute_entry (grub_menu_entry_t entry); -void grub_menu_execute_with_fallback (grub_menu_t menu, - grub_menu_entry_t entry, - grub_menu_execute_callback_t callback, - void *callback_data); void grub_menu_entry_run (grub_menu_entry_t entry); int grub_menu_get_default_entry_index (grub_menu_t menu); diff --git a/include/grub/mips/arc/kernel.h b/include/grub/mips/arc/kernel.h new file mode 100644 index 000000000..50694866b --- /dev/null +++ b/include/grub/mips/arc/kernel.h @@ -0,0 +1,2 @@ +#include + diff --git a/include/grub/mips/arc/memory.h b/include/grub/mips/arc/memory.h new file mode 100644 index 000000000..b960d2a37 --- /dev/null +++ b/include/grub/mips/arc/memory.h @@ -0,0 +1,42 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MEMORY_MACHINE_HEADER +#define GRUB_MEMORY_MACHINE_HEADER 1 + +#define GRUB_MACHINE_MEMORY_STACK_HIGH 0x8bfffff0 + +#ifndef ASM_FILE + +static inline grub_err_t +grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + int type __attribute__ ((unused)), + int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} +static inline grub_err_t +grub_machine_mmap_unregister (int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} + +#endif + +#endif diff --git a/include/grub/mips/qemu-mips/loader.h b/include/grub/mips/arc/time.h similarity index 100% rename from include/grub/mips/qemu-mips/loader.h rename to include/grub/mips/arc/time.h diff --git a/include/grub/mips/kernel.h b/include/grub/mips/kernel.h new file mode 100644 index 000000000..07b08848d --- /dev/null +++ b/include/grub/mips/kernel.h @@ -0,0 +1,24 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KERNEL_CPU_HEADER +#define GRUB_KERNEL_CPU_HEADER 1 + +#include + +#endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/include/grub/mips/loongson.h b/include/grub/mips/loongson.h index 6cb1178d5..e6f0241f2 100644 --- a/include/grub/mips/loongson.h +++ b/include/grub/mips/loongson.h @@ -19,11 +19,7 @@ #ifndef GRUB_LOONGSON_CPU_HEADER #define GRUB_LOONGSON_CPU_HEADER 1 -#ifdef ASM_FILE -#define GRUB_CPU_REGISTER_WRAP(x) x -#else -#define GRUB_CPU_REGISTER_WRAP(x) #x -#endif +#include #define GRUB_CPU_LOONGSON_FLASH_START 0xbfc00000 #define GRUB_CPU_LOONGSON_FLASH_TLB_REFILL 0xbfc00200 @@ -68,9 +64,9 @@ #define GRUB_CPU_LOONGSON_SECONDARY_CACHE_LOG_SIZE 19 #define GRUB_CPU_LOONGSON_COP0_BADVADDR GRUB_CPU_REGISTER_WRAP($8) -#define GRUB_CPU_LOONGSON_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP($9) #define GRUB_CPU_LOONGSON_COP0_CAUSE GRUB_CPU_REGISTER_WRAP($13) #define GRUB_CPU_LOONGSON_COP0_EPC GRUB_CPU_REGISTER_WRAP($14) +#define GRUB_CPU_LOONGSON_COP0_PRID GRUB_CPU_REGISTER_WRAP($15) #define GRUB_CPU_LOONGSON_COP0_CACHE_TAGLO GRUB_CPU_REGISTER_WRAP($28) #define GRUB_CPU_LOONGSON_COP0_CACHE_TAGHI GRUB_CPU_REGISTER_WRAP($29) @@ -85,6 +81,6 @@ #define GRUB_CPU_LOONGSON_PCI_HIT1_SEL_HI 0xbfe00154 #define GRUB_CPU_LOONGSON_GPIOCFG 0xbfe00120 -#define GRUB_CPU_LOONGSON_SHUTDOWN_GPIO 1 +#define GRUB_CPU_YEELOONG_SHUTDOWN_GPIO 1 #endif diff --git a/include/grub/mips/yeeloong/at_keyboard.h b/include/grub/mips/loongson/at_keyboard.h similarity index 100% rename from include/grub/mips/yeeloong/at_keyboard.h rename to include/grub/mips/loongson/at_keyboard.h diff --git a/include/grub/mips/yeeloong/cmos.h b/include/grub/mips/loongson/cmos.h similarity index 100% rename from include/grub/mips/yeeloong/cmos.h rename to include/grub/mips/loongson/cmos.h diff --git a/include/grub/mips/yeeloong/ec.h b/include/grub/mips/loongson/ec.h similarity index 95% rename from include/grub/mips/yeeloong/ec.h rename to include/grub/mips/loongson/ec.h index 62d1d33d9..3f8ff9931 100644 --- a/include/grub/mips/yeeloong/ec.h +++ b/include/grub/mips/loongson/ec.h @@ -19,6 +19,10 @@ #ifndef GRUB_EC_MACHINE_HEADER #define GRUB_EC_MACHINE_HEADER 1 +#include +#include +#include + #define GRUB_MACHINE_EC_MAGIC_PORT1 0x381 #define GRUB_MACHINE_EC_MAGIC_PORT2 0x382 #define GRUB_MACHINE_EC_DATA_PORT 0x383 diff --git a/include/grub/mips/yeeloong/kernel.h b/include/grub/mips/loongson/kernel.h similarity index 80% rename from include/grub/mips/yeeloong/kernel.h rename to include/grub/mips/loongson/kernel.h index 15cf9f9fd..5e6e6fdfb 100644 --- a/include/grub/mips/yeeloong/kernel.h +++ b/include/grub/mips/loongson/kernel.h @@ -20,11 +20,15 @@ #define GRUB_KERNEL_MACHINE_HEADER 1 #include +#include + +#define GRUB_ARCH_MACHINE_YEELOONG 0 +#define GRUB_ARCH_MACHINE_FULOONG2F 1 +#define GRUB_ARCH_MACHINE_FULOONG2E 2 #ifndef ASM_FILE -void EXPORT_FUNC (grub_reboot) (void) __attribute__ ((noreturn)); -void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn)); +extern grub_uint32_t EXPORT_VAR (grub_arch_machine) __attribute__ ((section(".text"))); #endif diff --git a/include/grub/mips/yeeloong/memory.h b/include/grub/mips/loongson/memory.h similarity index 60% rename from include/grub/mips/yeeloong/memory.h rename to include/grub/mips/loongson/memory.h index 9d53b5e0e..aa41fa626 100644 --- a/include/grub/mips/yeeloong/memory.h +++ b/include/grub/mips/loongson/memory.h @@ -26,36 +26,9 @@ #endif #define GRUB_MACHINE_MEMORY_STACK_HIGH 0x801ffff0 -#define GRUB_ARCH_LOWMEMVSTART 0x80000000 -#define GRUB_ARCH_LOWMEMPSTART 0x00000000 -#define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000 -#define GRUB_ARCH_HIGHMEMPSTART 0x10000000 #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)); - static inline grub_err_t grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), grub_uint64_t size __attribute__ ((unused)), @@ -70,11 +43,8 @@ grub_machine_mmap_unregister (int handle __attribute__ ((unused))) return GRUB_ERR_NONE; } -grub_uint64_t grub_mmap_get_lower (void); -grub_uint64_t grub_mmap_get_upper (void); - -extern grub_uint32_t EXPORT_VAR (grub_arch_memsize); -extern grub_uint32_t EXPORT_VAR (grub_arch_highmemsize); +extern grub_uint32_t EXPORT_VAR (grub_arch_memsize) __attribute__ ((section(".text"))); +extern grub_uint32_t EXPORT_VAR (grub_arch_highmemsize) __attribute__ ((section(".text"))); #endif diff --git a/include/grub/mips/yeeloong/pci.h b/include/grub/mips/loongson/pci.h similarity index 90% rename from include/grub/mips/yeeloong/pci.h rename to include/grub/mips/loongson/pci.h index 199bac048..57c7dd1fc 100644 --- a/include/grub/mips/yeeloong/pci.h +++ b/include/grub/mips/loongson/pci.h @@ -24,10 +24,8 @@ #include #endif -#define GRUB_YEELOONG_OHCI_PCIID 0x00351033 -#define GRUB_YEELOONG_EHCI_PCIID 0x00e01033 -#define GRUB_YEELOONG_OHCI_GHOST_FUNCTION 4 -#define GRUB_YEELOONG_EHCI_GHOST_FUNCTION 5 +#define GRUB_LOONGSON_OHCI_PCIID 0x00351033 +#define GRUB_LOONGSON_EHCI_PCIID 0x00e01033 #define GRUB_PCI_NUM_BUS 1 #define GRUB_PCI_NUM_DEVICES 16 @@ -66,7 +64,7 @@ grub_pci_read (grub_pci_address_t addr) { GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); return *(volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONFSPACE - | (addr & 0x03ff)); + | (addr & 0x07ff)); } static inline grub_uint16_t @@ -74,7 +72,7 @@ grub_pci_read_word (grub_pci_address_t addr) { GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); return *(volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONFSPACE - | (addr & 0x03ff)); + | (addr & 0x07ff)); } static inline grub_uint8_t @@ -82,7 +80,7 @@ grub_pci_read_byte (grub_pci_address_t addr) { GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); return *(volatile grub_uint8_t *) (GRUB_MACHINE_PCI_CONFSPACE - | (addr & 0x03ff)); + | (addr & 0x07ff)); } static inline void @@ -90,7 +88,7 @@ grub_pci_write (grub_pci_address_t addr, grub_uint32_t data) { GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); *(volatile grub_uint32_t *) (GRUB_MACHINE_PCI_CONFSPACE - | (addr & 0x03ff)) = data; + | (addr & 0x07ff)) = data; } static inline void @@ -98,7 +96,7 @@ grub_pci_write_word (grub_pci_address_t addr, grub_uint16_t data) { GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); *(volatile grub_uint16_t *) (GRUB_MACHINE_PCI_CONFSPACE - | (addr & 0x03ff)) = data; + | (addr & 0x07ff)) = data; } static inline void @@ -106,7 +104,7 @@ grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) { GRUB_MACHINE_PCI_CONF_CTRL_REG = 1 << ((addr >> 11) & 0xf); *(volatile grub_uint8_t *) (GRUB_MACHINE_PCI_CONFSPACE - | (addr & 0x03ff)) = data; + | (addr & 0x07ff)) = data; } volatile void * diff --git a/include/grub/mips/loongson/serial.h b/include/grub/mips/loongson/serial.h new file mode 100644 index 000000000..45e6d8457 --- /dev/null +++ b/include/grub/mips/loongson/serial.h @@ -0,0 +1,33 @@ +/* + * 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_MACHINE_SERIAL_HEADER +#define GRUB_MACHINE_SERIAL_HEADER 1 + +#define GRUB_MACHINE_SERIAL_PORT0_DIVISOR_115200 2 +#define GRUB_MACHINE_SERIAL_PORT2_DIVISOR_115200 1 +#define GRUB_MACHINE_SERIAL_PORT0 0xbff003f8 +#define GRUB_MACHINE_SERIAL_PORT1 0xbfd003f8 +#define GRUB_MACHINE_SERIAL_PORT2 0xbfd002f8 + +#ifndef ASM_FILE +#define GRUB_MACHINE_SERIAL_PORTS { GRUB_MACHINE_SERIAL_PORT0, GRUB_MACHINE_SERIAL_PORT1, GRUB_MACHINE_SERIAL_PORT2 } +#else +#endif + +#endif diff --git a/include/grub/mips/qemu-mips/time.h b/include/grub/mips/loongson/time.h similarity index 84% rename from include/grub/mips/qemu-mips/time.h rename to include/grub/mips/loongson/time.h index a73f64dea..098573261 100644 --- a/include/grub/mips/qemu-mips/time.h +++ b/include/grub/mips/loongson/time.h @@ -20,15 +20,8 @@ #define KERNEL_MACHINE_TIME_HEADER 1 #include +#include -#define GRUB_TICKS_PER_SECOND 1000 - -/* Return the real time in ticks. */ -grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); - -static inline void -grub_cpu_idle(void) -{ -} +extern grub_uint32_t EXPORT_VAR (grub_arch_busclock) __attribute__ ((section(".text"))); #endif /* ! KERNEL_MACHINE_TIME_HEADER */ diff --git a/include/grub/mips/memory.h b/include/grub/mips/memory.h index e51bcc1f2..a85bbe752 100644 --- a/include/grub/mips/memory.h +++ b/include/grub/mips/memory.h @@ -1 +1,60 @@ -#include +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MEMORY_CPU_HEADER +#define GRUB_MEMORY_CPU_HEADER 1 + +#ifndef ASM_FILE +#include +#include +#include +#endif + +#define GRUB_ARCH_LOWMEMVSTART 0x80000000 +#define GRUB_ARCH_LOWMEMPSTART 0x00000000 +#define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000 +#define GRUB_ARCH_HIGHMEMPSTART 0x10000000 + +#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_uint64_t grub_mmap_get_lower (void); +grub_uint64_t grub_mmap_get_upper (void); + +#endif + +#endif diff --git a/include/grub/mips/mips.h b/include/grub/mips/mips.h new file mode 100644 index 000000000..bafb2bde0 --- /dev/null +++ b/include/grub/mips/mips.h @@ -0,0 +1,30 @@ +/* + * 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_REGISTERS_CPU_HEADER +#define GRUB_REGISTERS_CPU_HEADER 1 + +#ifdef ASM_FILE +#define GRUB_CPU_REGISTER_WRAP(x) x +#else +#define GRUB_CPU_REGISTER_WRAP(x) #x +#endif + +#define GRUB_CPU_MIPS_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP($9) + +#endif diff --git a/include/grub/mips/qemu_mips/at_keyboard.h b/include/grub/mips/qemu_mips/at_keyboard.h new file mode 100644 index 000000000..37cc625d1 --- /dev/null +++ b/include/grub/mips/qemu_mips/at_keyboard.h @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MACHINE_AT_KEYBOARD_HEADER +#define GRUB_MACHINE_AT_KEYBOARD_HEADER 1 + +#define KEYBOARD_REG_DATA 0xb4000060 +#define KEYBOARD_REG_STATUS 0xb4000064 + +#endif diff --git a/include/grub/mips/qemu_mips/cmos.h b/include/grub/mips/qemu_mips/cmos.h new file mode 100644 index 000000000..4aef40e81 --- /dev/null +++ b/include/grub/mips/qemu_mips/cmos.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_CPU_CMOS_H +#define GRUB_CPU_CMOS_H 1 + +#include +#include + +#define GRUB_CMOS_ADDR_REG 0xb4000070 +#define GRUB_CMOS_DATA_REG 0xb4000071 + +#endif /* GRUB_CPU_CMOS_H */ diff --git a/include/grub/mips/qemu-mips/kernel.h b/include/grub/mips/qemu_mips/kernel.h similarity index 89% rename from include/grub/mips/qemu-mips/kernel.h rename to include/grub/mips/qemu_mips/kernel.h index 230455dbf..8b8b0149e 100644 --- a/include/grub/mips/qemu-mips/kernel.h +++ b/include/grub/mips/qemu_mips/kernel.h @@ -20,12 +20,10 @@ #define GRUB_KERNEL_MACHINE_HEADER 1 #include -#include #ifndef ASM_FILE -void EXPORT_FUNC (grub_reboot) (void); -void EXPORT_FUNC (grub_halt) (void); +void grub_qemu_init_cirrus (void); #endif diff --git a/include/grub/mips/qemu_mips/loader.h b/include/grub/mips/qemu_mips/loader.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/grub/mips/qemu-mips/memory.h b/include/grub/mips/qemu_mips/memory.h similarity index 84% rename from include/grub/mips/qemu-mips/memory.h rename to include/grub/mips/qemu_mips/memory.h index 99d9ef2be..29b04a5ad 100644 --- a/include/grub/mips/qemu-mips/memory.h +++ b/include/grub/mips/qemu_mips/memory.h @@ -29,10 +29,8 @@ #define GRUB_MACHINE_MEMORY_USABLE 0x81000000 #ifndef ASM_FILE -grub_err_t EXPORT_FUNC (grub_machine_mmap_iterate) -(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); -grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) - (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); + +extern grub_uint32_t grub_arch_memsize __attribute__ ((section(".text"))); static inline grub_err_t grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), diff --git a/include/grub/mips/qemu-mips/serial.h b/include/grub/mips/qemu_mips/serial.h similarity index 94% rename from include/grub/mips/qemu-mips/serial.h rename to include/grub/mips/qemu_mips/serial.h index 1f8ce0804..1708678dc 100644 --- a/include/grub/mips/qemu-mips/serial.h +++ b/include/grub/mips/qemu_mips/serial.h @@ -19,6 +19,6 @@ #ifndef GRUB_MACHINE_SERIAL_HEADER #define GRUB_MACHINE_SERIAL_HEADER 1 -#define GRUB_MACHINE_SERIAL_PORTS { 0x140003f8 } +#define GRUB_MACHINE_SERIAL_PORTS { 0xb40003f8 } #endif diff --git a/include/grub/mips/yeeloong/time.h b/include/grub/mips/qemu_mips/time.h similarity index 75% rename from include/grub/mips/yeeloong/time.h rename to include/grub/mips/qemu_mips/time.h index 7f468bf12..164b61ef8 100644 --- a/include/grub/mips/yeeloong/time.h +++ b/include/grub/mips/qemu_mips/time.h @@ -20,18 +20,6 @@ #define KERNEL_MACHINE_TIME_HEADER 1 #include - -#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) - -/* Return the real time in ticks. */ -grub_uint64_t EXPORT_FUNC (grub_get_rtc) (void); - -extern grub_uint32_t EXPORT_VAR (grub_arch_busclock); -extern grub_uint32_t EXPORT_VAR (grub_arch_cpuclock); - -static inline void -grub_cpu_idle(void) -{ -} +#include #endif /* ! KERNEL_MACHINE_TIME_HEADER */ diff --git a/include/grub/mips/time.h b/include/grub/mips/time.h index b143a48e0..f5c891a3a 100644 --- a/include/grub/mips/time.h +++ b/include/grub/mips/time.h @@ -1,6 +1,37 @@ -#ifdef GRUB_MACHINE_EMU +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,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 KERNEL_CPU_TIME_HEADER +#define KERNEL_CPU_TIME_HEADER 1 + +#ifndef GRUB_UTIL + +#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) + +/* Return the real time in ticks. */ +grub_uint64_t EXPORT_FUNC (grub_get_rtc) (void); + +extern grub_uint32_t EXPORT_VAR (grub_arch_cpuclock) __attribute__ ((section(".text"))); +#endif + static inline void grub_cpu_idle(void) { } + #endif diff --git a/include/grub/misc.h b/include/grub/misc.h index 27f15e44a..47607d3e3 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -49,14 +49,19 @@ #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, fmt, ## args) -/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ -#define grub_memcpy(d,s,n) grub_memmove ((d), (s), (n)) void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src); char *EXPORT_FUNC(grub_strncpy) (char *dest, const char *src, int c); char *EXPORT_FUNC(grub_stpcpy) (char *dest, const char *src); +/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ +static inline void * +grub_memcpy (void *dest, const void *src, grub_size_t n) +{ + return grub_memmove (dest, src, n); +} + static inline char * grub_strcat (char *dest, const char *src) { @@ -82,7 +87,7 @@ grub_strncat (char *dest, const char *src, int c) while (*p) p++; - while ((*p = *src) != '\0' && c--) + while (c-- && (*p = *src) != '\0') { p++; src++; @@ -108,7 +113,53 @@ int EXPORT_FUNC(grub_strncmp) (const char *s1, const char *s2, grub_size_t n); char *EXPORT_FUNC(grub_strchr) (const char *s, int c); char *EXPORT_FUNC(grub_strrchr) (const char *s, int c); int EXPORT_FUNC(grub_strword) (const char *s, const char *w); -char *EXPORT_FUNC(grub_strstr) (const char *haystack, const char *needle); + +/* Copied from gnulib. + Written by Bruno Haible , 2005. */ +static inline char * +grub_strstr (const char *haystack, const char *needle) +{ + /* Be careful not to look at the entire extent of haystack or needle + until needed. This is useful because of these two cases: + - haystack may be very long, and a match of needle found early, + - needle may be very long, and not even a short initial segment of + needle may be found in haystack. */ + if (*needle != '\0') + { + /* Speed up the following searches of needle by caching its first + character. */ + char b = *needle++; + + for (;; haystack++) + { + if (*haystack == '\0') + /* No match. */ + return 0; + if (*haystack == b) + /* The first character matches. */ + { + const char *rhaystack = haystack + 1; + const char *rneedle = needle; + + for (;; rhaystack++, rneedle++) + { + if (*rneedle == '\0') + /* Found a match. */ + return (char *) haystack; + if (*rhaystack == '\0') + /* No match. */ + return 0; + if (*rhaystack != *rneedle) + /* Nothing in this round. */ + break; + } + } + } + } + else + return (char *) haystack; +} + int EXPORT_FUNC(grub_isspace) (int c); int EXPORT_FUNC(grub_isprint) (int c); @@ -124,6 +175,18 @@ grub_isalpha (int c) return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +static inline int +grub_islower (int c) +{ + return (c >= 'a' && c <= 'z'); +} + +static inline int +grub_isupper (int c) +{ + return (c >= 'A' && c <= 'Z'); +} + static inline int grub_isgraph (int c) { @@ -136,6 +199,12 @@ grub_isdigit (int c) return (c >= '0' && c <= '9'); } +static inline int +grub_isxdigit (int c) +{ + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + static inline int grub_isalnum (int c) { @@ -193,7 +262,6 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n) return (int) grub_tolower (*s1) - (int) grub_tolower (*s2); } - unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base); unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base); @@ -240,6 +308,26 @@ grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) __attribute__ ((warn_unused int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +/* Replace all `ch' characters of `input' with `with' and copy the + result into `output'; return EOS address of `output'. */ +static inline char * +grub_strchrsub (char *output, const char *input, char ch, const char *with) +{ + while (*input) + { + if (*input == ch) + { + grub_strcpy (output, with); + output += grub_strlen (with); + input++; + continue; + } + *output++ = *input++; + } + *output = '\0'; + return output; +} + extern void (*EXPORT_VAR (grub_xputs)) (const char *str); static inline int @@ -268,7 +356,8 @@ char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) __attribute__ void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, - grub_uint32_t d, grub_uint32_t *r); + grub_uint64_t d, + grub_uint64_t *r); #if NEED_ENABLE_EXECUTE_STACK && !defined(GRUB_UTIL) void EXPORT_FUNC(__enable_execute_stack) (void *addr); @@ -281,6 +370,20 @@ void EXPORT_FUNC (__deregister_frame_info) (void); /* Inline functions. */ +static inline char * +grub_memchr (const void *p, int c, grub_size_t len) +{ + const char *s = p; + const char *e = s + len; + + for (; s < e; s++) + if (*s == c) + return (char *) s; + + return 0; +} + + static inline unsigned int grub_abs (int x) { @@ -290,24 +393,6 @@ grub_abs (int x) return (unsigned int) x; } -static inline long -grub_min (long x, long y) -{ - if (x < y) - return x; - else - return y; -} - -static inline long -grub_max (long x, long y) -{ - if (x > y) - return x; - else - return y; -} - /* Rounded-up division */ static inline unsigned int grub_div_roundup (unsigned int x, unsigned int y) @@ -316,12 +401,18 @@ grub_div_roundup (unsigned int x, unsigned int y) } /* Reboot the machine. */ -void EXPORT_FUNC (grub_reboot) (void) __attribute__ ((noreturn)); +#if defined (GRUB_MACHINE_EMU) || defined (GRUB_MACHINE_QEMU_MIPS) +void EXPORT_FUNC(grub_reboot) (void) __attribute__ ((noreturn)); +#else +void grub_reboot (void) __attribute__ ((noreturn)); +#endif #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 grub_halt (int no_apm) __attribute__ ((noreturn)); +#elif defined (__mips__) +void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn)); #else void grub_halt (void) __attribute__ ((noreturn)); #endif diff --git a/include/grub/mm.h b/include/grub/mm.h index cc115907a..82b200c27 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -36,7 +36,7 @@ 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__); +#define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); /* For debugging. */ #if defined(MM_DEBUG) && !defined(GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) @@ -72,4 +72,21 @@ void *EXPORT_FUNC(grub_debug_memalign) (const char *file, int line, grub_size_t align, grub_size_t size); #endif /* MM_DEBUG && ! GRUB_UTIL */ +#include + +static inline grub_err_t +grub_extend_alloc (grub_size_t sz, grub_size_t *allocated, void **ptr) +{ + void *n; + if (sz < *allocated) + return GRUB_ERR_NONE; + + *allocated = 2 * sz; + n = grub_realloc (*ptr, *allocated); + if (!n) + return grub_errno; + *ptr = n; + return GRUB_ERR_NONE; +} + #endif /* ! GRUB_MM_H */ diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h index a6e3fda49..9c8ac3e8a 100644 --- a/include/grub/msdos_partition.h +++ b/include/grub/msdos_partition.h @@ -42,9 +42,11 @@ #define GRUB_PC_PARTITION_TYPE_FAT32_LBA 0xc #define GRUB_PC_PARTITION_TYPE_FAT16_LBA 0xe #define GRUB_PC_PARTITION_TYPE_WIN95_EXTENDED 0xf +#define GRUB_PC_PARTITION_TYPE_PLAN9 0x39 #define GRUB_PC_PARTITION_TYPE_EZD 0x55 #define GRUB_PC_PARTITION_TYPE_MINIX 0x80 #define GRUB_PC_PARTITION_TYPE_LINUX_MINIX 0x81 +#define GRUB_PC_PARTITION_TYPE_LINUX_SWAP 0x82 #define GRUB_PC_PARTITION_TYPE_EXT2FS 0x83 #define GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED 0x85 #define GRUB_PC_PARTITION_TYPE_VSTAFS 0x9e diff --git a/include/grub/net.h b/include/grub/net.h index c6d71d5b6..d9fd821d9 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2007 Free Software Foundation, Inc. + * Copyright (C) 2010,2011 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 @@ -19,54 +19,494 @@ #ifndef GRUB_NET_HEADER #define GRUB_NET_HEADER 1 -#include -#include #include +#include +#include +#include +#include +#include +#include -struct grub_net; +enum + { + GRUB_NET_MAX_LINK_HEADER_SIZE = 64, + GRUB_NET_UDP_HEADER_SIZE = 8, + GRUB_NET_TCP_HEADER_SIZE = 20, + GRUB_NET_OUR_IPV4_HEADER_SIZE = 20, + GRUB_NET_OUR_IPV6_HEADER_SIZE = 40, + GRUB_NET_OUR_MAX_IP_HEADER_SIZE = 40, + GRUB_NET_TCP_RESERVE_SIZE = GRUB_NET_TCP_HEADER_SIZE + + GRUB_NET_OUR_IPV4_HEADER_SIZE + + GRUB_NET_MAX_LINK_HEADER_SIZE + }; -struct grub_net_dev +typedef enum grub_link_level_protocol_id { - /* The device name. */ + GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET +} grub_link_level_protocol_id_t; + +typedef struct grub_net_link_level_address +{ + grub_link_level_protocol_id_t type; + union + { + grub_uint8_t mac[6]; + }; +} grub_net_link_level_address_t; + +typedef enum grub_net_interface_flags + { + GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE = 1, + GRUB_NET_INTERFACE_ADDRESS_IMMUTABLE = 2, + GRUB_NET_INTERFACE_PERMANENT = 4 + } grub_net_interface_flags_t; + +typedef enum grub_net_card_flags + { + GRUB_NET_CARD_HWADDRESS_IMMUTABLE = 1, + GRUB_NET_CARD_NO_MANUAL_INTERFACES = 2 + } grub_net_card_flags_t; + +struct grub_net_card; + +struct grub_net_card_driver +{ + struct grub_net_card_driver *next; + struct grub_net_card_driver **prev; const char *name; - - /* FIXME: Just a template. */ - int (*probe) (struct grub_net *net, const void *addr); - void (*reset) (struct grub_net *net); - int (*poll) (struct grub_net *net); - void (*transmit) (struct grub_net *net, const void *destip, - unsigned srcsock, unsigned destsock, const void *packet); - void (*disable) (struct grub_net *net); - - /* The next net device. */ - struct grub_net_dev *next; + grub_err_t (*open) (const struct grub_net_card *dev); + void (*close) (const struct grub_net_card *dev); + grub_err_t (*send) (const struct grub_net_card *dev, + struct grub_net_buff *buf); + struct grub_net_buff * (*recv) (const struct grub_net_card *dev); }; -typedef struct grub_net_dev *grub_net_dev_t; -struct grub_fs; - -struct grub_net +typedef struct grub_net_packet { - /* The net name. */ + struct grub_net_packet *next; + struct grub_net_packet *prev; + struct grub_net_packets *up; + struct grub_net_buff *nb; +} grub_net_packet_t; + +typedef struct grub_net_packets +{ + grub_net_packet_t *first; + grub_net_packet_t *last; +} grub_net_packets_t; + +#ifdef GRUB_MACHINE_EFI +#include +#endif + +struct grub_net_slaac_mac_list +{ + struct grub_net_slaac_mac_list *next; + struct grub_net_slaac_mac_list **prev; + grub_net_link_level_address_t address; + int slaac_counter; + char *name; +}; + +struct grub_net_link_layer_entry; + +struct grub_net_card +{ + struct grub_net_card *next; + struct grub_net_card **prev; const char *name; + struct grub_net_card_driver *driver; + grub_net_link_level_address_t default_address; + grub_net_card_flags_t flags; + int num_ifaces; + int opened; + unsigned idle_poll_delay_ms; + grub_uint64_t last_poll; + grub_size_t mtu; + struct grub_net_slaac_mac_list *slaac_list; + grub_ssize_t new_ll_entry; + struct grub_net_link_layer_entry *link_layer_table; + union + { +#ifdef GRUB_MACHINE_EFI + struct + { + struct grub_efi_simple_network *efi_net; + grub_efi_handle_t efi_handle; + }; +#endif + void *data; + int data_num; + }; +}; - /* The underlying disk device. */ - grub_net_dev_t dev; +struct grub_net_network_level_interface; - /* The binding filesystem. */ - struct grub_fs *fs; +typedef enum grub_network_level_protocol_id +{ + GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV, + GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4, + GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6 +} grub_network_level_protocol_id_t; - /* FIXME: More data would be required, such as an IP address, a mask, - a gateway, etc. */ +typedef struct grub_net_network_level_address +{ + grub_network_level_protocol_id_t type; + union + { + grub_uint32_t ipv4; + grub_uint64_t ipv6[2]; + }; +} grub_net_network_level_address_t; - /* Device-specific data. */ +typedef struct grub_net_network_level_netaddress +{ + grub_network_level_protocol_id_t type; + union + { + struct { + grub_uint32_t base; + int masksize; + } ipv4; + struct { + grub_uint64_t base[2]; + int masksize; + } ipv6; + }; +} grub_net_network_level_netaddress_t; + +#define FOR_PACKETS(cont,var) for (var = (cont).first; var; var = var->next) + +static inline grub_err_t +grub_net_put_packet (grub_net_packets_t *pkts, struct grub_net_buff *nb) +{ + struct grub_net_packet *n; + + n = grub_malloc (sizeof (*n)); + if (!n) + return grub_errno; + + n->nb = nb; + n->next = NULL; + n->prev = NULL; + n->up = pkts; + if (pkts->first) + { + pkts->last->next = n; + pkts->last = n; + n->prev = pkts->last; + } + else + pkts->first = pkts->last = n; + + return GRUB_ERR_NONE; +} + +static inline void +grub_net_remove_packet (grub_net_packet_t *pkt) +{ + if (pkt->prev) + pkt->prev->next = pkt->next; + else + pkt->up->first = pkt->next; + if (pkt->next) + pkt->next->prev = pkt->prev; + else + pkt->up->last = pkt->prev; + grub_free (pkt); +} + +typedef struct grub_net_app_protocol *grub_net_app_level_t; + +typedef struct grub_net_socket *grub_net_socket_t; + +struct grub_net_app_protocol +{ + struct grub_net_app_protocol *next; + struct grub_net_app_protocol **prev; + const char *name; + grub_err_t (*dir) (grub_device_t device, const char *path, + int (*hook) (const char *filename, + const struct grub_dirhook_info *info)); + grub_err_t (*open) (struct grub_file *file, const char *filename); + grub_err_t (*seek) (struct grub_file *file, grub_off_t off); + grub_err_t (*close) (struct grub_file *file); +}; + +typedef struct grub_net +{ + char *server; + char *name; + grub_net_app_level_t protocol; + grub_net_packets_t packs; + grub_off_t offset; + grub_fs_t fs; + int eof; +} *grub_net_t; + +extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); + +struct grub_net_network_level_interface +{ + struct grub_net_network_level_interface *next; + struct grub_net_network_level_interface **prev; + char *name; + struct grub_net_card *card; + grub_net_network_level_address_t address; + grub_net_link_level_address_t hwaddress; + grub_net_interface_flags_t flags; + struct grub_net_bootp_packet *dhcp_ack; + grub_size_t dhcp_acklen; void *data; }; -typedef struct grub_net *grub_net_t; -/* FIXME: How to abstract networks? More consideration is necessary. */ +struct grub_net_session; -/* Note: Networks are very different from disks, because networks must - be initialized before used, and the status is persistent. */ +struct grub_net_session_level_protocol +{ + void (*close) (struct grub_net_session *session); + grub_ssize_t (*recv) (struct grub_net_session *session, void *buf, + grub_size_t size); + grub_err_t (*send) (struct grub_net_session *session, void *buf, + grub_size_t size); +}; + +struct grub_net_session +{ + struct grub_net_session_level_protocol *protocol; + void *data; +}; + +static inline void +grub_net_session_close (struct grub_net_session *session) +{ + session->protocol->close (session); +} + +static inline grub_err_t +grub_net_session_send (struct grub_net_session *session, void *buf, + grub_size_t size) +{ + return session->protocol->send (session, buf, size); +} + +static inline grub_ssize_t +grub_net_session_recv (struct grub_net_session *session, void *buf, + grub_size_t size) +{ + return session->protocol->recv (session, buf, size); +} + +struct grub_net_network_level_interface * +grub_net_add_addr (const char *name, + struct grub_net_card *card, + const grub_net_network_level_address_t *addr, + const grub_net_link_level_address_t *hwaddress, + grub_net_interface_flags_t flags); + +extern struct grub_net_network_level_interface *grub_net_network_level_interfaces; +#define FOR_NET_NETWORK_LEVEL_INTERFACES(var) for (var = grub_net_network_level_interfaces; var; var = var->next) + +extern grub_net_app_level_t grub_net_app_level_list; + +#ifndef GRUB_LST_GENERATOR +static inline void +grub_net_app_level_register (grub_net_app_level_t proto) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_net_app_level_list), + GRUB_AS_LIST (proto)); +} +#endif + +static inline void +grub_net_app_level_unregister (grub_net_app_level_t proto) +{ + grub_list_remove (GRUB_AS_LIST (proto)); +} + +#define FOR_NET_APP_LEVEL(var) FOR_LIST_ELEMENTS((var), \ + (grub_net_app_level_list)) + +extern struct grub_net_card *grub_net_cards; + +static inline void +grub_net_card_register (struct grub_net_card *card) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_net_cards), + GRUB_AS_LIST (card)); +} + +void +grub_net_card_unregister (struct grub_net_card *card); + +#define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next) +#define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0)) + + +struct grub_net_session * +grub_net_open_tcp (char *address, grub_uint16_t port); + +grub_err_t +grub_net_resolve_address (const char *name, + grub_net_network_level_address_t *addr); + +grub_err_t +grub_net_resolve_net_address (const char *name, + grub_net_network_level_netaddress_t *addr); + +grub_err_t +grub_net_route_address (grub_net_network_level_address_t addr, + grub_net_network_level_address_t *gateway, + struct grub_net_network_level_interface **interf); + + +grub_err_t +grub_net_add_route (const char *name, + grub_net_network_level_netaddress_t target, + struct grub_net_network_level_interface *inter); + +grub_err_t +grub_net_add_route_gw (const char *name, + grub_net_network_level_netaddress_t target, + grub_net_network_level_address_t gw); + + +#define GRUB_NET_BOOTP_MAC_ADDR_LEN 16 + +typedef grub_uint8_t grub_net_bootp_mac_addr_t[GRUB_NET_BOOTP_MAC_ADDR_LEN]; + +struct grub_net_bootp_packet +{ + grub_uint8_t opcode; + grub_uint8_t hw_type; /* hardware type. */ + grub_uint8_t hw_len; /* hardware addr len. */ + grub_uint8_t gate_hops; /* zero it. */ + grub_uint32_t ident; /* random number chosen by client. */ + grub_uint16_t seconds; /* seconds since did initial bootstrap. */ + grub_uint16_t flags; + grub_uint32_t client_ip; + grub_uint32_t your_ip; + grub_uint32_t server_ip; + grub_uint32_t gateway_ip; + grub_net_bootp_mac_addr_t mac_addr; + char server_name[64]; + char boot_file[128]; + grub_uint8_t vendor[0]; +} __attribute__ ((packed)); + +#define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 +#define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 +#define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 +#define GRUB_NET_BOOTP_RFC1048_MAGIC_3 0x63 + +enum + { + GRUB_NET_BOOTP_PAD = 0x00, + GRUB_NET_BOOTP_ROUTER = 0x03, + GRUB_NET_BOOTP_DNS = 0x06, + GRUB_NET_BOOTP_HOSTNAME = 0x0c, + GRUB_NET_BOOTP_DOMAIN = 0x0f, + GRUB_NET_BOOTP_ROOT_PATH = 0x11, + GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12, + GRUB_NET_BOOTP_END = 0xff + }; + +struct grub_net_network_level_interface * +grub_net_configure_by_dhcp_ack (const char *name, + struct grub_net_card *card, + grub_net_interface_flags_t flags, + const struct grub_net_bootp_packet *bp, + grub_size_t size, + int is_def, char **device, char **path); + +void +grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_card *card); + +int +grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b); +int +grub_net_addr_cmp (const grub_net_network_level_address_t *a, + const grub_net_network_level_address_t *b); + + +/* + Currently supported adresses: + IPv4: XXX.XXX.XXX.XXX + IPv6: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX + */ +#define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX") + +/* + Currently suppoerted adresses: + ethernet: XX:XX:XX:XX:XX:XX + */ + +#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX")) + +void +grub_net_addr_to_str (const grub_net_network_level_address_t *target, + char *buf); +void +grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str); + +extern struct grub_net_network_level_interface *grub_net_network_level_interfaces; +#define FOR_NET_NETWORK_LEVEL_INTERFACES(var) for (var = grub_net_network_level_interfaces; var; var = var->next) + +#define FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(var,next) for (var = grub_net_network_level_interfaces, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0)) + +void +grub_net_poll_cards (unsigned time); + +void grub_bootp_init (void); +void grub_bootp_fini (void); + +void grub_dns_init (void); +void grub_dns_fini (void); + +static inline void +grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter) +{ + inter->card->num_ifaces--; + *inter->prev = inter->next; + if (inter->next) + inter->next->prev = inter->prev; + inter->next = 0; + inter->prev = 0; +} + +void +grub_net_tcp_retransmit (void); + +void +grub_net_link_layer_add_address (struct grub_net_card *card, + const grub_net_network_level_address_t *nl, + const grub_net_link_level_address_t *ll, + int override); +int +grub_net_link_layer_resolve_check (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr); +grub_err_t +grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr, + grub_net_link_level_address_t *hw_addr); +grub_err_t +grub_net_dns_lookup (const char *name, + const struct grub_net_network_level_address *servers, + grub_size_t n_servers, + grub_size_t *naddresses, + struct grub_net_network_level_address **addresses, + int cache); +grub_err_t +grub_net_add_dns_server (const struct grub_net_network_level_address *s); +void +grub_net_remove_dns_server (const struct grub_net_network_level_address *s); + + +extern char *grub_net_default_server; + +#define GRUB_NET_TRIES 40 +#define GRUB_NET_INTERVAL 400 #endif /* ! GRUB_NET_HEADER */ diff --git a/include/grub/net/arp.h b/include/grub/net/arp.h new file mode 100644 index 000000000..bb1703622 --- /dev/null +++ b/include/grub/net/arp.h @@ -0,0 +1,31 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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_NET_ARP_HEADER +#define GRUB_NET_ARP_HEADER 1 +#include +#include + +extern grub_err_t grub_net_arp_receive (struct grub_net_buff *nb, + struct grub_net_card *card); + +grub_err_t +grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr); + +#endif diff --git a/include/grub/net/ethernet.h b/include/grub/net/ethernet.h new file mode 100644 index 000000000..23a935e98 --- /dev/null +++ b/include/grub/net/ethernet.h @@ -0,0 +1,41 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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_NET_ETHERNET_HEADER +#define GRUB_NET_ETHERNET_HEADER 1 +#include +#include + +/* IANA Ethertype */ +typedef enum + { + GRUB_NET_ETHERTYPE_IP = 0x0800, + GRUB_NET_ETHERTYPE_ARP = 0x0806, + GRUB_NET_ETHERTYPE_IP6 = 0x86DD, + } grub_net_ethertype_t; + +grub_err_t +send_ethernet_packet (struct grub_net_network_level_interface *inf, + struct grub_net_buff *nb, + grub_net_link_level_address_t target_addr, + grub_net_ethertype_t ethertype); +grub_err_t +grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + struct grub_net_card *card); + +#endif diff --git a/include/grub/net/ip.h b/include/grub/net/ip.h new file mode 100644 index 000000000..7a8e61479 --- /dev/null +++ b/include/grub/net/ip.h @@ -0,0 +1,95 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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_NET_IP_HEADER +#define GRUB_NET_IP_HEADER 1 +#include +#include + +typedef enum grub_net_ip_protocol + { + GRUB_NET_IP_ICMP = 1, + GRUB_NET_IP_TCP = 6, + GRUB_NET_IP_UDP = 17, + GRUB_NET_IP_ICMPV6 = 58 + } grub_net_ip_protocol_t; +#define GRUB_NET_IP_BROADCAST 0xFFFFFFFF + +static inline grub_uint64_t +grub_net_ipv6_get_id (const grub_net_link_level_address_t *addr) +{ + return grub_cpu_to_be64 (((grub_uint64_t) (addr->mac[0] ^ 2) << 56) + | ((grub_uint64_t) addr->mac[1] << 48) + | ((grub_uint64_t) addr->mac[2] << 40) + | 0xfffe000000ULL + | ((grub_uint64_t) addr->mac[3] << 16) + | ((grub_uint64_t) addr->mac[4] << 8) + | ((grub_uint64_t) addr->mac[5])); +} + +grub_uint16_t grub_net_ip_chksum(void *ipv, grub_size_t len); + +grub_err_t +grub_net_recv_ip_packets (struct grub_net_buff *nb, + struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddress, + const grub_net_link_level_address_t *src_hwaddress); + +grub_err_t +grub_net_send_ip_packet (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *target, + const grub_net_link_level_address_t *ll_target_addr, + struct grub_net_buff *nb, + grub_net_ip_protocol_t proto); + +grub_err_t +grub_net_recv_icmp_packet (struct grub_net_buff *nb, + struct grub_net_network_level_interface *inf, + const grub_net_link_level_address_t *ll_src, + const grub_net_network_level_address_t *src); +grub_err_t +grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + struct grub_net_card *card, + struct grub_net_network_level_interface *inf, + const grub_net_link_level_address_t *ll_src, + const grub_net_network_level_address_t *source, + const grub_net_network_level_address_t *dest, + grub_uint8_t ttl); +grub_err_t +grub_net_recv_udp_packet (struct grub_net_buff *nb, + struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *src); +grub_err_t +grub_net_recv_tcp_packet (struct grub_net_buff *nb, + struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *source); + +grub_uint16_t +grub_net_ip_transport_checksum (struct grub_net_buff *nb, + grub_uint16_t proto, + const grub_net_network_level_address_t *src, + const grub_net_network_level_address_t *dst); + +struct grub_net_network_level_interface * +grub_net_ipv6_get_link_local (struct grub_net_card *card, + const grub_net_link_level_address_t *hwaddr); +grub_err_t +grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr); + +#endif diff --git a/include/grub/net/netbuff.h b/include/grub/net/netbuff.h new file mode 100644 index 000000000..c745d51d7 --- /dev/null +++ b/include/grub/net/netbuff.h @@ -0,0 +1,30 @@ +#ifndef GRUB_NETBUFF_HEADER +#define GRUB_NETBUFF_HEADER + +#include + +#define NETBUFF_ALIGN 2048 +#define NETBUFFMINLEN 64 + +struct grub_net_buff +{ + /* Pointer to the start of the buffer. */ + grub_uint8_t *head; + /* Pointer to the data. */ + grub_uint8_t *data; + /* Pointer to the tail. */ + grub_uint8_t *tail; + /* Pointer to the end of the buffer. */ + grub_uint8_t *end; +}; + +grub_err_t grub_netbuff_put (struct grub_net_buff *net_buff, grub_size_t len); +grub_err_t grub_netbuff_unput (struct grub_net_buff *net_buff, grub_size_t len); +grub_err_t grub_netbuff_push (struct grub_net_buff *net_buff, grub_size_t len); +grub_err_t grub_netbuff_pull (struct grub_net_buff *net_buff, grub_size_t len); +grub_err_t grub_netbuff_reserve (struct grub_net_buff *net_buff, grub_size_t len); +grub_err_t grub_netbuff_clear (struct grub_net_buff *net_buff); +struct grub_net_buff * grub_netbuff_alloc (grub_size_t len); +grub_err_t grub_netbuff_free (struct grub_net_buff *net_buff); + +#endif diff --git a/include/grub/net/tcp.h b/include/grub/net/tcp.h new file mode 100644 index 000000000..62bfd2eba --- /dev/null +++ b/include/grub/net/tcp.h @@ -0,0 +1,79 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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_NET_TCP_HEADER +#define GRUB_NET_TCP_HEADER 1 +#include +#include + +struct grub_net_tcp_socket; +typedef struct grub_net_tcp_socket *grub_net_tcp_socket_t; + +struct grub_net_tcp_listen; +typedef struct grub_net_tcp_listen *grub_net_tcp_listen_t; + +grub_net_tcp_socket_t +grub_net_tcp_open (char *server, + grub_uint16_t out_port, + grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, + struct grub_net_buff *nb, + void *data), + void (*error_hook) (grub_net_tcp_socket_t sock, + void *data), + void (*fin_hook) (grub_net_tcp_socket_t sock, + void *data), + void *hook_data); + +grub_net_tcp_listen_t +grub_net_tcp_listen (grub_uint16_t port, + const struct grub_net_network_level_interface *inf, + grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen, + grub_net_tcp_socket_t sock, + void *data), + void *hook_data); + +void +grub_net_tcp_stop_listen (grub_net_tcp_listen_t listen); + +grub_err_t +grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket, + struct grub_net_buff *nb, + int push); + +enum + { + GRUB_NET_TCP_CONTINUE_RECEIVING, + GRUB_NET_TCP_DISCARD, + GRUB_NET_TCP_ABORT + }; + +void +grub_net_tcp_close (grub_net_tcp_socket_t sock, int discard_received); + +grub_err_t +grub_net_tcp_accept (grub_net_tcp_socket_t sock, + grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, + struct grub_net_buff *nb, + void *data), + void (*error_hook) (grub_net_tcp_socket_t sock, + void *data), + void (*fin_hook) (grub_net_tcp_socket_t sock, + void *data), + void *hook_data); + +#endif diff --git a/include/grub/net/udp.h b/include/grub/net/udp.h new file mode 100644 index 000000000..1a7efa777 --- /dev/null +++ b/include/grub/net/udp.h @@ -0,0 +1,51 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011 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_NET_UDP_HEADER +#define GRUB_NET_UDP_HEADER 1 +#include +#include + +struct udphdr +{ + grub_uint16_t src; + grub_uint16_t dst; + grub_uint16_t len; + grub_uint16_t chksum; +} __attribute__ ((packed)); + +struct grub_net_udp_socket; +typedef struct grub_net_udp_socket *grub_net_udp_socket_t; + +grub_net_udp_socket_t +grub_net_udp_open (grub_net_network_level_address_t addr, + grub_uint16_t out_port, + grub_err_t (*recv_hook) (grub_net_udp_socket_t sock, + struct grub_net_buff *nb, + void *data), + void *recv_hook_data); + +void +grub_net_udp_close (grub_net_udp_socket_t sock); + +grub_err_t +grub_net_send_udp_packet (const grub_net_udp_socket_t socket, + struct grub_net_buff *nb); + + +#endif diff --git a/include/grub/normal.h b/include/grub/normal.h index 187567797..84e387242 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -28,9 +28,6 @@ #include #include -/* The maximum size of a command-line. */ -#define GRUB_MAX_CMDLINE 1600 - /* The standard left and right margin for some messages. */ #define STANDARD_MARGIN 6 @@ -51,7 +48,7 @@ extern int grub_normal_exit_level; /* Defined in `main.c'. */ void grub_enter_normal_mode (const char *config); void grub_normal_execute (const char *config, int nested, int batch); -void grub_menu_init_page (int nested, int edit, +void grub_menu_init_page (int nested, int edit, int *num_entries, struct grub_term_output *term); void grub_normal_init_page (struct grub_term_output *term); char *grub_file_getline (grub_file_t file); @@ -80,6 +77,11 @@ grub_print_ucs4 (const grub_uint32_t * str, const grub_uint32_t * last_position, int margin_left, int margin_right, struct grub_term_output *term); +int +grub_ucs4_count_lines (const grub_uint32_t * str, + const grub_uint32_t * last_position, + int margin_left, int margin_right, + struct grub_term_output *term); grub_ssize_t grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position, struct grub_term_output *term); @@ -89,7 +91,7 @@ void grub_print_message_indented (const char *msg, int margin_left, void grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested); grub_err_t -grub_show_menu (grub_menu_t menu, int nested); +grub_show_menu (grub_menu_t menu, int nested, int autobooted); /* Defined in `handler.c'. */ void read_handler_list (void); diff --git a/include/grub/ntfs.h b/include/grub/ntfs.h index 31b99398b..5cdd5f73f 100644 --- a/include/grub/ntfs.h +++ b/include/grub/ntfs.h @@ -20,79 +20,87 @@ #ifndef GRUB_NTFS_H #define GRUB_NTFS_H 1 -#define FILE_MFT 0 -#define FILE_MFTMIRR 1 -#define FILE_LOGFILE 2 -#define FILE_VOLUME 3 -#define FILE_ATTRDEF 4 -#define FILE_ROOT 5 -#define FILE_BITMAP 6 -#define FILE_BOOT 7 -#define FILE_BADCLUS 8 -#define FILE_QUOTA 9 -#define FILE_UPCASE 10 +enum + { + GRUB_NTFS_FILE_MFT = 0, + GRUB_NTFS_FILE_MFTMIRR = 1, + GRUB_NTFS_FILE_LOGFILE = 2, + GRUB_NTFS_FILE_VOLUME = 3, + GRUB_NTFS_FILE_ATTRDEF = 4, + GRUB_NTFS_FILE_ROOT = 5, + GRUB_NTFS_FILE_BITMAP = 6, + GRUB_NTFS_FILE_BOOT = 7, + GRUB_NTFS_FILE_BADCLUS = 8, + GRUB_NTFS_FILE_QUOTA = 9, + GRUB_NTFS_FILE_UPCASE = 10, + }; -#define AT_STANDARD_INFORMATION 0x10 -#define AT_ATTRIBUTE_LIST 0x20 -#define AT_FILENAME 0x30 -#define AT_OBJECT_ID 0x40 -#define AT_SECURITY_DESCRIPTOR 0x50 -#define AT_VOLUME_NAME 0x60 -#define AT_VOLUME_INFORMATION 0x70 -#define AT_DATA 0x80 -#define AT_INDEX_ROOT 0x90 -#define AT_INDEX_ALLOCATION 0xA0 -#define AT_BITMAP 0xB0 -#define AT_SYMLINK 0xC0 -#define AT_EA_INFORMATION 0xD0 -#define AT_EA 0xE0 +enum + { + GRUB_NTFS_AT_STANDARD_INFORMATION = 0x10, + GRUB_NTFS_AT_ATTRIBUTE_LIST = 0x20, + GRUB_NTFS_AT_FILENAME = 0x30, + GRUB_NTFS_AT_OBJECT_ID = 0x40, + GRUB_NTFS_AT_SECURITY_DESCRIPTOR = 0x50, + GRUB_NTFS_AT_VOLUME_NAME = 0x60, + GRUB_NTFS_AT_VOLUME_INFORMATION = 0x70, + GRUB_NTFS_AT_DATA = 0x80, + GRUB_NTFS_AT_INDEX_ROOT = 0x90, + GRUB_NTFS_AT_INDEX_ALLOCATION = 0xA0, + GRUB_NTFS_AT_BITMAP = 0xB0, + GRUB_NTFS_AT_SYMLINK = 0xC0, + GRUB_NTFS_AT_EA_INFORMATION = 0xD0, + GRUB_NTFS_AT_EA = 0xE0, + }; -#define ATTR_READ_ONLY 0x1 -#define ATTR_HIDDEN 0x2 -#define ATTR_SYSTEM 0x4 -#define ATTR_ARCHIVE 0x20 -#define ATTR_DEVICE 0x40 -#define ATTR_NORMAL 0x80 -#define ATTR_TEMPORARY 0x100 -#define ATTR_SPARSE 0x200 -#define ATTR_REPARSE 0x400 -#define ATTR_COMPRESSED 0x800 -#define ATTR_OFFLINE 0x1000 -#define ATTR_NOT_INDEXED 0x2000 -#define ATTR_ENCRYPTED 0x4000 -#define ATTR_DIRECTORY 0x10000000 -#define ATTR_INDEX_VIEW 0x20000000 +enum + { + GRUB_NTFS_ATTR_READ_ONLY = 0x1, + GRUB_NTFS_ATTR_HIDDEN = 0x2, + GRUB_NTFS_ATTR_SYSTEM = 0x4, + GRUB_NTFS_ATTR_ARCHIVE = 0x20, + GRUB_NTFS_ATTR_DEVICE = 0x40, + GRUB_NTFS_ATTR_NORMAL = 0x80, + GRUB_NTFS_ATTR_TEMPORARY = 0x100, + GRUB_NTFS_ATTR_SPARSE = 0x200, + GRUB_NTFS_ATTR_REPARSE = 0x400, + GRUB_NTFS_ATTR_COMPRESSED = 0x800, + GRUB_NTFS_ATTR_OFFLINE = 0x1000, + GRUB_NTFS_ATTR_NOT_INDEXED = 0x2000, + GRUB_NTFS_ATTR_ENCRYPTED = 0x4000, + GRUB_NTFS_ATTR_DIRECTORY = 0x10000000, + GRUB_NTFS_ATTR_INDEX_VIEW = 0x20000000 + }; -#define FLAG_COMPRESSED 1 -#define FLAG_ENCRYPTED 0x4000 -#define FLAG_SPARSE 0x8000 +enum + { + GRUB_NTFS_FLAG_COMPRESSED = 1, + GRUB_NTFS_FLAG_ENCRYPTED = 0x4000, + GRUB_NTFS_FLAG_SPARSE = 0x8000 + }; -#define BLK_SHR GRUB_DISK_SECTOR_BITS +#define GRUB_NTFS_BLK_SHR GRUB_DISK_SECTOR_BITS -#define MAX_MFT (1024 >> BLK_SHR) -#define MAX_IDX (16384 >> BLK_SHR) +#define GRUB_NTFS_MAX_MFT (4096 >> GRUB_NTFS_BLK_SHR) +#define GRUB_NTFS_MAX_IDX (16384 >> GRUB_NTFS_BLK_SHR) -#define COM_LEN 4096 -#define COM_LOG_LEN 12 -#define COM_SEC (COM_LEN >> BLK_SHR) +#define GRUB_NTFS_COM_LEN 4096 +#define GRUB_NTFS_COM_LOG_LEN 12 +#define GRUB_NTFS_COM_SEC (GRUB_NTFS_COM_LEN >> GRUB_NTFS_BLK_SHR) -#define AF_ALST 1 -#define AF_MMFT 2 -#define AF_GPOS 4 +enum + { + GRUB_NTFS_AF_ALST = 1, + GRUB_NTFS_AF_MMFT = 2, + GRUB_NTFS_AF_GPOS = 4, + }; -#define RF_COMP 1 -#define RF_CBLK 2 -#define RF_BLNK 4 - -#define valueat(buf,ofs,type) *((type*)(((char*)buf)+ofs)) - -#define u16at(buf,ofs) grub_le_to_cpu16(valueat(buf,ofs,grub_uint16_t)) -#define u32at(buf,ofs) grub_le_to_cpu32(valueat(buf,ofs,grub_uint32_t)) -#define u64at(buf,ofs) grub_le_to_cpu64(valueat(buf,ofs,grub_uint64_t)) - -#define v16at(buf,ofs) valueat(buf,ofs,grub_uint16_t) -#define v32at(buf,ofs) valueat(buf,ofs,grub_uint32_t) -#define v64at(buf,ofs) valueat(buf,ofs,grub_uint64_t) +enum + { + GRUB_NTFS_RF_COMP = 1, + GRUB_NTFS_RF_CBLK = 2, + GRUB_NTFS_RF_BLNK = 4 + }; struct grub_ntfs_bpb { @@ -106,20 +114,20 @@ struct grub_ntfs_bpb grub_uint16_t sectors_per_track; grub_uint16_t num_heads; grub_uint32_t num_hidden_sectors; - grub_uint32_t reserved_3[2]; + grub_uint32_t reserved_3; + grub_uint8_t bios_drive; + grub_uint8_t reserved_4[3]; grub_uint64_t num_total_sectors; grub_uint64_t mft_lcn; grub_uint64_t mft_mirr_lcn; grub_int8_t clusters_per_mft; - grub_int8_t reserved_4[3]; - grub_int8_t clusters_per_index; grub_int8_t reserved_5[3]; + grub_int8_t clusters_per_index; + grub_int8_t reserved_6[3]; grub_uint64_t num_serial; grub_uint32_t checksum; } __attribute__ ((packed)); -#define grub_ntfs_file grub_fshelp_node - struct grub_ntfs_attr { int flags; @@ -130,11 +138,12 @@ struct grub_ntfs_attr struct grub_ntfs_file *mft; }; -struct grub_fshelp_node +struct grub_ntfs_file { struct grub_ntfs_data *data; char *buf; grub_uint64_t size; + grub_uint64_t mtime; grub_uint32_t ino; int inode_read; struct grub_ntfs_attr attr; @@ -148,7 +157,6 @@ struct grub_ntfs_data grub_uint32_t mft_size; grub_uint32_t idx_size; grub_uint32_t spc; - grub_uint32_t blocksize; grub_uint32_t mft_start; grub_uint64_t uuid; }; @@ -171,13 +179,15 @@ struct grub_ntfs_rlst struct grub_ntfs_comp comp; }; -typedef grub_err_t (*ntfscomp_func_t) (struct grub_ntfs_attr * at, char *dest, - grub_uint32_t ofs, grub_uint32_t len, - struct grub_ntfs_rlst * ctx, - grub_uint32_t vcn); +typedef grub_err_t (*grub_ntfscomp_func_t) (struct grub_ntfs_attr * at, + char *dest, + grub_uint32_t ofs, + grub_uint32_t len, + struct grub_ntfs_rlst * ctx, + grub_uint32_t vcn); -extern ntfscomp_func_t EXPORT_VAR (grub_ntfscomp_func); +extern grub_ntfscomp_func_t grub_ntfscomp_func; -grub_err_t EXPORT_FUNC(grub_ntfs_read_run_list) (struct grub_ntfs_rlst *ctx); +grub_err_t grub_ntfs_read_run_list (struct grub_ntfs_rlst *ctx); #endif /* ! GRUB_NTFS_H */ diff --git a/include/grub/offsets.h b/include/grub/offsets.h index b096abf37..d55e308c7 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -19,39 +19,26 @@ #ifndef OFFSETS_HEADER #define OFFSETS_HEADER 1 -/* The offset of GRUB_TOTAL_MODULE_SIZE. */ -#define GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE 0x8 - -/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ -#define GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE 0xc +/* The offset of GRUB_COMPRESSED_SIZE. */ +#define GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE 0x08 /* The offset of GRUB_COMPRESSED_SIZE. */ -#define GRUB_KERNEL_I386_PC_COMPRESSED_SIZE 0x10 - -/* The offset of GRUB_INSTALL_DOS_PART. */ -#define GRUB_KERNEL_I386_PC_INSTALL_DOS_PART 0x14 - -/* The offset of GRUB_INSTALL_BSD_PART. */ -#define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART 0x18 +#define GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE 0x0c /* Offset of reed_solomon_redundancy. */ -#define GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY 0x1c +#define GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY 0x10 -/* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE 0xc90 +/* Offset of field holding no reed solomon length. */ +#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH 0x14 -#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x6f8 +#define GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE 0x18 -/* 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) +#define GRUB_DECOMPRESSOR_I386_PC_MAX_DECOMPRESSOR_SIZE (0x9000-0x8200) /* The segment where the kernel is loaded. */ #define GRUB_BOOT_I386_PC_KERNEL_SEG 0x800 -#define GRUB_KERNEL_I386_PC_LINK_ADDR 0x8200 +#define GRUB_KERNEL_I386_PC_LINK_ADDR 0x9000 /* The upper memory area (starting at 640 kiB). */ #define GRUB_MEMORY_I386_PC_UPPER 0xa0000 @@ -63,75 +50,48 @@ /* The offset of GRUB_CORE_ENTRY_ADDR. */ #define GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR 0x8 -/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ -#define GRUB_KERNEL_I386_QEMU_KERNEL_IMAGE_SIZE 0xc - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_I386_QEMU_PREFIX 0x10 - -/* End of the data section. */ -#define GRUB_KERNEL_I386_QEMU_PREFIX_END 0x50 - #define GRUB_KERNEL_I386_QEMU_LINK_ADDR 0x8200 /* The offset of GRUB_TOTAL_MODULE_SIZE. */ #define GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE 0x8 -/* The offset of GRUB_KERNEL_IMAGE_SIZE. */ -#define GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE 0xc - -/* The offset of GRUB_COMPRESSED_SIZE. */ -#define GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE 0x10 - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX 0x14 - -/* End of the data section. */ -#define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END 0x114 - #define GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE 12 #define GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS 0x4400 -#define GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE 0 #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 -#define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX 0x4 -#define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END 0x44 #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 -#define GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR 0x80200000 +#define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR 0x80200000 -#define GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN 32 +#define GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN 32 -#define GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE 0x8 -#define GRUB_KERNEL_MIPS_YEELOONG_UNCOMPRESSED_SIZE 0xc +#define GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE 0x8 +#define GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE 0xc +#define GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR 0x10 -#define GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE 0x08 -#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX 0x0c -#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END 0x54 +#define GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE 0x08 -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_I386_EFI_PREFIX 0x8 +#define GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR 0x80200000 +#define GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN 32 +#define GRUB_DECOMPRESSOR_MIPS_QEMU_MIPS_COMPRESSED_SIZE 0x8 +#define GRUB_DECOMPRESSOR_MIPS_QEMU_MIPS_UNCOMPRESSED_SIZE 0xc +#define GRUB_DECOMPRESSOR_MIPS_QEMU_MIPS_UNCOMPRESSED_ADDR 0x10 +#define GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE 0x08 -/* End of the data section. */ -#define GRUB_KERNEL_I386_EFI_PREFIX_END 0x50 +#define GRUB_KERNEL_MIPS_ARC_LINK_ADDR 0x8bd00000 -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8 +#define GRUB_KERNEL_MIPS_ARC_LINK_ALIGN 32 -/* End of the data section. */ -#define GRUB_KERNEL_X86_64_EFI_PREFIX_END 0x50 +#define GRUB_DECOMPRESSOR_MIPS_ARC_COMPRESSED_SIZE 0x8 +#define GRUB_DECOMPRESSOR_MIPS_ARC_UNCOMPRESSED_SIZE 0xc +#define GRUB_DECOMPRESSOR_MIPS_ARC_UNCOMPRESSED_ADDR 0x10 + +#define GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE 0x08 -#define GRUB_KERNEL_I386_COREBOOT_PREFIX 0x2 -#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_PREFIX_END 0x42 #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR 0x10000 #define GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN 0x1000 @@ -141,10 +101,14 @@ /* Non-zero value is only needed for PowerMacs. */ #define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0 #define GRUB_KERNEL_I386_COREBOOT_MOD_GAP 0x0 +#define GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP 0x0 #define GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN 0x1000 +#define GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN 0x1 -#define GRUB_KERNEL_MIPS_YEELOONG_MOD_ALIGN 0x1 +#define GRUB_KERNEL_MIPS_LOONGSON_MOD_ALIGN 0x1 +#define GRUB_KERNEL_MIPS_ARC_MOD_ALIGN 0x1 +#define GRUB_KERNEL_MIPS_QEMU_MIPS_MOD_ALIGN 0x1 /* Minimal gap between _end and the start of the modules. It's a hack for PowerMac to prevent "CLAIM failed" error. The real fix is to @@ -157,17 +121,14 @@ #define GRUB_KERNEL_MACHINE_MOD_ALIGN GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _MOD_ALIGN) #define GRUB_KERNEL_MACHINE_MOD_GAP GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _MOD_GAP) #define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _TOTAL_MODULE_SIZE) -#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _KERNEL_IMAGE_SIZE) -#define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _COMPRESSED_SIZE) -#define GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _UNCOMPRESSED_SIZE) -#define GRUB_KERNEL_MACHINE_PREFIX GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _PREFIX) -#define GRUB_KERNEL_MACHINE_PREFIX_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _PREFIX_END) #define GRUB_BOOT_MACHINE_KERNEL_SEG GRUB_OFFSETS_CONCAT (GRUB_BOOT_, GRUB_MACHINE, _KERNEL_SEG) #define GRUB_MEMORY_MACHINE_UPPER GRUB_OFFSETS_CONCAT (GRUB_MEMORY_, GRUB_MACHINE, _UPPER) -#define GRUB_KERNEL_MACHINE_RAW_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _RAW_SIZE) -#define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _INSTALL_BSD_PART) -#define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _INSTALL_DOS_PART) +#define GRUB_MACHINE_LINK_ADDR GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _LINK_ADDR) + +#define GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_DECOMPRESSOR_, GRUB_MACHINE, _COMPRESSED_SIZE) +#define GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_DECOMPRESSOR_, GRUB_MACHINE, _UNCOMPRESSED_SIZE) +#define GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR GRUB_OFFSETS_CONCAT (GRUB_DECOMPRESSOR_, GRUB_MACHINE, _UNCOMPRESSED_ADDR) #endif #ifndef ASM_FILE diff --git a/include/grub/partition.h b/include/grub/partition.h index e7e00ef7f..7c1e7f6b3 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -38,6 +38,7 @@ struct grub_partition_map { /* The next partition map type. */ struct grub_partition_map *next; + struct grub_partition_map **prev; /* The name of the partition map type. */ const char *name; @@ -106,8 +107,7 @@ grub_partition_map_register (grub_partition_map_t partmap) static inline void grub_partition_map_unregister (grub_partition_map_t partmap) { - grub_list_remove (GRUB_AS_LIST_P (&grub_partition_map_list), - GRUB_AS_LIST (partmap)); + grub_list_remove (GRUB_AS_LIST (partmap)); } #define FOR_PARTITION_MAPS(var) FOR_LIST_ELEMENTS((var), (grub_partition_map_list)) diff --git a/include/grub/parttool.h b/include/grub/parttool.h index 8291e1161..4e8f8d5e5 100644 --- a/include/grub/parttool.h +++ b/include/grub/parttool.h @@ -21,8 +21,8 @@ struct grub_parttool_argdesc { - char *name; - char *desc; + const char *name; + const char *desc; enum {GRUB_PARTTOOL_ARG_END, GRUB_PARTTOOL_ARG_BOOL, GRUB_PARTTOOL_ARG_VAL} type; }; diff --git a/include/grub/pci.h b/include/grub/pci.h index f34e3d907..2c2806889 100644 --- a/include/grub/pci.h +++ b/include/grub/pci.h @@ -132,6 +132,21 @@ void EXPORT_FUNC(grub_dma_free) (struct grub_pci_dma_chunk *ch); volatile void *EXPORT_FUNC(grub_dma_get_virt) (struct grub_pci_dma_chunk *ch); grub_uint32_t EXPORT_FUNC(grub_dma_get_phys) (struct grub_pci_dma_chunk *ch); +static inline void * +grub_dma_phys2virt (grub_uint32_t phys, struct grub_pci_dma_chunk *chunk) +{ + return ((grub_uint8_t *) grub_dma_get_virt (chunk) + + (phys - grub_dma_get_phys (chunk))); +} + +static inline grub_uint32_t +grub_dma_virt2phys (volatile void *virt, struct grub_pci_dma_chunk *chunk) +{ + return (((grub_uint8_t *) virt - (grub_uint8_t *) grub_dma_get_virt (chunk)) + + grub_dma_get_phys (chunk)); +} + + #endif #endif /* GRUB_PCI_H */ diff --git a/include/grub/powerpc/ieee1275/biosdisk.h b/include/grub/powerpc/ieee1275/biosdisk.h deleted file mode 100644 index 30584d6b7..000000000 --- a/include/grub/powerpc/ieee1275/biosdisk.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,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_BIOSDISK_MACHINE_HEADER -#define GRUB_BIOSDISK_MACHINE_HEADER 1 - -#define GRUB_BIOSDISK_FLAG_LBA 1 - -struct grub_biosdisk_data -{ - int drive; - unsigned long cylinders; - unsigned long heads; - unsigned long sectors; - unsigned long flags; -}; - -int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap); -int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, - int soff, int nsec, int segment); -int grub_biosdisk_check_int13_extensions (int drive); -int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp); -int grub_biosdisk_get_diskinfo_standard (int drive, - unsigned long *cylinders, - unsigned long *heads, - unsigned long *sectors); -int grub_biosdisk_get_num_floppies (void); - -void grub_biosdisk_init (void); - -#endif /* ! GRUB_BIOSDISK_MACHINE_HEADER */ diff --git a/include/grub/powerpc/ieee1275/util/biosdisk.h b/include/grub/powerpc/ieee1275/util/biosdisk.h deleted file mode 100644 index f4262a0a4..000000000 --- a/include/grub/powerpc/ieee1275/util/biosdisk.h +++ /dev/null @@ -1,27 +0,0 @@ -/* biosdisk.h - emulate biosdisk */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,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_BIOSDISK_MACHINE_UTIL_HEADER -#define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1 - -void grub_util_biosdisk_init (const char *dev_map); -void grub_util_biosdisk_fini (void); -char *grub_util_biosdisk_get_grub_dev (const char *os_dev); - -#endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ diff --git a/include/grub/priority_queue.h b/include/grub/priority_queue.h new file mode 100644 index 000000000..a5d98c8c9 --- /dev/null +++ b/include/grub/priority_queue.h @@ -0,0 +1,36 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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_PRIORITY_QUEUE_HEADER +#define GRUB_PRIORITY_QUEUE_HEADER 1 + +#include +#include + +struct grub_priority_queue; +typedef struct grub_priority_queue *grub_priority_queue_t; +typedef int (*grub_comparator_t) (const void *a, const void *b); + +grub_priority_queue_t grub_priority_queue_new (grub_size_t elsize, + grub_comparator_t cmp); +void grub_priority_queue_destroy (grub_priority_queue_t pq); +void *grub_priority_queue_top (grub_priority_queue_t pq); +void grub_priority_queue_pop (grub_priority_queue_t pq); +grub_err_t grub_priority_queue_push (grub_priority_queue_t pq, const void *el); + +#endif diff --git a/include/grub/raid.h b/include/grub/raid.h deleted file mode 100644 index 711a7f79c..000000000 --- a/include/grub/raid.h +++ /dev/null @@ -1,88 +0,0 @@ -/* raid.h - On disk structures for RAID. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * 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_RAID_H -#define GRUB_RAID_H 1 - -#include - -#define GRUB_RAID_MAX_DEVICES 32 - -#define GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC 0 -#define GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC 1 -#define GRUB_RAID_LAYOUT_LEFT_SYMMETRIC 2 -#define GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC 3 - -#define GRUB_RAID_LAYOUT_RIGHT_MASK 1 -#define GRUB_RAID_LAYOUT_SYMMETRIC_MASK 2 - -struct grub_raid_array -{ - int number; /* The device number, taken from md_minor so we - are consistent with the device name in - Linux. */ - int level; /* RAID levels, only 0, 1 or 5 at the moment. */ - int layout; /* Layout for RAID 5/6. */ - unsigned int total_devs; /* Total number of devices in the array. */ - grub_size_t chunk_size; /* The size of a chunk, in 512 byte sectors. */ - grub_uint64_t disk_size; /* Size of an individual disk, in 512 byte - sectors. */ - int index; /* Index of current device. */ - int uuid_len; /* The length of uuid. */ - char *uuid; /* The UUID of the device. */ - - /* The following field is setup by the caller. */ - char *name; /* That will be "md". */ - unsigned int nr_devs; /* The number of devices we've found so far. */ - grub_disk_t device[GRUB_RAID_MAX_DEVICES]; /* Array of total_devs devices. */ - grub_disk_addr_t start_sector[GRUB_RAID_MAX_DEVICES]; - /* Start of each device, in 512 byte sectors. */ - struct grub_raid_array *next; -}; - -struct grub_raid -{ - const char *name; - - grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array, - grub_disk_addr_t *start_sector); - - struct grub_raid *next; -}; -typedef struct grub_raid *grub_raid_t; - -void grub_raid_register (grub_raid_t raid); -void grub_raid_unregister (grub_raid_t raid); - -void grub_raid_block_xor (char *buf1, const char *buf2, int size); - -typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_raid_array *array, - int disknr, char *buf, - grub_disk_addr_t sector, - int size); - -typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_raid_array *array, - int disknr, int p, char *buf, - grub_disk_addr_t sector, - int size); - -extern grub_raid5_recover_func_t grub_raid5_recover_func; -extern grub_raid6_recover_func_t grub_raid6_recover_func; - -#endif /* ! GRUB_RAID_H */ diff --git a/include/grub/reader.h b/include/grub/reader.h index fd72a3252..cd92df8f2 100644 --- a/include/grub/reader.h +++ b/include/grub/reader.h @@ -24,6 +24,6 @@ typedef grub_err_t (*grub_reader_getline_t) (char **, int); -void grub_rescue_run (void); +void grub_rescue_run (void) __attribute__ ((noreturn)); #endif /* ! GRUB_READER_HEADER */ diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 6d31fca5a..fdccaca8d 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -245,8 +245,9 @@ 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); +int grub_script_argv_append (struct grub_script_argv *argv, const char *s, + grub_size_t slen); +int grub_script_argv_split_append (struct grub_script_argv *argv, const char *s); struct grub_script_arglist * grub_script_create_arglist (struct grub_parser_param *state); diff --git a/include/grub/scsi.h b/include/grub/scsi.h index b30d317c7..13300ca15 100644 --- a/include/grub/scsi.h +++ b/include/grub/scsi.h @@ -19,6 +19,8 @@ #ifndef GRUB_SCSI_H #define GRUB_SCSI_H 1 +#include + typedef struct grub_scsi_dev *grub_scsi_dev_t; void grub_scsi_dev_register (grub_scsi_dev_t dev); @@ -29,9 +31,13 @@ struct grub_scsi; enum { GRUB_SCSI_SUBSYSTEM_USBMS, - GRUB_SCSI_SUBSYSTEM_ATAPI + GRUB_SCSI_SUBSYSTEM_PATA, + GRUB_SCSI_SUBSYSTEM_AHCI, + GRUB_SCSI_NUM_SUBSYSTEMS }; +extern const char grub_scsi_names[GRUB_SCSI_NUM_SUBSYSTEMS][5]; + #define GRUB_SCSI_ID_SUBSYSTEM_SHIFT 24 #define GRUB_SCSI_ID_BUS_SHIFT 8 #define GRUB_SCSI_ID_LUN_SHIFT 0 @@ -45,16 +51,12 @@ grub_make_scsi_id (int subsystem, int bus, int lun) struct grub_scsi_dev { - /* The device name. */ - const char *name; - - grub_uint8_t id; - /* Call HOOK with each device name, until HOOK returns non-zero. */ - int (*iterate) (int (*hook) (int bus, int luns)); + int (*iterate) (int NESTED_FUNC_ATTR (*hook) (int id, int bus, int luns), + grub_disk_pull_t pull); /* Open the device named NAME, and set up SCSI. */ - grub_err_t (*open) (int bus, struct grub_scsi *scsi); + grub_err_t (*open) (int id, int bus, struct grub_scsi *scsi); /* Close the scsi device SCSI. */ void (*close) (struct grub_scsi *scsi); @@ -67,7 +69,7 @@ struct grub_scsi_dev /* Write SIZE bytes from BUF to the device SCSI after sending the command CMD of size CMDSIZE. */ grub_err_t (*write) (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, - grub_size_t size, char *buf); + grub_size_t size, const char *buf); /* The next scsi device. */ struct grub_scsi_dev *next; @@ -92,11 +94,11 @@ struct grub_scsi /* Set to 0 when not removable, 1 when removable. */ int removable; - /* Size of the device in blocks. */ - int size; + /* Size of the device in blocks - 1. */ + grub_uint64_t last_block; /* Size of one block. */ - int blocksize; + grub_uint32_t blocksize; /* Device-specific data. */ void *data; diff --git a/include/grub/scsicmd.h b/include/grub/scsicmd.h index 9cc5afe72..a3e79888a 100644 --- a/include/grub/scsicmd.h +++ b/include/grub/scsicmd.h @@ -85,7 +85,7 @@ struct grub_scsi_request_sense_data /* there can be additional sense field */ } __attribute__((packed)); -struct grub_scsi_read_capacity +struct grub_scsi_read_capacity10 { grub_uint8_t opcode; grub_uint8_t lun; /* 7-5 LUN, 4-1 reserved, 0 reserved */ @@ -97,12 +97,29 @@ struct grub_scsi_read_capacity grub_uint16_t pad; /* To be ATAPI compatible */ } __attribute__((packed)); -struct grub_scsi_read_capacity_data +struct grub_scsi_read_capacity10_data { - grub_uint32_t size; + grub_uint32_t last_block; grub_uint32_t blocksize; } __attribute__((packed)); +struct grub_scsi_read_capacity16 +{ + grub_uint8_t opcode; + grub_uint8_t lun; /* 7-5 LUN, 4-0 0x10 */ + grub_uint64_t logical_block_addr; /* only if PMI=1 */ + grub_uint32_t alloc_len; + grub_uint8_t PMI; + grub_uint8_t control; +} __attribute__((packed)); + +struct grub_scsi_read_capacity16_data +{ + grub_uint64_t last_block; + grub_uint32_t blocksize; + grub_uint8_t pad[20]; +} __attribute__((packed)); + struct grub_scsi_read10 { grub_uint8_t opcode; @@ -124,6 +141,16 @@ struct grub_scsi_read12 grub_uint8_t control; } __attribute__((packed)); +struct grub_scsi_read16 +{ + grub_uint8_t opcode; + grub_uint8_t lun; + grub_uint64_t lba; + grub_uint32_t size; + grub_uint8_t reserved; + grub_uint8_t control; +} __attribute__((packed)); + struct grub_scsi_write10 { grub_uint8_t opcode; @@ -145,14 +172,27 @@ struct grub_scsi_write12 grub_uint8_t control; } __attribute__((packed)); +struct grub_scsi_write16 +{ + grub_uint8_t opcode; + grub_uint8_t lun; + grub_uint64_t lba; + grub_uint32_t size; + grub_uint8_t reserved; + grub_uint8_t control; +} __attribute__((packed)); + typedef enum { grub_scsi_cmd_test_unit_ready = 0x00, grub_scsi_cmd_request_sense = 0x03, grub_scsi_cmd_inquiry = 0x12, - grub_scsi_cmd_read_capacity = 0x25, + grub_scsi_cmd_read_capacity10 = 0x25, grub_scsi_cmd_read10 = 0x28, grub_scsi_cmd_write10 = 0x2a, + grub_scsi_cmd_read16 = 0x88, + grub_scsi_cmd_write16 = 0x8a, + grub_scsi_cmd_read_capacity16 = 0x9e, grub_scsi_cmd_read12 = 0xa8, grub_scsi_cmd_write12 = 0xaa, } grub_scsi_cmd_t; diff --git a/include/grub/serial.h b/include/grub/serial.h index 652268b2e..242823fab 100644 --- a/include/grub/serial.h +++ b/include/grub/serial.h @@ -63,6 +63,7 @@ struct grub_serial_config struct grub_serial_port { struct grub_serial_port *next; + struct grub_serial_port **prev; char *name; struct grub_serial_driver *driver; struct grub_serial_config config; @@ -72,7 +73,11 @@ struct grub_serial_port */ union { - grub_port_t port; + struct + { + grub_port_t port; + int broken; + }; struct { grub_usb_device_t usbdev; @@ -92,13 +97,39 @@ grub_err_t EXPORT_FUNC(grub_serial_register) (struct grub_serial_port *port); void EXPORT_FUNC(grub_serial_unregister) (struct grub_serial_port *port); + /* Convenience functions to perform primitive operations on a port. */ +static inline grub_err_t +grub_serial_port_configure (struct grub_serial_port *port, + struct grub_serial_config *config) +{ + return port->driver->configure (port, config); +} + +static inline int +grub_serial_port_fetch (struct grub_serial_port *port) +{ + return port->driver->fetch (port); +} + +static inline void +grub_serial_port_put (struct grub_serial_port *port, const int c) +{ + port->driver->put (port, c); +} + +static inline void +grub_serial_port_fini (struct grub_serial_port *port) +{ + port->driver->fini (port); +} + /* Set default settings. */ static inline grub_err_t grub_serial_config_defaults (struct grub_serial_port *port) { struct grub_serial_config config = { -#ifdef GRUB_MACHINE_MIPS_YEELOONG +#ifdef GRUB_MACHINE_MIPS_LOONGSON .speed = 115200, #else .speed = 9600, @@ -113,6 +144,7 @@ grub_serial_config_defaults (struct grub_serial_port *port) void grub_ns8250_init (void); char *grub_serial_ns8250_add_port (grub_port_t port); +struct grub_serial_port *grub_serial_find (const char *name); extern struct grub_serial_driver grub_ns8250_driver; void EXPORT_FUNC(grub_serial_unregister_driver) (struct grub_serial_driver *driver); diff --git a/include/grub/sparc64/ieee1275/boot.h b/include/grub/sparc64/ieee1275/boot.h index 112d19bc7..60edc712e 100644 --- a/include/grub/sparc64/ieee1275/boot.h +++ b/include/grub/sparc64/ieee1275/boot.h @@ -39,9 +39,7 @@ #define GRUB_BOOT_MACHINE_SIGNATURE 0xbb44aa55 -#define GRUB_BOOT_MACHINE_VER_MAJ 0x08 - -#define GRUB_BOOT_MACHINE_BOOT_DEVPATH 0x0a +#define GRUB_BOOT_MACHINE_BOOT_DEVPATH 0x08 #define GRUB_BOOT_MACHINE_BOOT_DEVPATH_END 0x80 diff --git a/include/grub/sparc64/ieee1275/kernel.h b/include/grub/sparc64/ieee1275/kernel.h index 5aa50b852..9a00bea61 100644 --- a/include/grub/sparc64/ieee1275/kernel.h +++ b/include/grub/sparc64/ieee1275/kernel.h @@ -26,12 +26,6 @@ #include #include -/* The size of kernel image. */ -extern grub_int32_t grub_kernel_image_size; - -/* The total size of module images following the kernel. */ -extern grub_int32_t grub_total_module_size; - #endif /* ! ASM_FILE */ #endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/include/grub/term.h b/include/grub/term.h index dbcb2f52c..8fdf16234 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -140,9 +140,6 @@ grub_term_color_state; /* The X position of the left border. */ #define GRUB_TERM_LEFT_BORDER_X GRUB_TERM_MARGIN -/* The number of lines of messages at the bottom. */ -#define GRUB_TERM_MESSAGE_HEIGHT 8 - /* The Y position of the first entry. */ #define GRUB_TERM_FIRST_ENTRY_Y (GRUB_TERM_TOP_BORDER_Y + 1) @@ -150,6 +147,7 @@ struct grub_term_input { /* The next terminal. */ struct grub_term_input *next; + struct grub_term_input **prev; /* The terminal name. */ const char *name; @@ -174,6 +172,7 @@ struct grub_term_output { /* The next terminal. */ struct grub_term_output *next; + struct grub_term_output **prev; /* The terminal name. */ const char *name; @@ -251,6 +250,14 @@ grub_term_register_input (const char *name __attribute__ ((unused)), } } +static inline void +grub_term_register_input_inactive (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); +} + static inline void grub_term_register_input_active (const char *name __attribute__ ((unused)), grub_term_input_t term) @@ -275,6 +282,14 @@ grub_term_register_output (const char *name __attribute__ ((unused)), } } +static inline void +grub_term_register_output_inactive (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); +} + static inline void grub_term_register_output_active (const char *name __attribute__ ((unused)), grub_term_output_t term) @@ -287,17 +302,15 @@ grub_term_register_output_active (const char *name __attribute__ ((unused)), static inline void grub_term_unregister_input (grub_term_input_t term) { - grub_list_remove (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); - grub_list_remove (GRUB_AS_LIST_P (&grub_term_inputs_disabled), - GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); } static inline void grub_term_unregister_output (grub_term_output_t term) { - grub_list_remove (GRUB_AS_LIST_P (&grub_term_outputs), GRUB_AS_LIST (term)); - grub_list_remove (GRUB_AS_LIST_P (&(grub_term_outputs_disabled)), - GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); } #define FOR_ACTIVE_TERM_INPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_inputs)) @@ -339,29 +352,6 @@ grub_term_entry_width (struct grub_term_output *term) return grub_term_border_width (term) - 2 - GRUB_TERM_MARGIN * 2 - 1; } -/* The height of the border. */ - -static inline unsigned -grub_term_border_height (struct grub_term_output *term) -{ - return grub_term_height (term) - GRUB_TERM_TOP_BORDER_Y - - GRUB_TERM_MESSAGE_HEIGHT; -} - -/* The number of entries shown at a time. */ -static inline int -grub_term_num_entries (struct grub_term_output *term) -{ - return grub_term_border_height (term) - 2; -} - -static inline int -grub_term_cursor_x (struct grub_term_output *term) -{ - return (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term) - - GRUB_TERM_MARGIN - 1); -} - static inline grub_uint16_t grub_term_getxy (struct grub_term_output *term) { diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index 8317995d8..e3b28ce88 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -27,7 +27,7 @@ char *EXPORT_FUNC(grub_terminfo_get_current) (struct grub_term_output *term); grub_err_t EXPORT_FUNC(grub_terminfo_set_current) (struct grub_term_output *term, const char *); -#define GRUB_TERMINFO_READKEY_MAX_LEN 4 +#define GRUB_TERMINFO_READKEY_MAX_LEN 6 struct grub_terminfo_input_state { int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN]; @@ -56,6 +56,7 @@ struct grub_terminfo_output_state void (*put) (struct grub_term_output *term, const int c); }; +grub_err_t EXPORT_FUNC(grub_terminfo_output_init) (struct grub_term_output *term); void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_term_output_t term, grub_uint8_t x, grub_uint8_t y); void EXPORT_FUNC(grub_terminfo_cls) (grub_term_output_t term); diff --git a/include/grub/test.h b/include/grub/test.h index 336d3b672..04a8ca13a 100644 --- a/include/grub/test.h +++ b/include/grub/test.h @@ -29,6 +29,7 @@ struct grub_test { /* The next test. */ struct grub_test *next; + struct grub_test **prev; /* The test name. */ char *name; diff --git a/include/grub/tparm.h b/include/grub/tparm.h index 642a22f90..0c6f9e0f0 100644 --- a/include/grub/tparm.h +++ b/include/grub/tparm.h @@ -21,6 +21,6 @@ #define GRUB_TPARM_HEADER 1 /* Function prototypes. */ -char *grub_terminfo_tparm (const char *string, ...); +const char *grub_terminfo_tparm (const char *string, ...); #endif /* ! GRUB_TPARM_HEADER */ diff --git a/include/grub/types.h b/include/grub/types.h index 221fef3c0..94badaa1d 100644 --- a/include/grub/types.h +++ b/include/grub/types.h @@ -84,12 +84,10 @@ typedef unsigned long long grub_uint64_t; /* Misc types. */ #if GRUB_TARGET_SIZEOF_VOID_P == 8 typedef grub_uint64_t grub_target_addr_t; -typedef grub_uint64_t grub_target_off_t; typedef grub_uint64_t grub_target_size_t; typedef grub_int64_t grub_target_ssize_t; #else typedef grub_uint32_t grub_target_addr_t; -typedef grub_uint32_t grub_target_off_t; typedef grub_uint32_t grub_target_size_t; typedef grub_int32_t grub_target_ssize_t; #endif @@ -100,11 +98,15 @@ typedef grub_uint64_t grub_size_t; typedef grub_int64_t grub_ssize_t; # if GRUB_CPU_SIZEOF_LONG == 8 -# define PRIxGRUB_SIZE "lx" -# define PRIuGRUB_SIZE "lu" +# define PRIxGRUB_SIZE "lx" +# define PRIxGRUB_ADDR "lx" +# define PRIuGRUB_SIZE "lu" +# define PRIdGRUB_SSIZE "ld" # else -# define PRIxGRUB_SIZE "llx" -# define PRIuGRUB_SIZE "llu" +# define PRIxGRUB_SIZE "llx" +# define PRIxGRUB_ADDR "llx" +# define PRIuGRUB_SIZE "llu" +# define PRIdGRUB_SSIZE "lld" # endif #else typedef grub_uint32_t grub_addr_t; @@ -112,9 +114,17 @@ typedef grub_uint32_t grub_size_t; typedef grub_int32_t grub_ssize_t; # define PRIxGRUB_SIZE "x" +# define PRIxGRUB_ADDR "x" # define PRIuGRUB_SIZE "u" +# define PRIdGRUB_SSIZE "d" #endif +#define GRUB_UCHAR_MAX 0xFF +#define GRUB_USHRT_MAX 65535 +#define GRUB_SHRT_MAX 0x7fff +#define GRUB_UINT_MAX 4294967295U +#define GRUB_INT_MAX 0x7fffffff + #if GRUB_CPU_SIZEOF_LONG == 8 # define GRUB_ULONG_MAX 18446744073709551615UL # define GRUB_LONG_MAX 9223372036854775807L @@ -125,15 +135,9 @@ typedef grub_int32_t grub_ssize_t; # define GRUB_LONG_MIN (-2147483647L - 1) #endif -#if GRUB_CPU_SIZEOF_VOID_P == 4 -#define UINT_TO_PTR(x) ((void*)(grub_uint32_t)(x)) -#define PTR_TO_UINT64(x) ((grub_uint64_t)(grub_uint32_t)(x)) -#define PTR_TO_UINT32(x) ((grub_uint32_t)(x)) -#else -#define UINT_TO_PTR(x) ((void*)(grub_uint64_t)(x)) -#define PTR_TO_UINT64(x) ((grub_uint64_t)(x)) -#define PTR_TO_UINT32(x) ((grub_uint32_t)(grub_uint64_t)(x)) -#endif +typedef grub_uint64_t grub_properly_aligned_t; + +#define GRUB_PROPERLY_ALIGNED_ARRAY(name, size) grub_properly_aligned_t name[((size) + sizeof (grub_properly_aligned_t) - 1) / sizeof (grub_properly_aligned_t)] /* The type for representing a file offset. */ typedef grub_uint64_t grub_off_t; @@ -148,6 +152,21 @@ typedef grub_uint64_t grub_disk_addr_t; (grub_uint16_t) ((_x << 8) | (_x >> 8)); \ }) +#define grub_swap_bytes16_compile_time(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define grub_swap_bytes32_compile_time(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000UL) >> 24)) +#define grub_swap_bytes64_compile_time(x) \ +({ \ + grub_uint64_t _x = (x); \ + (grub_uint64_t) ((_x << 56) \ + | ((_x & (grub_uint64_t) 0xFF00ULL) << 40) \ + | ((_x & (grub_uint64_t) 0xFF0000ULL) << 24) \ + | ((_x & (grub_uint64_t) 0xFF000000ULL) << 8) \ + | ((_x & (grub_uint64_t) 0xFF00000000ULL) >> 8) \ + | ((_x & (grub_uint64_t) 0xFF0000000000ULL) >> 24) \ + | ((_x & (grub_uint64_t) 0xFF000000000000ULL) >> 40) \ + | (_x >> 56)); \ +}) + #if defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3) static inline grub_uint32_t grub_swap_bytes32(grub_uint32_t x) { @@ -195,6 +214,12 @@ static inline grub_uint64_t grub_swap_bytes64(grub_uint64_t x) # define grub_be_to_cpu16(x) ((grub_uint16_t) (x)) # define grub_be_to_cpu32(x) ((grub_uint32_t) (x)) # define grub_be_to_cpu64(x) ((grub_uint64_t) (x)) +# define grub_cpu_to_be16_compile_time(x) ((grub_uint16_t) (x)) +# define grub_cpu_to_be32_compile_time(x) ((grub_uint32_t) (x)) +# define grub_cpu_to_be64_compile_time(x) ((grub_uint64_t) (x)) +# define grub_be_to_cpu64_compile_time(x) ((grub_uint64_t) (x)) +# define grub_cpu_to_le32_compile_time(x) grub_swap_bytes32_compile_time(x) +# define grub_cpu_to_le16_compile_time(x) grub_swap_bytes16_compile_time(x) #else /* ! WORDS_BIGENDIAN */ # define grub_cpu_to_le16(x) ((grub_uint16_t) (x)) # define grub_cpu_to_le32(x) ((grub_uint32_t) (x)) @@ -208,6 +233,66 @@ static inline grub_uint64_t grub_swap_bytes64(grub_uint64_t x) # define grub_be_to_cpu16(x) grub_swap_bytes16(x) # define grub_be_to_cpu32(x) grub_swap_bytes32(x) # define grub_be_to_cpu64(x) grub_swap_bytes64(x) +# define grub_cpu_to_be16_compile_time(x) grub_swap_bytes16_compile_time(x) +# define grub_cpu_to_be32_compile_time(x) grub_swap_bytes32_compile_time(x) +# define grub_cpu_to_be64_compile_time(x) grub_swap_bytes64_compile_time(x) +# define grub_be_to_cpu64_compile_time(x) grub_swap_bytes64_compile_time(x) +# define grub_cpu_to_le16_compile_time(x) ((grub_uint16_t) (x)) +# define grub_cpu_to_le32_compile_time(x) ((grub_uint32_t) (x)) + #endif /* ! WORDS_BIGENDIAN */ +static inline grub_uint16_t grub_get_unaligned16 (const void *ptr) +{ + struct grub_unaligned_uint16_t + { + grub_uint16_t d; + } __attribute__ ((packed)); + const struct grub_unaligned_uint16_t *dd + = (const struct grub_unaligned_uint16_t *) ptr; + return dd->d; +} + +static inline void grub_set_unaligned16 (void *ptr, grub_uint16_t val) +{ + struct grub_unaligned_uint16_t + { + grub_uint16_t d; + } __attribute__ ((packed)); + struct grub_unaligned_uint16_t *dd = (struct grub_unaligned_uint16_t *) ptr; + dd->d = val; +} + +static inline grub_uint32_t grub_get_unaligned32 (const void *ptr) +{ + struct grub_unaligned_uint32_t + { + grub_uint32_t d; + } __attribute__ ((packed)); + const struct grub_unaligned_uint32_t *dd + = (const struct grub_unaligned_uint32_t *) ptr; + return dd->d; +} + +static inline void grub_set_unaligned32 (void *ptr, grub_uint32_t val) +{ + struct grub_unaligned_uint32_t + { + grub_uint32_t d; + } __attribute__ ((packed)); + struct grub_unaligned_uint32_t *dd = (struct grub_unaligned_uint32_t *) ptr; + dd->d = val; +} + +static inline grub_uint64_t grub_get_unaligned64 (const void *ptr) +{ + struct grub_unaligned_uint64_t + { + grub_uint64_t d; + } __attribute__ ((packed)); + const struct grub_unaligned_uint64_t *dd + = (const struct grub_unaligned_uint64_t *)ptr; + return dd->d; +} + #endif /* ! GRUB_TYPES_HEADER */ diff --git a/include/grub/unicode.h b/include/grub/unicode.h index 64769258a..24240a019 100644 --- a/include/grub/unicode.h +++ b/include/grub/unicode.h @@ -31,12 +31,12 @@ struct grub_unicode_bidi_pair struct grub_unicode_compact_range { - grub_uint32_t start:21; - grub_uint32_t end:21; - grub_uint8_t bidi_type:5; - grub_uint8_t comb_type; - grub_uint8_t bidi_mirror:1; - grub_uint8_t join_type:3; + unsigned start:21; + unsigned len:9; + unsigned bidi_type:5; + unsigned comb_type:8; + unsigned bidi_mirror:1; + unsigned join_type:3; } __attribute__ ((packed)); /* Old-style Arabic shaping. Used for "visual UTF-8" and @@ -206,8 +206,11 @@ enum GRUB_UNICODE_BLACK_LEFT_TRIANGLE = 0x25c4, GRUB_UNICODE_VARIATION_SELECTOR_1 = 0xfe00, GRUB_UNICODE_VARIATION_SELECTOR_16 = 0xfe0f, + GRUB_UNICODE_TAG_START = 0xe0000, + GRUB_UNICODE_TAG_END = 0xe007f, GRUB_UNICODE_VARIATION_SELECTOR_17 = 0xe0100, - GRUB_UNICODE_VARIATION_SELECTOR_256 = 0xe01ef + GRUB_UNICODE_VARIATION_SELECTOR_256 = 0xe01ef, + GRUB_UNICODE_LAST_VALID = 0x10ffff }; extern struct grub_unicode_compact_range grub_unicode_compact[]; diff --git a/include/grub/usb.h b/include/grub/usb.h index c31ce1310..08d57b2be 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -38,7 +38,8 @@ typedef enum GRUB_USB_ERR_BABBLE, GRUB_USB_ERR_TIMEOUT, GRUB_USB_ERR_BITSTUFF, - GRUB_USB_ERR_UNRECOVERABLE + GRUB_USB_ERR_UNRECOVERABLE, + GRUB_USB_ERR_BADDEVICE } grub_usb_err_t; typedef enum @@ -197,6 +198,11 @@ struct grub_usb_device grub_uint32_t statuschange; struct grub_usb_desc_endp *hub_endpoint; + + /* EHCI Split Transfer information */ + int port; + + int hubaddr; }; @@ -266,6 +272,7 @@ typedef int (*grub_usb_attach_hook_class) (grub_usb_device_t usbdev, struct grub_usb_attach_desc { struct grub_usb_attach_desc *next; + struct grub_usb_attach_desc **prev; int class; grub_usb_attach_hook_class hook; }; diff --git a/include/grub/util/libzfs.h b/include/grub/util/libzfs.h index 0500f70d7..a02caa335 100644 --- a/include/grub/util/libzfs.h +++ b/include/grub/util/libzfs.h @@ -42,4 +42,6 @@ extern nvlist_t *zpool_get_config (zpool_handle_t *, nvlist_t **); #endif /* ! HAVE_LIBZFS_H */ +libzfs_handle_t *grub_get_libzfs_handle (void); + #endif diff --git a/include/grub/util/lvm.h b/include/grub/util/lvm.h index 7a4c76c6b..ff268f83f 100644 --- a/include/grub/util/lvm.h +++ b/include/grub/util/lvm.h @@ -1,7 +1,7 @@ /* lvm.h - LVM support for GRUB utils. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2011 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,14 @@ #ifndef GRUB_LVM_UTIL_HEADER #define GRUB_LVM_UTIL_HEADER 1 +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + #ifdef __linux__ +#define LVM_DEV_MAPPER_STRING "/dev/mapper/" +#else +#define LVM_DEV_MAPPER_STRING "/dev/linux_lvm/" +#endif + int grub_util_lvm_isvolume (char *name); #endif diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 48dfbb868..419c8661c 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -47,7 +47,6 @@ void grub_util_write_image_at (const void *img, size_t size, off_t offset, void sync (void); int fsync (int fno); -void sleep(int s); grub_int64_t grub_util_get_disk_size (char *name); diff --git a/include/grub/vga.h b/include/grub/vga.h index 7f112d83a..58ec3ba15 100644 --- a/include/grub/vga.h +++ b/include/grub/vga.h @@ -19,7 +19,12 @@ #ifndef GRUB_VGA_HEADER #define GRUB_VGA_HEADER 1 +#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS #include +#else +#include +#define GRUB_MACHINE_PCI_IO_BASE 0xb4000000 +#endif enum { @@ -84,8 +89,8 @@ enum { GRUB_VGA_IO_MISC_COLOR = 0x01, GRUB_VGA_IO_MISC_ENABLE_VRAM_ACCESS = 0x02, - GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 = 0x08, GRUB_VGA_IO_MISC_28MHZ = 0x04, + GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 = 0x08, GRUB_VGA_IO_MISC_UPPER_64K = 0x20, GRUB_VGA_IO_MISC_NEGATIVE_HORIZ_POLARITY = 0x40, GRUB_VGA_IO_MISC_NEGATIVE_VERT_POLARITY = 0x80, @@ -290,11 +295,24 @@ static inline void grub_vga_write_arx (grub_uint8_t val, grub_uint8_t addr) { grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_INPUT_STATUS1_REGISTER); + grub_inb (GRUB_MACHINE_PCI_IO_BASE + 0x3ba); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX_READ); grub_outb (val, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); } +static inline grub_uint8_t +grub_vga_read_arx (grub_uint8_t addr) +{ + grub_uint8_t val; + grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_INPUT_STATUS1_REGISTER); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); + val = grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX_READ); + grub_outb (val, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); + return val; +} + struct grub_video_hw_config { unsigned vertical_total; diff --git a/include/grub/video.h b/include/grub/video.h index 5350d87eb..b3709bceb 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -27,6 +27,15 @@ specific coding format. */ typedef grub_uint32_t grub_video_color_t; +/* Video color in hardware independent format. */ +typedef struct grub_video_rgba_color +{ + grub_uint8_t red; + grub_uint8_t green; + grub_uint8_t blue; + grub_uint8_t alpha; +} grub_video_rgba_color_t; + /* This structure is driver specific and should not be accessed directly by outside code. */ struct grub_video_render_target; @@ -201,6 +210,66 @@ struct grub_video_palette_data grub_uint8_t a; /* Reserved bits value (0-255). */ }; +struct grub_video_edid_info +{ + grub_uint8_t header[8]; + grub_uint16_t manufacturer_id; + grub_uint16_t product_id; + grub_uint32_t serial_number; + grub_uint8_t week_of_manufacture; + grub_uint8_t year_of_manufacture; + grub_uint8_t version; + grub_uint8_t revision; + + grub_uint8_t video_input_definition; + grub_uint8_t max_horizontal_image_size; + grub_uint8_t max_vertical_image_size; + grub_uint8_t display_gamma; + grub_uint8_t feature_support; +#define GRUB_VIDEO_EDID_FEATURE_PREFERRED_TIMING_MODE (1 << 1) + + grub_uint8_t red_green_lo; + grub_uint8_t blue_white_lo; + grub_uint8_t red_x_hi; + grub_uint8_t red_y_hi; + grub_uint8_t green_x_hi; + grub_uint8_t green_y_hi; + grub_uint8_t blue_x_hi; + grub_uint8_t blue_y_hi; + grub_uint8_t white_x_hi; + grub_uint8_t white_y_hi; + + grub_uint8_t established_timings_1; + grub_uint8_t established_timings_2; + grub_uint8_t manufacturer_reserved_timings; + + grub_uint16_t standard_timings[8]; + + struct { + grub_uint16_t pixel_clock; + /* Only valid if the pixel clock is non-null. */ + grub_uint8_t horizontal_active_lo; + grub_uint8_t horizontal_blanking_lo; + grub_uint8_t horizontal_hi; + grub_uint8_t vertical_active_lo; + grub_uint8_t vertical_blanking_lo; + grub_uint8_t vertical_hi; + grub_uint8_t horizontal_sync_offset_lo; + grub_uint8_t horizontal_sync_pulse_width_lo; + grub_uint8_t vertical_sync_lo; + grub_uint8_t sync_hi; + grub_uint8_t horizontal_image_size_lo; + grub_uint8_t vertical_image_size_lo; + grub_uint8_t image_size_hi; + grub_uint8_t horizontal_border; + grub_uint8_t vertical_border; + grub_uint8_t flags; + } detailed_timings[4]; + + grub_uint8_t extension_flag; + grub_uint8_t checksum; +} __attribute__ ((packed)); + typedef enum grub_video_driver_id { GRUB_VIDEO_DRIVER_NONE, @@ -211,7 +280,9 @@ typedef enum grub_video_driver_id GRUB_VIDEO_DRIVER_VGA, GRUB_VIDEO_DRIVER_CIRRUS, GRUB_VIDEO_DRIVER_BOCHS, - GRUB_VIDEO_DRIVER_SDL + GRUB_VIDEO_DRIVER_SDL, + GRUB_VIDEO_DRIVER_SIS315PRO, + GRUB_VIDEO_DRIVER_RADEON_FULOONG2E, } grub_video_driver_id_t; typedef enum grub_video_adapter_prio @@ -227,6 +298,7 @@ struct grub_video_adapter { /* The next video adapter. */ struct grub_video_adapter *next; + struct grub_video_adapter **prev; /* The video adapter name. */ const char *name; @@ -302,6 +374,8 @@ struct grub_video_adapter int (*iterate) (int (*hook) (const struct grub_video_mode_info *info)); + grub_err_t (*get_edid) (struct grub_video_edid_info *edid_info); + void (*print_adapter_specific_info) (void); }; typedef struct grub_video_adapter *grub_video_adapter_t; @@ -325,8 +399,7 @@ grub_video_register (grub_video_adapter_t adapter) static inline void grub_video_unregister (grub_video_adapter_t adapter) { - grub_list_remove (GRUB_AS_LIST_P (&grub_video_adapter_list), - GRUB_AS_LIST (adapter)); + grub_list_remove (GRUB_AS_LIST (adapter)); } #define FOR_VIDEO_ADAPTERS(var) FOR_LIST_ELEMENTS((var), (grub_video_adapter_list)) @@ -414,6 +487,11 @@ grub_err_t EXPORT_FUNC (grub_video_set_active_render_target) (struct grub_video_ grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target); +grub_err_t EXPORT_FUNC (grub_video_edid_checksum) (struct grub_video_edid_info *edid_info); +grub_err_t EXPORT_FUNC (grub_video_edid_preferred_mode) (struct grub_video_edid_info *edid_info, + unsigned int *width, + unsigned int *height); + grub_err_t EXPORT_FUNC (grub_video_set_mode) (const char *modestring, unsigned int modemask, unsigned int modevalue); @@ -428,4 +506,27 @@ grub_video_check_mode_flag (grub_video_mode_type_t flags, grub_video_driver_id_t EXPORT_FUNC (grub_video_get_driver_id) (void); +static __inline grub_video_rgba_color_t +grub_video_rgba_color_rgb (int r, int g, int b) +{ + grub_video_rgba_color_t c; + c.red = r; + c.green = g; + c.blue = b; + c.alpha = 255; + return c; +} + +static __inline grub_video_color_t +grub_video_map_rgba_color (grub_video_rgba_color_t c) +{ + return grub_video_map_rgba (c.red, c.green, c.blue, c.alpha); +} + +int EXPORT_FUNC (grub_video_get_named_color) (const char *name, + grub_video_rgba_color_t *color); + +grub_err_t EXPORT_FUNC (grub_video_parse_color) (const char *s, + grub_video_rgba_color_t *color); + #endif /* ! GRUB_VIDEO_HEADER */ diff --git a/include/grub/x86_64/types.h b/include/grub/x86_64/types.h index bdee5a109..d53138ea3 100644 --- a/include/grub/x86_64/types.h +++ b/include/grub/x86_64/types.h @@ -28,4 +28,6 @@ /* x86_64 is little-endian. */ #undef GRUB_TARGET_WORDS_BIGENDIAN +#define GRUB_HAVE_UNALIGNED_ACCESS 1 + #endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/include/grub/xnu.h b/include/grub/xnu.h index 076aeb5ed..2a096d803 100644 --- a/include/grub/xnu.h +++ b/include/grub/xnu.h @@ -81,7 +81,7 @@ struct grub_xnu_extheader } __attribute__ ((packed)); struct grub_xnu_devtree_key *grub_xnu_create_key (struct grub_xnu_devtree_key **parent, - char *name); + const char *name); extern struct grub_xnu_devtree_key *grub_xnu_devtree_root; @@ -89,18 +89,20 @@ void grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur); 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); + const char *name); void grub_xnu_lock (void); void grub_xnu_unlock (void); grub_err_t grub_xnu_resume (char *imagename); grub_err_t grub_xnu_boot_resume (void); struct grub_xnu_devtree_key *grub_xnu_find_key (struct grub_xnu_devtree_key *parent, - char *name); + const char *name); grub_err_t grub_xnu_align_heap (int align); -grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, +grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, + const char *osbundlerequired, int maxrecursion); -grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, +grub_err_t grub_xnu_load_kext_from_dir (char *dirname, + const char *osbundlerequired, int maxrecursion); grub_err_t grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target); grub_err_t grub_xnu_fill_devicetree (void); diff --git a/include/grub/zfs/dmu.h b/include/grub/zfs/dmu.h new file mode 100644 index 000000000..8fc6dc5b5 --- /dev/null +++ b/include/grub/zfs/dmu.h @@ -0,0 +1,120 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DMU_H +#define _SYS_DMU_H + +/* + * This file describes the interface that the DMU provides for its + * consumers. + * + * The DMU also interacts with the SPA. That interface is described in + * dmu_spa.h. + */ +typedef enum dmu_object_type { + DMU_OT_NONE, + /* general: */ + DMU_OT_OBJECT_DIRECTORY, /* ZAP */ + DMU_OT_OBJECT_ARRAY, /* UINT64 */ + DMU_OT_PACKED_NVLIST, /* UINT8 (XDR by nvlist_pack/unpack) */ + DMU_OT_PACKED_NVLIST_SIZE, /* UINT64 */ + DMU_OT_BPLIST, /* UINT64 */ + DMU_OT_BPLIST_HDR, /* UINT64 */ + /* spa: */ + DMU_OT_SPACE_MAP_HEADER, /* UINT64 */ + DMU_OT_SPACE_MAP, /* UINT64 */ + /* zil: */ + DMU_OT_INTENT_LOG, /* UINT64 */ + /* dmu: */ + DMU_OT_DNODE, /* DNODE */ + DMU_OT_OBJSET, /* OBJSET */ + /* dsl: */ + DMU_OT_DSL_DIR, /* UINT64 */ + DMU_OT_DSL_DIR_CHILD_MAP, /* ZAP */ + DMU_OT_DSL_DS_SNAP_MAP, /* ZAP */ + DMU_OT_DSL_PROPS, /* ZAP */ + DMU_OT_DSL_DATASET, /* UINT64 */ + /* zpl: */ + DMU_OT_ZNODE, /* ZNODE */ + DMU_OT_OLDACL, /* OLD ACL */ + DMU_OT_PLAIN_FILE_CONTENTS, /* UINT8 */ + DMU_OT_DIRECTORY_CONTENTS, /* ZAP */ + DMU_OT_MASTER_NODE, /* ZAP */ + DMU_OT_UNLINKED_SET, /* ZAP */ + /* zvol: */ + DMU_OT_ZVOL, /* UINT8 */ + DMU_OT_ZVOL_PROP, /* ZAP */ + /* other; for testing only! */ + DMU_OT_PLAIN_OTHER, /* UINT8 */ + DMU_OT_UINT64_OTHER, /* UINT64 */ + DMU_OT_ZAP_OTHER, /* ZAP */ + /* new object types: */ + DMU_OT_ERROR_LOG, /* ZAP */ + DMU_OT_SPA_HISTORY, /* UINT8 */ + DMU_OT_SPA_HISTORY_OFFSETS, /* spa_his_phys_t */ + DMU_OT_POOL_PROPS, /* ZAP */ + DMU_OT_DSL_PERMS, /* ZAP */ + DMU_OT_ACL, /* ACL */ + DMU_OT_SYSACL, /* SYSACL */ + DMU_OT_FUID, /* FUID table (Packed NVLIST UINT8) */ + DMU_OT_FUID_SIZE, /* FUID table size UINT64 */ + DMU_OT_NEXT_CLONES, /* ZAP */ + DMU_OT_SCRUB_QUEUE, /* ZAP */ + DMU_OT_USERGROUP_USED, /* ZAP */ + DMU_OT_USERGROUP_QUOTA, /* ZAP */ + DMU_OT_USERREFS, /* ZAP */ + DMU_OT_DDT_ZAP, /* ZAP */ + DMU_OT_DDT_STATS, /* ZAP */ + DMU_OT_SA, /* System attr */ + DMU_OT_SA_MASTER_NODE, /* ZAP */ + DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */ + DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */ + DMU_OT_DSL_KEYCHAIN = 54, + DMU_OT_NUMTYPES +} dmu_object_type_t; + +typedef enum dmu_objset_type { + DMU_OST_NONE, + DMU_OST_META, + DMU_OST_ZFS, + DMU_OST_ZVOL, + DMU_OST_OTHER, /* For testing only! */ + DMU_OST_ANY, /* Be careful! */ + DMU_OST_NUMTYPES +} dmu_objset_type_t; + +/* + * The names of zap entries in the DIRECTORY_OBJECT of the MOS. + */ +#define DMU_POOL_DIRECTORY_OBJECT 1 +#define DMU_POOL_CONFIG "config" +#define DMU_POOL_ROOT_DATASET "root_dataset" +#define DMU_POOL_SYNC_BPLIST "sync_bplist" +#define DMU_POOL_ERRLOG_SCRUB "errlog_scrub" +#define DMU_POOL_ERRLOG_LAST "errlog_last" +#define DMU_POOL_SPARES "spares" +#define DMU_POOL_DEFLATE "deflate" +#define DMU_POOL_HISTORY "history" +#define DMU_POOL_PROPS "pool_props" +#define DMU_POOL_L2CACHE "l2cache" + +#endif /* _SYS_DMU_H */ diff --git a/include/grub/zfs/dmu_objset.h b/include/grub/zfs/dmu_objset.h new file mode 100644 index 000000000..57d21db5c --- /dev/null +++ b/include/grub/zfs/dmu_objset.h @@ -0,0 +1,43 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. + * Copyright (C) 2010 Robert Millan + * + * 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 . + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DMU_OBJSET_H +#define _SYS_DMU_OBJSET_H + +#include + +#define OBJSET_PHYS_SIZE 2048 +#define OBJSET_PHYS_SIZE_V14 1024 + +typedef struct objset_phys { + dnode_phys_t os_meta_dnode; + zil_header_t os_zil_header; + grub_uint64_t os_type; + grub_uint64_t os_flags; + char os_pad[OBJSET_PHYS_SIZE - sizeof (dnode_phys_t)*3 - + sizeof (zil_header_t) - sizeof (grub_uint64_t)*2]; + dnode_phys_t os_userused_dnode; + dnode_phys_t os_groupused_dnode; +} objset_phys_t; + +#endif /* _SYS_DMU_OBJSET_H */ diff --git a/include/grub/zfs/dnode.h b/include/grub/zfs/dnode.h new file mode 100644 index 000000000..e4993df1e --- /dev/null +++ b/include/grub/zfs/dnode.h @@ -0,0 +1,74 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DNODE_H +#define _SYS_DNODE_H + +#include + +/* + * Fixed constants. + */ +#define DNODE_SHIFT 9 /* 512 bytes */ +#define DNODE_BLOCK_SHIFT 14 /* 16k */ +#define DNODE_CORE_SIZE 64 /* 64 bytes for dnode sans blkptrs */ + +/* + * Derived constants. + */ +#define DNODE_SIZE (1 << DNODE_SHIFT) +#define DN_MAX_NBLKPTR ((DNODE_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT) +#define DN_MAX_BONUSLEN (DNODE_SIZE - DNODE_CORE_SIZE - (1 << SPA_BLKPTRSHIFT)) + +#define DNODES_PER_BLOCK_SHIFT (DNODE_BLOCK_SHIFT - DNODE_SHIFT) +#define DNODES_PER_BLOCK (1ULL << DNODES_PER_BLOCK_SHIFT) + +#define DNODE_FLAG_SPILL_BLKPTR (1<<2) + +#define DN_BONUS(dnp) ((void*)((dnp)->dn_bonus + \ + (((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t)))) + +typedef struct dnode_phys { + grub_uint8_t dn_type; /* dmu_object_type_t */ + grub_uint8_t dn_indblkshift; /* ln2(indirect block size) */ + grub_uint8_t dn_nlevels; /* 1=dn_blkptr->data blocks */ + grub_uint8_t dn_nblkptr; /* length of dn_blkptr */ + grub_uint8_t dn_bonustype; /* type of data in bonus buffer */ + grub_uint8_t dn_checksum; /* ZIO_CHECKSUM type */ + grub_uint8_t dn_compress; /* ZIO_COMPRESS type */ + grub_uint8_t dn_flags; /* DNODE_FLAG_* */ + grub_uint16_t dn_datablkszsec; /* data block size in 512b sectors */ + grub_uint16_t dn_bonuslen; /* length of dn_bonus */ + grub_uint8_t dn_pad2[4]; + + /* accounting is protected by dn_dirty_mtx */ + grub_uint64_t dn_maxblkid; /* largest allocated block ID */ + grub_uint64_t dn_used; /* bytes (or sectors) of disk space */ + + grub_uint64_t dn_pad3[4]; + + blkptr_t dn_blkptr[1]; + grub_uint8_t dn_bonus[DN_MAX_BONUSLEN - sizeof (blkptr_t)]; + blkptr_t dn_spill; +} dnode_phys_t; + +#endif /* _SYS_DNODE_H */ diff --git a/include/grub/zfs/dsl_dataset.h b/include/grub/zfs/dsl_dataset.h new file mode 100644 index 000000000..c17bf801e --- /dev/null +++ b/include/grub/zfs/dsl_dataset.h @@ -0,0 +1,52 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DSL_DATASET_H +#define _SYS_DSL_DATASET_H + +typedef struct dsl_dataset_phys { + grub_uint64_t ds_dir_obj; + grub_uint64_t ds_prev_snap_obj; + grub_uint64_t ds_prev_snap_txg; + grub_uint64_t ds_next_snap_obj; + grub_uint64_t ds_snapnames_zapobj; /* zap obj of snaps; ==0 for snaps */ + grub_uint64_t ds_num_children; /* clone/snap children; ==0 for head */ + grub_uint64_t ds_creation_time; /* seconds since 1970 */ + grub_uint64_t ds_creation_txg; + grub_uint64_t ds_deadlist_obj; + grub_uint64_t ds_used_bytes; + grub_uint64_t ds_compressed_bytes; + grub_uint64_t ds_uncompressed_bytes; + grub_uint64_t ds_unique_bytes; /* only relevant to snapshots */ + /* + * The ds_fsid_guid is a 56-bit ID that can change to avoid + * collisions. The ds_guid is a 64-bit ID that will never + * change, so there is a small probability that it will collide. + */ + grub_uint64_t ds_fsid_guid; + grub_uint64_t ds_guid; + grub_uint64_t ds_flags; + blkptr_t ds_bp; + grub_uint64_t ds_pad[8]; /* pad out to 320 bytes for good measure */ +} dsl_dataset_phys_t; + +#endif /* _SYS_DSL_DATASET_H */ diff --git a/include/grub/zfs/dsl_dir.h b/include/grub/zfs/dsl_dir.h new file mode 100644 index 000000000..6542a77fe --- /dev/null +++ b/include/grub/zfs/dsl_dir.h @@ -0,0 +1,50 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_DSL_DIR_H +#define _SYS_DSL_DIR_H + +typedef struct dsl_dir_phys { + grub_uint64_t dd_creation_time; /* not actually used */ + grub_uint64_t dd_head_dataset_obj; + grub_uint64_t dd_parent_obj; + grub_uint64_t dd_clone_parent_obj; + grub_uint64_t dd_child_dir_zapobj; + /* + * how much space our children are accounting for; for leaf + * datasets, == physical space used by fs + snaps + */ + grub_uint64_t dd_used_bytes; + grub_uint64_t dd_compressed_bytes; + grub_uint64_t dd_uncompressed_bytes; + /* Administrative quota setting */ + grub_uint64_t dd_quota; + /* Administrative reservation setting */ + grub_uint64_t dd_reserved; + grub_uint64_t dd_props_zapobj; + grub_uint64_t dd_deleg_zapobj; /* dataset permissions */ + grub_uint64_t unused[7]; + grub_uint64_t keychain; + grub_uint64_t unused2[12]; +} dsl_dir_phys_t; + +#endif /* _SYS_DSL_DIR_H */ diff --git a/include/grub/zfs/sa_impl.h b/include/grub/zfs/sa_impl.h new file mode 100644 index 000000000..0845d1290 --- /dev/null +++ b/include/grub/zfs/sa_impl.h @@ -0,0 +1,37 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _SYS_SA_IMPL_H +#define _SYS_SA_IMPL_H + +typedef struct sa_hdr_phys { + grub_uint32_t sa_magic; + grub_uint16_t sa_layout_info; + grub_uint16_t sa_lengths[1]; +} sa_hdr_phys_t; + +#define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0) +#define SA_TYPE_OFFSET 0x0 +#define SA_SIZE_OFFSET 0x8 +#define SA_MTIME_OFFSET 0x38 +#define SA_SYMLINK_OFFSET 0xa0 + +#endif /* _SYS_SA_IMPL_H */ diff --git a/include/grub/zfs/spa.h b/include/grub/zfs/spa.h new file mode 100644 index 000000000..19a2b640a --- /dev/null +++ b/include/grub/zfs/spa.h @@ -0,0 +1,299 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2009 Free Software Foundation, Inc. + * Copyright 2010 Sun Microsystems, 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_ZFS_SPA_HEADER +#define GRUB_ZFS_SPA_HEADER 1 + +#define grub_zfs_to_cpu16(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_be_to_cpu16(x) \ + : grub_le_to_cpu16(x)) +#define grub_cpu_to_zfs16(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_cpu_to_be16(x) \ + : grub_cpu_to_le16(x)) + +#define grub_zfs_to_cpu32(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_be_to_cpu32(x) \ + : grub_le_to_cpu32(x)) +#define grub_cpu_to_zfs32(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_cpu_to_be32(x) \ + : grub_cpu_to_le32(x)) + +#define grub_zfs_to_cpu64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) \ + ? grub_be_to_cpu64(x) \ + : grub_le_to_cpu64(x)) +#define grub_cpu_to_zfs64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? grub_cpu_to_be64(x) \ + : grub_cpu_to_le64(x)) + +/* + * General-purpose 32-bit and 64-bit bitfield encodings. + */ +#define BF32_DECODE(x, low, len) P2PHASE((x) >> (low), 1U << (len)) +#define BF64_DECODE(x, low, len) P2PHASE((x) >> (low), 1ULL << (len)) +#define BF32_ENCODE(x, low, len) (P2PHASE((x), 1U << (len)) << (low)) +#define BF64_ENCODE(x, low, len) (P2PHASE((x), 1ULL << (len)) << (low)) + +#define BF32_GET(x, low, len) BF32_DECODE(x, low, len) +#define BF64_GET(x, low, len) BF64_DECODE(x, low, len) + +#define BF32_SET(x, low, len, val) \ + ((x) ^= BF32_ENCODE((x >> low) ^ (val), low, len)) +#define BF64_SET(x, low, len, val) \ + ((x) ^= BF64_ENCODE((x >> low) ^ (val), low, len)) + +#define BF32_GET_SB(x, low, len, shift, bias) \ + ((BF32_GET(x, low, len) + (bias)) << (shift)) +#define BF64_GET_SB(x, low, len, shift, bias) \ + ((BF64_GET(x, low, len) + (bias)) << (shift)) + +#define BF32_SET_SB(x, low, len, shift, bias, val) \ + BF32_SET(x, low, len, ((val) >> (shift)) - (bias)) +#define BF64_SET_SB(x, low, len, shift, bias, val) \ + BF64_SET(x, low, len, ((val) >> (shift)) - (bias)) + +#define SPA_MINBLOCKSHIFT 9 +#define SPA_MINBLOCKSIZE (1ULL << SPA_MINBLOCKSHIFT) + +/* + * Size of block to hold the configuration data (a packed nvlist) + */ +#define SPA_CONFIG_BLOCKSIZE (1 << 14) + +/* + * The DVA size encodings for LSIZE and PSIZE support blocks up to 32MB. + * The ASIZE encoding should be at least 64 times larger (6 more bits) + * to support up to 4-way RAID-Z mirror mode with worst-case gang block + * overhead, three DVAs per bp, plus one more bit in case we do anything + * else that expands the ASIZE. + */ +#define SPA_LSIZEBITS 16 /* LSIZE up to 32M (2^16 * 512) */ +#define SPA_PSIZEBITS 16 /* PSIZE up to 32M (2^16 * 512) */ +#define SPA_ASIZEBITS 24 /* ASIZE up to 64 times larger */ + +/* + * All SPA data is represented by 128-bit data virtual addresses (DVAs). + * The members of the dva_t should be considered opaque outside the SPA. + */ +typedef struct dva { + grub_uint64_t dva_word[2]; +} dva_t; + +/* + * Each block has a 256-bit checksum -- strong enough for cryptographic hashes. + */ +typedef struct zio_cksum { + grub_uint64_t zc_word[4]; +} zio_cksum_t; + +/* + * Each block is described by its DVAs, time of birth, checksum, etc. + * The word-by-word, bit-by-bit layout of the blkptr is as follows: + * + * 64 56 48 40 32 24 16 8 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 0 | vdev1 | GRID | ASIZE | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 1 |G| offset1 | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 2 | vdev2 | GRID | ASIZE | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 3 |G| offset2 | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 4 | vdev3 | GRID | ASIZE | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 5 |G| offset3 | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 6 |BDX|lvl| type | cksum | comp | PSIZE | LSIZE | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 7 | padding | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 8 | padding | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * 9 | physical birth txg | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * a | logical birth txg | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * b | fill count | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * c | checksum[0] | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * d | checksum[1] | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * e | checksum[2] | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * f | checksum[3] | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * Legend: + * + * vdev virtual device ID + * offset offset into virtual device + * LSIZE logical size + * PSIZE physical size (after compression) + * ASIZE allocated size (including RAID-Z parity and gang block headers) + * GRID RAID-Z layout information (reserved for future use) + * cksum checksum function + * comp compression function + * G gang block indicator + * B byteorder (endianness) + * D dedup + * X unused + * lvl level of indirection + * type DMU object type + * phys birth txg of block allocation; zero if same as logical birth txg + * log. birth transaction group in which the block was logically born + * fill count number of non-zero blocks under this bp + * checksum[4] 256-bit checksum of the data this bp describes + */ +#define SPA_BLKPTRSHIFT 7 /* blkptr_t is 128 bytes */ +#define SPA_DVAS_PER_BP 3 /* Number of DVAs in a bp */ + +typedef struct blkptr { + dva_t blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */ + grub_uint64_t blk_prop; /* size, compression, type, etc */ + grub_uint64_t blk_pad[2]; /* Extra space for the future */ + grub_uint64_t blk_phys_birth; /* txg when block was allocated */ + grub_uint64_t blk_birth; /* transaction group at birth */ + grub_uint64_t blk_fill; /* fill count */ + zio_cksum_t blk_cksum; /* 256-bit checksum */ +} blkptr_t; + +/* + * Macros to get and set fields in a bp or DVA. + */ +#define DVA_GET_ASIZE(dva) \ + BF64_GET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0) +#define DVA_SET_ASIZE(dva, x) \ + BF64_SET_SB((dva)->dva_word[0], 0, 24, SPA_MINBLOCKSHIFT, 0, x) + +#define DVA_GET_GRID(dva) BF64_GET((dva)->dva_word[0], 24, 8) +#define DVA_SET_GRID(dva, x) BF64_SET((dva)->dva_word[0], 24, 8, x) + +#define DVA_GET_VDEV(dva) BF64_GET((dva)->dva_word[0], 32, 32) +#define DVA_SET_VDEV(dva, x) BF64_SET((dva)->dva_word[0], 32, 32, x) + +#define DVA_GET_GANG(dva) BF64_GET((dva)->dva_word[1], 63, 1) +#define DVA_SET_GANG(dva, x) BF64_SET((dva)->dva_word[1], 63, 1, x) + +#define BP_GET_LSIZE(bp) \ + BF64_GET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1) +#define BP_SET_LSIZE(bp, x) \ + BF64_SET_SB((bp)->blk_prop, 0, 16, SPA_MINBLOCKSHIFT, 1, x) + +#define BP_GET_COMPRESS(bp) BF64_GET((bp)->blk_prop, 32, 8) +#define BP_SET_COMPRESS(bp, x) BF64_SET((bp)->blk_prop, 32, 8, x) + +#define BP_GET_CHECKSUM(bp) BF64_GET((bp)->blk_prop, 40, 8) +#define BP_SET_CHECKSUM(bp, x) BF64_SET((bp)->blk_prop, 40, 8, x) + +#define BP_GET_TYPE(bp) BF64_GET((bp)->blk_prop, 48, 8) +#define BP_SET_TYPE(bp, x) BF64_SET((bp)->blk_prop, 48, 8, x) + +#define BP_GET_LEVEL(bp) BF64_GET((bp)->blk_prop, 56, 5) +#define BP_SET_LEVEL(bp, x) BF64_SET((bp)->blk_prop, 56, 5, x) + +#define BP_GET_PROP_BIT_61(bp) BF64_GET((bp)->blk_prop, 61, 1) +#define BP_SET_PROP_BIT_61(bp, x) BF64_SET((bp)->blk_prop, 61, 1, x) + +#define BP_GET_DEDUP(bp) BF64_GET((bp)->blk_prop, 62, 1) +#define BP_SET_DEDUP(bp, x) BF64_SET((bp)->blk_prop, 62, 1, x) + +#define BP_GET_BYTEORDER(bp) (0 - BF64_GET((bp)->blk_prop, 63, 1)) +#define BP_SET_BYTEORDER(bp, x) BF64_SET((bp)->blk_prop, 63, 1, x) + +#define BP_PHYSICAL_BIRTH(bp) \ + ((bp)->blk_phys_birth ? (bp)->blk_phys_birth : (bp)->blk_birth) + +#define BP_SET_BIRTH(bp, logical, physical) \ +{ \ + (bp)->blk_birth = (logical); \ + (bp)->blk_phys_birth = ((logical) == (physical) ? 0 : (physical)); \ +} + +#define BP_GET_ASIZE(bp) \ + (DVA_GET_ASIZE(&(bp)->blk_dva[0]) + DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \ + DVA_GET_ASIZE(&(bp)->blk_dva[2])) + +#define BP_GET_UCSIZE(bp) \ + ((BP_GET_LEVEL(bp) > 0 || dmu_ot[BP_GET_TYPE(bp)].ot_metadata) ? \ + BP_GET_PSIZE(bp) : BP_GET_LSIZE(bp)); + +#define BP_GET_NDVAS(bp) \ + (!!DVA_GET_ASIZE(&(bp)->blk_dva[0]) + \ + !!DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \ + !!DVA_GET_ASIZE(&(bp)->blk_dva[2])) + +#define BP_COUNT_GANG(bp) \ + (DVA_GET_GANG(&(bp)->blk_dva[0]) + \ + DVA_GET_GANG(&(bp)->blk_dva[1]) + \ + DVA_GET_GANG(&(bp)->blk_dva[2])) + +#define DVA_EQUAL(dva1, dva2) \ + ((dva1)->dva_word[1] == (dva2)->dva_word[1] && \ + (dva1)->dva_word[0] == (dva2)->dva_word[0]) + +#define BP_EQUAL(bp1, bp2) \ + (BP_PHYSICAL_BIRTH(bp1) == BP_PHYSICAL_BIRTH(bp2) && \ + DVA_EQUAL(&(bp1)->blk_dva[0], &(bp2)->blk_dva[0]) && \ + DVA_EQUAL(&(bp1)->blk_dva[1], &(bp2)->blk_dva[1]) && \ + DVA_EQUAL(&(bp1)->blk_dva[2], &(bp2)->blk_dva[2])) + +#define ZIO_CHECKSUM_EQUAL(zc1, zc2) \ + (0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \ + ((zc1).zc_word[1] - (zc2).zc_word[1]) | \ + ((zc1).zc_word[2] - (zc2).zc_word[2]) | \ + ((zc1).zc_word[3] - (zc2).zc_word[3]))) + +#define DVA_IS_VALID(dva) (DVA_GET_ASIZE(dva) != 0) + +#define ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3) \ +{ \ + (zcp)->zc_word[0] = w0; \ + (zcp)->zc_word[1] = w1; \ + (zcp)->zc_word[2] = w2; \ + (zcp)->zc_word[3] = w3; \ +} + +#define BP_IDENTITY(bp) (&(bp)->blk_dva[0]) +#define BP_IS_GANG(bp) DVA_GET_GANG(BP_IDENTITY(bp)) +#define BP_IS_HOLE(bp) ((bp)->blk_birth == 0) + +/* BP_IS_RAIDZ(bp) assumes no block compression */ +#define BP_IS_RAIDZ(bp) (DVA_GET_ASIZE(&(bp)->blk_dva[0]) > \ + BP_GET_PSIZE(bp)) + +#define BP_ZERO(bp) \ +{ \ + (bp)->blk_dva[0].dva_word[0] = 0; \ + (bp)->blk_dva[0].dva_word[1] = 0; \ + (bp)->blk_dva[1].dva_word[0] = 0; \ + (bp)->blk_dva[1].dva_word[1] = 0; \ + (bp)->blk_dva[2].dva_word[0] = 0; \ + (bp)->blk_dva[2].dva_word[1] = 0; \ + (bp)->blk_prop = 0; \ + (bp)->blk_pad[0] = 0; \ + (bp)->blk_pad[1] = 0; \ + (bp)->blk_phys_birth = 0; \ + (bp)->blk_birth = 0; \ + (bp)->blk_fill = 0; \ + ZIO_SET_CHECKSUM(&(bp)->blk_cksum, 0, 0, 0, 0); \ +} + +#define BP_SPRINTF_LEN 320 + +#endif /* ! GRUB_ZFS_SPA_HEADER */ diff --git a/include/grub/zfs/uberblock_impl.h b/include/grub/zfs/uberblock_impl.h new file mode 100644 index 000000000..1bf7f2b07 --- /dev/null +++ b/include/grub/zfs/uberblock_impl.h @@ -0,0 +1,60 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_UBERBLOCK_IMPL_H +#define _SYS_UBERBLOCK_IMPL_H + +/* + * The uberblock version is incremented whenever an incompatible on-disk + * format change is made to the SPA, DMU, or ZAP. + * + * Note: the first two fields should never be moved. When a storage pool + * is opened, the uberblock must be read off the disk before the version + * can be checked. If the ub_version field is moved, we may not detect + * version mismatch. If the ub_magic field is moved, applications that + * expect the magic number in the first word won't work. + */ +#define UBERBLOCK_MAGIC 0x00bab10c /* oo-ba-bloc! */ +#define UBERBLOCK_SHIFT 10 /* up to 1K */ + +typedef struct uberblock { + grub_uint64_t ub_magic; /* UBERBLOCK_MAGIC */ + grub_uint64_t ub_version; /* ZFS_VERSION */ + grub_uint64_t ub_txg; /* txg of last sync */ + grub_uint64_t ub_guid_sum; /* sum of all vdev guids */ + grub_uint64_t ub_timestamp; /* UTC time of last sync */ + blkptr_t ub_rootbp; /* MOS objset_phys_t */ +} uberblock_t; + +#define UBERBLOCK_SIZE (1ULL << UBERBLOCK_SHIFT) +#define VDEV_UBERBLOCK_SHIFT UBERBLOCK_SHIFT + +/* XXX Uberblock_phys_t is no longer in the kernel zfs */ +typedef struct uberblock_phys { + uberblock_t ubp_uberblock; + char ubp_pad[UBERBLOCK_SIZE - sizeof (uberblock_t) - + sizeof (zio_eck_t)]; + zio_eck_t ubp_zec; +} uberblock_phys_t; + + +#endif /* _SYS_UBERBLOCK_IMPL_H */ diff --git a/include/grub/zfs/vdev_impl.h b/include/grub/zfs/vdev_impl.h new file mode 100644 index 000000000..9b5f0a7a8 --- /dev/null +++ b/include/grub/zfs/vdev_impl.h @@ -0,0 +1,69 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_VDEV_IMPL_H +#define _SYS_VDEV_IMPL_H + +#define VDEV_SKIP_SIZE (8 << 10) +#define VDEV_BOOT_HEADER_SIZE (8 << 10) +#define VDEV_PHYS_SIZE (112 << 10) +#define VDEV_UBERBLOCK_RING (128 << 10) + +/* ZFS boot block */ +#define VDEV_BOOT_MAGIC 0x2f5b007b10cULL +#define VDEV_BOOT_VERSION 1 /* version number */ + +typedef struct vdev_boot_header { + grub_uint64_t vb_magic; /* VDEV_BOOT_MAGIC */ + grub_uint64_t vb_version; /* VDEV_BOOT_VERSION */ + grub_uint64_t vb_offset; /* start offset (bytes) */ + grub_uint64_t vb_size; /* size (bytes) */ + char vb_pad[VDEV_BOOT_HEADER_SIZE - 4 * sizeof (grub_uint64_t)]; +} vdev_boot_header_t; + +typedef struct vdev_phys { + char vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)]; + zio_eck_t vp_zbt; +} vdev_phys_t; + +typedef struct vdev_label { + char vl_pad[VDEV_SKIP_SIZE]; /* 8K */ + vdev_boot_header_t vl_boot_header; /* 8K */ + vdev_phys_t vl_vdev_phys; /* 112K */ + char vl_uberblock[VDEV_UBERBLOCK_RING]; /* 128K */ +} vdev_label_t; /* 256K total */ + +/* + * Size and offset of embedded boot loader region on each label. + * The total size of the first two labels plus the boot area is 4MB. + */ +#define VDEV_BOOT_OFFSET (2 * sizeof (vdev_label_t)) +#define VDEV_BOOT_SIZE (7ULL << 19) /* 3.5M */ + +/* + * Size of label regions at the start and end of each leaf device. + */ +#define VDEV_LABEL_START_SIZE (2 * sizeof (vdev_label_t) + VDEV_BOOT_SIZE) +#define VDEV_LABEL_END_SIZE (2 * sizeof (vdev_label_t)) +#define VDEV_LABELS 4 + +#endif /* _SYS_VDEV_IMPL_H */ diff --git a/include/grub/zfs/zap_impl.h b/include/grub/zfs/zap_impl.h new file mode 100644 index 000000000..0e985d9f9 --- /dev/null +++ b/include/grub/zfs/zap_impl.h @@ -0,0 +1,109 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_ZAP_IMPL_H +#define _SYS_ZAP_IMPL_H + +#define ZAP_MAGIC 0x2F52AB2ABULL + +#define ZAP_HASHBITS 28 +#define MZAP_ENT_LEN 64 +#define MZAP_NAME_LEN (MZAP_ENT_LEN - 8 - 4 - 2) + +typedef struct mzap_ent_phys { + grub_uint64_t mze_value; + grub_uint32_t mze_cd; + grub_uint16_t mze_pad; /* in case we want to chain them someday */ + char mze_name[MZAP_NAME_LEN]; +} mzap_ent_phys_t; + +typedef struct mzap_phys { + grub_uint64_t mz_block_type; /* ZBT_MICRO */ + grub_uint64_t mz_salt; + grub_uint64_t mz_pad[6]; + mzap_ent_phys_t mz_chunk[1]; + /* actually variable size depending on block size */ +} mzap_phys_t; + +/* + * The (fat) zap is stored in one object. It is an array of + * 1<= 6] [zap_leaf_t] [ptrtbl] ... + * + */ + +#define ZBT_LEAF ((1ULL << 63) + 0) +#define ZBT_HEADER ((1ULL << 63) + 1) +#define ZBT_MICRO ((1ULL << 63) + 3) +/* any other values are ptrtbl blocks */ + +/* + * the embedded pointer table takes up half a block: + * block size / entry size (2^3) / 2 + */ +#define ZAP_EMBEDDED_PTRTBL_SHIFT(zap) (FZAP_BLOCK_SHIFT(zap) - 3 - 1) + +/* + * The embedded pointer table starts half-way through the block. Since + * the pointer table itself is half the block, it starts at (64-bit) + * word number (1<zap_f.zap_phys) \ + [(idx) + (1<. + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_ZAP_LEAF_H +#define _SYS_ZAP_LEAF_H + +#define ZAP_LEAF_MAGIC 0x2AB1EAF + +/* chunk size = 24 bytes */ +#define ZAP_LEAF_CHUNKSIZE 24 + +/* + * The amount of space within the chunk available for the array is: + * chunk size - space for type (1) - space for next pointer (2) + */ +#define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3) + +typedef enum zap_chunk_type { + ZAP_CHUNK_FREE = 253, + ZAP_CHUNK_ENTRY = 252, + ZAP_CHUNK_ARRAY = 251, + ZAP_CHUNK_TYPE_MAX = 250 +} zap_chunk_type_t; + +/* + * TAKE NOTE: + * If zap_leaf_phys_t is modified, zap_leaf_byteswap() must be modified. + */ +typedef struct zap_leaf_phys { + struct zap_leaf_header { + grub_uint64_t lh_block_type; /* ZBT_LEAF */ + grub_uint64_t lh_pad1; + grub_uint64_t lh_prefix; /* hash prefix of this leaf */ + grub_uint32_t lh_magic; /* ZAP_LEAF_MAGIC */ + grub_uint16_t lh_nfree; /* number free chunks */ + grub_uint16_t lh_nentries; /* number of entries */ + grub_uint16_t lh_prefix_len; /* num bits used to id this */ + +/* above is accessable to zap, below is zap_leaf private */ + + grub_uint16_t lh_freelist; /* chunk head of free list */ + grub_uint8_t lh_pad2[12]; + } l_hdr; /* 2 24-byte chunks */ + + /* + * The header is followed by a hash table with + * ZAP_LEAF_HASH_NUMENTRIES(zap) entries. The hash table is + * followed by an array of ZAP_LEAF_NUMCHUNKS(zap) + * zap_leaf_chunk structures. These structures are accessed + * with the ZAP_LEAF_CHUNK() macro. + */ + + grub_uint16_t l_hash[0]; + grub_properly_aligned_t l_entries[0]; +} zap_leaf_phys_t; + +typedef union zap_leaf_chunk { + struct zap_leaf_entry { + grub_uint8_t le_type; /* always ZAP_CHUNK_ENTRY */ + grub_uint8_t le_int_size; /* size of ints */ + grub_uint16_t le_next; /* next entry in hash chain */ + grub_uint16_t le_name_chunk; /* first chunk of the name */ + grub_uint16_t le_name_length; /* bytes in name, incl null */ + grub_uint16_t le_value_chunk; /* first chunk of the value */ + grub_uint16_t le_value_length; /* value length in ints */ + grub_uint32_t le_cd; /* collision differentiator */ + grub_uint64_t le_hash; /* hash value of the name */ + } l_entry; + struct zap_leaf_array { + grub_uint8_t la_type; /* always ZAP_CHUNK_ARRAY */ + union + { + grub_uint8_t la_array[ZAP_LEAF_ARRAY_BYTES]; + grub_uint64_t la_array64; + } __attribute__ ((packed)); + grub_uint16_t la_next; /* next blk or CHAIN_END */ + } l_array; + struct zap_leaf_free { + grub_uint8_t lf_type; /* always ZAP_CHUNK_FREE */ + grub_uint8_t lf_pad[ZAP_LEAF_ARRAY_BYTES]; + grub_uint16_t lf_next; /* next in free list, or CHAIN_END */ + } l_free; +} zap_leaf_chunk_t; + +#endif /* _SYS_ZAP_LEAF_H */ diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h new file mode 100644 index 000000000..e326c8b2f --- /dev/null +++ b/include/grub/zfs/zfs.h @@ -0,0 +1,153 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,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 . + */ + /* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef GRUB_ZFS_HEADER +#define GRUB_ZFS_HEADER 1 + +#include +#include +#include + +typedef enum grub_zfs_endian + { + GRUB_ZFS_UNKNOWN_ENDIAN = -2, + GRUB_ZFS_LITTLE_ENDIAN = -1, + GRUB_ZFS_BIG_ENDIAN = 0 + } grub_zfs_endian_t; + +/* + * On-disk version number. + */ +#define SPA_VERSION 33ULL + +/* + * The following are configuration names used in the nvlist describing a pool's + * configuration. + */ +#define ZPOOL_CONFIG_VERSION "version" +#define ZPOOL_CONFIG_POOL_NAME "name" +#define ZPOOL_CONFIG_POOL_STATE "state" +#define ZPOOL_CONFIG_POOL_TXG "txg" +#define ZPOOL_CONFIG_POOL_GUID "pool_guid" +#define ZPOOL_CONFIG_CREATE_TXG "create_txg" +#define ZPOOL_CONFIG_TOP_GUID "top_guid" +#define ZPOOL_CONFIG_VDEV_TREE "vdev_tree" +#define ZPOOL_CONFIG_TYPE "type" +#define ZPOOL_CONFIG_CHILDREN "children" +#define ZPOOL_CONFIG_ID "id" +#define ZPOOL_CONFIG_GUID "guid" +#define ZPOOL_CONFIG_PATH "path" +#define ZPOOL_CONFIG_DEVID "devid" +#define ZPOOL_CONFIG_METASLAB_ARRAY "metaslab_array" +#define ZPOOL_CONFIG_METASLAB_SHIFT "metaslab_shift" +#define ZPOOL_CONFIG_ASHIFT "ashift" +#define ZPOOL_CONFIG_ASIZE "asize" +#define ZPOOL_CONFIG_DTL "DTL" +#define ZPOOL_CONFIG_STATS "stats" +#define ZPOOL_CONFIG_WHOLE_DISK "whole_disk" +#define ZPOOL_CONFIG_ERRCOUNT "error_count" +#define ZPOOL_CONFIG_NOT_PRESENT "not_present" +#define ZPOOL_CONFIG_SPARES "spares" +#define ZPOOL_CONFIG_IS_SPARE "is_spare" +#define ZPOOL_CONFIG_NPARITY "nparity" +#define ZPOOL_CONFIG_PHYS_PATH "phys_path" +#define ZPOOL_CONFIG_L2CACHE "l2cache" +#define ZPOOL_CONFIG_HOLE_ARRAY "hole_array" +#define ZPOOL_CONFIG_VDEV_CHILDREN "vdev_children" +#define ZPOOL_CONFIG_IS_HOLE "is_hole" +#define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram" +#define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats" +#define ZPOOL_CONFIG_DDT_STATS "ddt_stats" +/* + * The persistent vdev state is stored as separate values rather than a single + * 'vdev_state' entry. This is because a device can be in multiple states, such + * as offline and degraded. + */ +#define ZPOOL_CONFIG_OFFLINE "offline" +#define ZPOOL_CONFIG_FAULTED "faulted" +#define ZPOOL_CONFIG_DEGRADED "degraded" +#define ZPOOL_CONFIG_REMOVED "removed" + +#define VDEV_TYPE_ROOT "root" +#define VDEV_TYPE_MIRROR "mirror" +#define VDEV_TYPE_REPLACING "replacing" +#define VDEV_TYPE_RAIDZ "raidz" +#define VDEV_TYPE_DISK "disk" +#define VDEV_TYPE_FILE "file" +#define VDEV_TYPE_MISSING "missing" +#define VDEV_TYPE_HOLE "hole" +#define VDEV_TYPE_SPARE "spare" +#define VDEV_TYPE_L2CACHE "l2cache" + +/* + * pool state. The following states are written to disk as part of the normal + * SPA lifecycle: ACTIVE, EXPORTED, DESTROYED, SPARE, L2CACHE. The remaining + * states are software abstractions used at various levels to communicate pool + * state. + */ +typedef enum pool_state { + POOL_STATE_ACTIVE = 0, /* In active use */ + POOL_STATE_EXPORTED, /* Explicitly exported */ + POOL_STATE_DESTROYED, /* Explicitly destroyed */ + POOL_STATE_SPARE, /* Reserved for hot spare use */ + POOL_STATE_L2CACHE, /* Level 2 ARC device */ + POOL_STATE_UNINITIALIZED, /* Internal spa_t state */ + POOL_STATE_UNAVAIL, /* Internal libzfs state */ + POOL_STATE_POTENTIALLY_ACTIVE /* Internal libzfs state */ +} pool_state_t; + +struct grub_zfs_data; + +grub_err_t grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist); +grub_err_t grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename, + grub_uint64_t *mdnobj); + +char *grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name); +char *grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name); +int grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name, + grub_uint64_t *out); +char *grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, + const char *name, + grub_size_t index); +int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist, + const char *name); +grub_err_t +grub_zfs_add_key (grub_uint8_t *key_in, + grub_size_t keylen, + int passphrase); + +extern grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher, + grub_uint64_t algo, + void *nonce, + char *buf, grub_size_t size, + const grub_uint32_t *expected_mac, + grub_zfs_endian_t endian); + +struct grub_zfs_key; + +extern grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key, + grub_size_t keysize, + grub_uint64_t salt, + grub_uint64_t algo); + + + +#endif /* ! GRUB_ZFS_HEADER */ diff --git a/include/grub/zfs/zfs_acl.h b/include/grub/zfs/zfs_acl.h new file mode 100644 index 000000000..277738279 --- /dev/null +++ b/include/grub/zfs/zfs_acl.h @@ -0,0 +1,59 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_FS_ZFS_ACL_H +#define _SYS_FS_ZFS_ACL_H + +#ifndef _UID_T +#define _UID_T +typedef unsigned int uid_t; /* UID type */ +#endif /* _UID_T */ + +typedef struct zfs_oldace { + grub_uint32_t z_fuid; /* "who" */ + grub_uint32_t z_access_mask; /* access mask */ + grub_uint16_t z_flags; /* flags, i.e inheritance */ + grub_uint16_t z_type; /* type of entry allow/deny */ +} zfs_oldace_t; + +#define ACE_SLOT_CNT 6 + +typedef struct zfs_znode_acl_v0 { + grub_uint64_t z_acl_extern_obj; /* ext acl pieces */ + grub_uint32_t z_acl_count; /* Number of ACEs */ + grub_uint16_t z_acl_version; /* acl version */ + grub_uint16_t z_acl_pad; /* pad */ + zfs_oldace_t z_ace_data[ACE_SLOT_CNT]; /* 6 standard ACEs */ +} zfs_znode_acl_v0_t; + +#define ZFS_ACE_SPACE (sizeof (zfs_oldace_t) * ACE_SLOT_CNT) + +typedef struct zfs_znode_acl { + grub_uint64_t z_acl_extern_obj; /* ext acl pieces */ + grub_uint32_t z_acl_size; /* Number of bytes in ACL */ + grub_uint16_t z_acl_version; /* acl version */ + grub_uint16_t z_acl_count; /* ace count */ + grub_uint8_t z_ace_data[ZFS_ACE_SPACE]; /* space for embedded ACEs */ +} zfs_znode_acl_t; + + +#endif /* _SYS_FS_ZFS_ACL_H */ diff --git a/include/grub/zfs/zfs_znode.h b/include/grub/zfs/zfs_znode.h new file mode 100644 index 000000000..efd6d10a6 --- /dev/null +++ b/include/grub/zfs/zfs_znode.h @@ -0,0 +1,70 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_FS_ZFS_ZNODE_H +#define _SYS_FS_ZFS_ZNODE_H + +#include + +#define MASTER_NODE_OBJ 1 +#define ZFS_ROOT_OBJ "ROOT" +#define ZPL_VERSION_STR "VERSION" +#define ZFS_SA_ATTRS "SA_ATTRS" + +#define ZPL_VERSION 5ULL + +#define ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48) + +/* + * This is the persistent portion of the znode. It is stored + * in the "bonus buffer" of the file. Short symbolic links + * are also stored in the bonus buffer. + */ +typedef struct znode_phys { + grub_uint64_t zp_atime[2]; /* 0 - last file access time */ + grub_uint64_t zp_mtime[2]; /* 16 - last file modification time */ + grub_uint64_t zp_ctime[2]; /* 32 - last file change time */ + grub_uint64_t zp_crtime[2]; /* 48 - creation time */ + grub_uint64_t zp_gen; /* 64 - generation (txg of creation) */ + grub_uint64_t zp_mode; /* 72 - file mode bits */ + grub_uint64_t zp_size; /* 80 - size of file */ + grub_uint64_t zp_parent; /* 88 - directory parent (`..') */ + grub_uint64_t zp_links; /* 96 - number of links to file */ + grub_uint64_t zp_xattr; /* 104 - DMU object for xattrs */ + grub_uint64_t zp_rdev; /* 112 - dev_t for VBLK & VCHR files */ + grub_uint64_t zp_flags; /* 120 - persistent flags */ + grub_uint64_t zp_uid; /* 128 - file owner */ + grub_uint64_t zp_gid; /* 136 - owning group */ + grub_uint64_t zp_pad[4]; /* 144 - future */ + zfs_znode_acl_t zp_acl; /* 176 - 263 ACL */ + /* + * Data may pad out any remaining bytes in the znode buffer, eg: + * + * |<---------------------- dnode_phys (512) ------------------------>| + * |<-- dnode (192) --->|<----------- "bonus" buffer (320) ---------->| + * |<---- znode (264) ---->|<---- data (56) ---->| + * + * At present, we only use this space to store symbolic links. + */ +} znode_phys_t; + +#endif /* _SYS_FS_ZFS_ZNODE_H */ diff --git a/include/grub/zfs/zil.h b/include/grub/zfs/zil.h new file mode 100644 index 000000000..45d16f402 --- /dev/null +++ b/include/grub/zfs/zil.h @@ -0,0 +1,56 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_ZIL_H +#define _SYS_ZIL_H + +/* + * Intent log format: + * + * Each objset has its own intent log. The log header (zil_header_t) + * for objset N's intent log is kept in the Nth object of the SPA's + * intent_log objset. The log header points to a chain of log blocks, + * each of which contains log records (i.e., transactions) followed by + * a log block trailer (zil_trailer_t). The format of a log record + * depends on the record (or transaction) type, but all records begin + * with a common structure that defines the type, length, and txg. + */ + +/* + * Intent log header - this on disk structure holds fields to manage + * the log. All fields are 64 bit to easily handle cross architectures. + */ +typedef struct zil_header { + grub_uint64_t zh_claim_txg; /* txg in which log blocks were claimed */ + grub_uint64_t zh_replay_seq; /* highest replayed sequence number */ + blkptr_t zh_log; /* log chain */ + grub_uint64_t zh_claim_seq; /* highest claimed sequence number */ + grub_uint64_t zh_flags; /* header flags */ + grub_uint64_t zh_pad[4]; +} zil_header_t; + +/* + * zh_flags bit settings + */ +#define ZIL_REPLAY_NEEDED 0x1 /* replay needed - internal only */ + +#endif /* _SYS_ZIL_H */ diff --git a/include/grub/zfs/zio.h b/include/grub/zfs/zio.h new file mode 100644 index 000000000..b1c46da3a --- /dev/null +++ b/include/grub/zfs/zio.h @@ -0,0 +1,94 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _ZIO_H +#define _ZIO_H + +#include + +#define ZEC_MAGIC 0x210da7ab10c7a11ULL /* zio data bloc tail */ + +typedef struct zio_eck { + grub_uint64_t zec_magic; /* for validation, endianness */ + zio_cksum_t zec_cksum; /* 256-bit checksum */ +} __attribute__ ((packed)) zio_eck_t; + +/* + * Gang block headers are self-checksumming and contain an array + * of block pointers. + */ +#define SPA_GANGBLOCKSIZE SPA_MINBLOCKSIZE +#define SPA_GBH_NBLKPTRS ((SPA_GANGBLOCKSIZE - \ + sizeof (zio_eck_t)) / sizeof (blkptr_t)) +#define SPA_GBH_FILLER ((SPA_GANGBLOCKSIZE - \ + sizeof (zio_eck_t) - \ + (SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\ + sizeof (grub_uint64_t)) + +#define ZIO_GET_IOSIZE(zio) \ + (BP_IS_GANG((zio)->io_bp) ? \ + SPA_GANGBLOCKSIZE : BP_GET_PSIZE((zio)->io_bp)) + +typedef struct zio_gbh { + blkptr_t zg_blkptr[SPA_GBH_NBLKPTRS]; + grub_uint64_t zg_filler[SPA_GBH_FILLER]; + zio_eck_t zg_tail; +} zio_gbh_phys_t; + +enum zio_checksum { + ZIO_CHECKSUM_INHERIT = 0, + ZIO_CHECKSUM_ON, + ZIO_CHECKSUM_OFF, + ZIO_CHECKSUM_LABEL, + ZIO_CHECKSUM_GANG_HEADER, + ZIO_CHECKSUM_ZILOG, + ZIO_CHECKSUM_FLETCHER_2, + ZIO_CHECKSUM_FLETCHER_4, + ZIO_CHECKSUM_SHA256, + ZIO_CHECKSUM_ZILOG2, + ZIO_CHECKSUM_SHA256_MAC, + ZIO_CHECKSUM_FUNCTIONS +}; + +#define ZIO_CHECKSUM_ON_VALUE ZIO_CHECKSUM_FLETCHER_2 +#define ZIO_CHECKSUM_DEFAULT ZIO_CHECKSUM_ON + +enum zio_compress { + ZIO_COMPRESS_INHERIT = 0, + ZIO_COMPRESS_ON, + ZIO_COMPRESS_OFF, + ZIO_COMPRESS_LZJB, + ZIO_COMPRESS_EMPTY, + ZIO_COMPRESS_GZIP1, + ZIO_COMPRESS_GZIP2, + ZIO_COMPRESS_GZIP3, + ZIO_COMPRESS_GZIP4, + ZIO_COMPRESS_GZIP5, + ZIO_COMPRESS_GZIP6, + ZIO_COMPRESS_GZIP7, + ZIO_COMPRESS_GZIP8, + ZIO_COMPRESS_GZIP9, + ZIO_COMPRESS_ZLE, + ZIO_COMPRESS_FUNCTIONS +}; + +#endif /* _ZIO_H */ diff --git a/include/grub/zfs/zio_checksum.h b/include/grub/zfs/zio_checksum.h new file mode 100644 index 000000000..e03c85a83 --- /dev/null +++ b/include/grub/zfs/zio_checksum.h @@ -0,0 +1,33 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004 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 . + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_ZIO_CHECKSUM_H +#define _SYS_ZIO_CHECKSUM_H + +extern void zio_checksum_SHA256 (const void *, grub_uint64_t, + grub_zfs_endian_t endian, zio_cksum_t *); +extern void fletcher_2 (const void *, grub_uint64_t, grub_zfs_endian_t endian, + zio_cksum_t *); +extern void fletcher_4 (const void *, grub_uint64_t, grub_zfs_endian_t endian, + zio_cksum_t *); + +#endif /* _SYS_ZIO_CHECKSUM_H */ diff --git a/po/Makefile.in.in b/po/Makefile.in.in index d0af6c962..5a7c07c5b 100644 --- a/po/Makefile.in.in +++ b/po/Makefile.in.in @@ -165,7 +165,7 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in $(srcdir)/POTFILES-shell --package-version='@VERSION@' \ --msgid-bugs-address="$$msgid_bugs_address" \ ;; \ - esac + esac; \ case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \ '' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ @@ -173,7 +173,8 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in $(srcdir)/POTFILES-shell --files-from=$(srcdir)/POTFILES-shell.in \ --copyright-holder='$(COPYRIGHT_HOLDER)' \ --msgid-bugs-address="$$msgid_bugs_address" \ - --join-existing --language=Shell --keyword=gettext_quoted \ + --join-existing --language=Shell \ + --keyword=gettext_quoted --keyword=gettext_printf \ ;; \ *) \ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ @@ -183,10 +184,13 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in $(srcdir)/POTFILES-shell --package-name="$${package_gnu}@PACKAGE@" \ --package-version='@VERSION@' \ --msgid-bugs-address="$$msgid_bugs_address" \ - --join-existing --language=Shell --keyword=gettext_quoted \ + --join-existing --language=Shell \ + --keyword=gettext_quoted --keyword=gettext_printf \ ;; \ - esac + esac ; \ test ! -f $(DOMAIN).po || { \ + sed -f grub.d.sed < $(DOMAIN).po > $(DOMAIN).1po && \ + mv $(DOMAIN).1po $(DOMAIN).po; \ if test -f $(srcdir)/$(DOMAIN).pot; then \ sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 8329fdf0a..6f352148a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,117 +1,563 @@ -# List of files which contain translatable strings. -grub-core/commands/acpi.c -grub-core/commands/blocklist.c -grub-core/commands/boot.c -grub-core/commands/cat.c -grub-core/commands/cmp.c -grub-core/commands/configfile.c -grub-core/commands/date.c -grub-core/commands/echo.c -grub-core/commands/efi/fixvideo.c -grub-core/commands/efi/loadbios.c -grub-core/commands/gptsync.c -grub-core/commands/halt.c -grub-core/commands/hashsum.c -grub-core/commands/hdparm.c -grub-core/commands/help.c -grub-core/commands/hexdump.c -grub-core/commands/i386/cpuid.c -grub-core/commands/i386/pc/drivemap.c -grub-core/commands/i386/pc/halt.c -grub-core/commands/i386/pc/lsapm.c -grub-core/commands/i386/pc/play.c -grub-core/commands/i386/pc/pxecmd.c -grub-core/commands/ieee1275/suspend.c -grub-core/commands/iorw.c -grub-core/commands/keylayouts.c -grub-core/commands/keystatus.c -grub-core/commands/legacycfg.c -grub-core/commands/loadenv.c -grub-core/commands/ls.c -grub-core/commands/lsacpi.c -grub-core/commands/lsmmap.c -grub-core/commands/lspci.c -grub-core/commands/memrw.c -grub-core/commands/menuentry.c -grub-core/commands/minicmd.c -grub-core/commands/parttool.c -grub-core/commands/password.c -grub-core/commands/password_pbkdf2.c -grub-core/commands/probe.c -grub-core/commands/read.c -grub-core/commands/reboot.c -grub-core/commands/regexp.c -grub-core/commands/search.c -grub-core/commands/search_file.c -grub-core/commands/search_label.c -grub-core/commands/search_uuid.c -grub-core/commands/search_wrap.c -grub-core/commands/setpci.c -grub-core/commands/sleep.c -grub-core/commands/terminal.c -grub-core/commands/test.c -grub-core/commands/testload.c -grub-core/commands/true.c -grub-core/commands/usbtest.c -grub-core/commands/videoinfo.c -grub-core/commands/videotest.c -grub-core/commands/xnu_uuid.c - -grub-core/disk/loopback.c - -grub-core/efiemu/main.c - -grub-core/font/font_cmd.c - -grub-core/gettext/gettext.c - -grub-core/gfxmenu/gui_progress_bar.c - -grub-core/hello/hello.c - -grub-core/kern/corecmd.c -grub-core/kern/emu/hostdisk.c -grub-core/kern/emu/misc.c -grub-core/kern/err.c - -grub-core/lib/arg.c - -grub-core/loader/efi/appleloader.c -grub-core/loader/efi/chainloader.c -grub-core/loader/i386/bsd.c -grub-core/loader/i386/linux.c -grub-core/loader/i386/pc/chainloader.c -grub-core/loader/i386/pc/linux.c -grub-core/loader/i386/pc/ntldr.c -grub-core/loader/i386/xnu.c -grub-core/loader/mips/linux.c -grub-core/loader/multiboot.c -grub-core/loader/powerpc/ieee1275/linux.c -grub-core/loader/sparc64/ieee1275/linux.c -grub-core/loader/xnu.c - -grub-core/mmap/mmap.c - -grub-core/normal/auth.c -grub-core/normal/cmdline.c -grub-core/normal/color.c -grub-core/normal/context.c -grub-core/normal/dyncmd.c -grub-core/normal/main.c -grub-core/normal/menu.c -grub-core/normal/menu_entry.c -grub-core/normal/menu_text.c -grub-core/normal/misc.c - -grub-core/script/main.c - -grub-core/term/gfxterm.c -grub-core/term/serial.c -grub-core/term/terminfo.c - -grub-core/tests/test_blockarg.c - -util/grub-editenv.c -util/grub-fstest.c -util/grub-mkimage.c -util/grub-setup.c +./grub-core/boot/decompressor/minilib.c +./grub-core/boot/decompressor/none.c +./grub-core/boot/decompressor/xz.c +./grub-core/bus/bonito.c +./grub-core/bus/cs5536.c +./grub-core/bus/emu/pci.c +./grub-core/bus/pci.c +./grub-core/bus/usb/emu/usb.c +./grub-core/bus/usb/ohci.c +./grub-core/bus/usb/serial/common.c +./grub-core/bus/usb/serial/ftdi.c +./grub-core/bus/usb/serial/pl2303.c +./grub-core/bus/usb/uhci.c +./grub-core/bus/usb/usb.c +./grub-core/bus/usb/usbhub.c +./grub-core/bus/usb/usbtrans.c +./grub-core/commands/acpi.c +./grub-core/commands/acpihalt.c +./grub-core/commands/arc/lsdev.c +./grub-core/commands/blocklist.c +./grub-core/commands/boot.c +./grub-core/commands/cacheinfo.c +./grub-core/commands/cat.c +./grub-core/commands/cmp.c +./grub-core/commands/configfile.c +./grub-core/commands/date.c +./grub-core/commands/echo.c +./grub-core/commands/efi/acpi.c +./grub-core/commands/efi/fixvideo.c +./grub-core/commands/efi/loadbios.c +./grub-core/commands/efi/lsefimmap.c +./grub-core/commands/efi/lsefisystab.c +./grub-core/commands/efi/lssal.c +./grub-core/commands/extcmd.c +./grub-core/commands/gptsync.c +./grub-core/commands/halt.c +./grub-core/commands/hashsum.c +./grub-core/commands/hdparm.c +./grub-core/commands/help.c +./grub-core/commands/hexdump.c +./grub-core/commands/i386/cmostest.c +./grub-core/commands/i386/cpuid.c +./grub-core/commands/i386/pc/acpi.c +./grub-core/commands/i386/pc/drivemap.c +./grub-core/commands/i386/pc/halt.c +./grub-core/commands/i386/pc/lsapm.c +./grub-core/commands/i386/pc/play.c +./grub-core/commands/i386/pc/sendkey.c +./grub-core/commands/ieee1275/suspend.c +./grub-core/commands/iorw.c +./grub-core/commands/keylayouts.c +./grub-core/commands/keystatus.c +./grub-core/commands/legacycfg.c +./grub-core/commands/loadenv.c +./grub-core/commands/lsacpi.c +./grub-core/commands/ls.c +./grub-core/commands/lsmmap.c +./grub-core/commands/lspci.c +./grub-core/commands/memrw.c +./grub-core/commands/menuentry.c +./grub-core/commands/minicmd.c +./grub-core/commands/mips/loongson/lsspd.c +./grub-core/commands/parttool.c +./grub-core/commands/password.c +./grub-core/commands/password_pbkdf2.c +./grub-core/commands/probe.c +./grub-core/commands/read.c +./grub-core/commands/reboot.c +./grub-core/commands/regexp.c +./grub-core/commands/search.c +./grub-core/commands/search_file.c +./grub-core/commands/search_label.c +./grub-core/commands/search_uuid.c +./grub-core/commands/search_wrap.c +./grub-core/commands/setpci.c +./grub-core/commands/sleep.c +./grub-core/commands/terminal.c +./grub-core/commands/test.c +./grub-core/commands/testload.c +./grub-core/commands/time.c +./grub-core/commands/true.c +./grub-core/commands/usbtest.c +./grub-core/commands/videoinfo.c +./grub-core/commands/videotest.c +./grub-core/commands/wildcard.c +./grub-core/commands/xnu_uuid.c +./grub-core/disk/AFSplitter.c +./grub-core/disk/ahci.c +./grub-core/disk/arc/arcdisk.c +./grub-core/disk/ata.c +./grub-core/disk/cryptodisk.c +./grub-core/disk/diskfilter.c +./grub-core/disk/dmraid_nvidia.c +./grub-core/disk/efi/efidisk.c +./grub-core/disk/geli.c +./grub-core/disk/host.c +./grub-core/disk/i386/pc/biosdisk.c +./grub-core/disk/ieee1275/nand.c +./grub-core/disk/ieee1275/ofdisk.c +./grub-core/disk/ldm.c +./grub-core/disk/loopback.c +./grub-core/disk/luks.c +./grub-core/disk/lvm.c +./grub-core/disk/mdraid1x_linux.c +./grub-core/disk/mdraid_linux.c +./grub-core/disk/memdisk.c +./grub-core/disk/pata.c +./grub-core/disk/raid5_recover.c +./grub-core/disk/raid6_recover.c +./grub-core/disk/scsi.c +./grub-core/disk/usbms.c +./grub-core/efiemu/i386/coredetect.c +./grub-core/efiemu/i386/loadcore32.c +./grub-core/efiemu/i386/loadcore64.c +./grub-core/efiemu/i386/nocfgtables.c +./grub-core/efiemu/i386/pc/cfgtables.c +./grub-core/efiemu/loadcore32.c +./grub-core/efiemu/loadcore64.c +./grub-core/efiemu/loadcore.c +./grub-core/efiemu/loadcore_common.c +./grub-core/efiemu/main.c +./grub-core/efiemu/mm.c +./grub-core/efiemu/pnvram.c +./grub-core/efiemu/prepare32.c +./grub-core/efiemu/prepare64.c +./grub-core/efiemu/prepare.c +./grub-core/efiemu/runtime/efiemu.c +./grub-core/efiemu/symbols.c +./grub-core/font/font.c +./grub-core/font/font_cmd.c +./grub-core/fs/affs.c +./grub-core/fs/afs.c +./grub-core/fs/bfs.c +./grub-core/fs/btrfs.c +./grub-core/fs/cpio_be.c +./grub-core/fs/cpio.c +./grub-core/fs/exfat.c +./grub-core/fs/ext2.c +./grub-core/fs/fat.c +./grub-core/fs/fshelp.c +./grub-core/fs/hfs.c +./grub-core/fs/hfsplus.c +./grub-core/fs/iso9660.c +./grub-core/fs/jfs.c +./grub-core/fs/minix2.c +./grub-core/fs/minix3.c +./grub-core/fs/minix.c +./grub-core/fs/newc.c +./grub-core/fs/nilfs2.c +./grub-core/fs/ntfs.c +./grub-core/fs/ntfscomp.c +./grub-core/fs/odc.c +./grub-core/fs/reiserfs.c +./grub-core/fs/romfs.c +./grub-core/fs/sfs.c +./grub-core/fs/squash4.c +./grub-core/fs/tar.c +./grub-core/fs/udf.c +./grub-core/fs/ufs2.c +./grub-core/fs/ufs.c +./grub-core/fs/xfs.c +./grub-core/fs/zfs/zfs.c +./grub-core/fs/zfs/zfscrypt.c +./grub-core/fs/zfs/zfs_fletcher.c +./grub-core/fs/zfs/zfsinfo.c +./grub-core/fs/zfs/zfs_lzjb.c +./grub-core/fs/zfs/zfs_sha256.c +./grub-core/gentrigtables.c +./grub-core/gettext/gettext.c +./grub-core/gfxmenu/font.c +./grub-core/gfxmenu/gfxmenu.c +./grub-core/gfxmenu/gui_box.c +./grub-core/gfxmenu/gui_canvas.c +./grub-core/gfxmenu/gui_circular_progress.c +./grub-core/gfxmenu/gui_image.c +./grub-core/gfxmenu/gui_label.c +./grub-core/gfxmenu/gui_list.c +./grub-core/gfxmenu/gui_progress_bar.c +./grub-core/gfxmenu/gui_string_util.c +./grub-core/gfxmenu/gui_util.c +./grub-core/gfxmenu/icon_manager.c +./grub-core/gfxmenu/model.c +./grub-core/gfxmenu/theme_loader.c +./grub-core/gfxmenu/view.c +./grub-core/gfxmenu/widget-box.c +./grub-core/gnulib/alloca.c +./grub-core/gnulib/argp-ba.c +./grub-core/gnulib/argp-eexst.c +./grub-core/gnulib/argp-fmtstream.c +./grub-core/gnulib/argp-fs-xinl.c +./grub-core/gnulib/argp-help.c +./grub-core/gnulib/argp-parse.c +./grub-core/gnulib/argp-pin.c +./grub-core/gnulib/argp-pv.c +./grub-core/gnulib/argp-pvh.c +./grub-core/gnulib/argp-xinl.c +./grub-core/gnulib/asnprintf.c +./grub-core/gnulib/basename-lgpl.c +./grub-core/gnulib/btowc.c +./grub-core/gnulib/dirname-lgpl.c +./grub-core/gnulib/error.c +./grub-core/gnulib/fnmatch.c +./grub-core/gnulib/fnmatch_loop.c +./grub-core/gnulib/getdelim.c +./grub-core/gnulib/getline.c +./grub-core/gnulib/getopt1.c +./grub-core/gnulib/getopt.c +./grub-core/gnulib/localcharset.c +./grub-core/gnulib/malloc.c +./grub-core/gnulib/mbrtowc.c +./grub-core/gnulib/mbsinit.c +./grub-core/gnulib/mbsrtowcs.c +./grub-core/gnulib/mbsrtowcs-state.c +./grub-core/gnulib/memchr.c +./grub-core/gnulib/mempcpy.c +./grub-core/gnulib/nl_langinfo.c +./grub-core/gnulib/printf-args.c +./grub-core/gnulib/printf-parse.c +./grub-core/gnulib/progname.c +./grub-core/gnulib/rawmemchr.c +./grub-core/gnulib/realloc.c +./grub-core/gnulib/regcomp.c +./grub-core/gnulib/regex.c +./grub-core/gnulib/regexec.c +./grub-core/gnulib/regex_internal.c +./grub-core/gnulib/sleep.c +./grub-core/gnulib/stdio-write.c +./grub-core/gnulib/strcasecmp.c +./grub-core/gnulib/strchrnul.c +./grub-core/gnulib/strerror.c +./grub-core/gnulib/stripslash.c +./grub-core/gnulib/strncasecmp.c +./grub-core/gnulib/strndup.c +./grub-core/gnulib/strnlen1.c +./grub-core/gnulib/strnlen.c +./grub-core/gnulib/vasnprintf.c +./grub-core/gnulib/vsnprintf.c +./grub-core/gnulib/wcrtomb.c +./grub-core/hello/hello.c +./grub-core/hook/datehook.c +./grub-core/io/bufio.c +./grub-core/io/gzio.c +./grub-core/io/lzopio.c +./grub-core/io/xzio.c +./grub-core/kern/command.c +./grub-core/kern/corecmd.c +./grub-core/kern/device.c +./grub-core/kern/disk.c +./grub-core/kern/dl.c +./grub-core/kern/efi/efi.c +./grub-core/kern/efi/init.c +./grub-core/kern/efi/mm.c +./grub-core/kern/elf.c +./grub-core/kern/emu/cache.c +./grub-core/kern/emu/console.c +./grub-core/kern/emu/full.c +./grub-core/kern/emu/hostdisk.c +./grub-core/kern/emu/hostfs.c +./grub-core/kern/emu/lite.c +./grub-core/kern/emu/main.c +./grub-core/kern/emu/misc.c +./grub-core/kern/emu/mm.c +./grub-core/kern/emu/time.c +./grub-core/kern/env.c +./grub-core/kern/err.c +./grub-core/kern/file.c +./grub-core/kern/fs.c +./grub-core/kern/generic/millisleep.c +./grub-core/kern/generic/rtc_get_time_ms.c +./grub-core/kern/i386/coreboot/init.c +./grub-core/kern/i386/coreboot/mmap.c +./grub-core/kern/i386/dl.c +./grub-core/kern/i386/efi/init.c +./grub-core/kern/i386/multiboot_mmap.c +./grub-core/kern/i386/pc/init.c +./grub-core/kern/i386/pc/mmap.c +./grub-core/kern/i386/pit.c +./grub-core/kern/i386/qemu/mmap.c +./grub-core/kern/i386/tsc.c +./grub-core/kern/ia64/dl.c +./grub-core/kern/ia64/dl_helper.c +./grub-core/kern/ia64/efi/init.c +./grub-core/kern/ieee1275/cmain.c +./grub-core/kern/ieee1275/ieee1275.c +./grub-core/kern/ieee1275/init.c +./grub-core/kern/ieee1275/mmap.c +./grub-core/kern/ieee1275/openfw.c +./grub-core/kern/list.c +./grub-core/kern/main.c +./grub-core/kern/mips/arc/init.c +./grub-core/kern/mips/dl.c +./grub-core/kern/mips/init.c +./grub-core/kern/mips/loongson/init.c +./grub-core/kern/mips/qemu_mips/init.c +./grub-core/kern/misc.c +./grub-core/kern/mm.c +./grub-core/kern/parser.c +./grub-core/kern/partition.c +./grub-core/kern/powerpc/dl.c +./grub-core/kern/rescue_parser.c +./grub-core/kern/rescue_reader.c +./grub-core/kern/sparc64/dl.c +./grub-core/kern/sparc64/ieee1275/ieee1275.c +./grub-core/kern/term.c +./grub-core/kern/time.c +./grub-core/kern/vga_init.c +./grub-core/kern/x86_64/dl.c +./grub-core/lib/adler32.c +./grub-core/lib/arc/datetime.c +./grub-core/lib/arg.c +./grub-core/lib/cmdline.c +./grub-core/lib/cmos_datetime.c +./grub-core/lib/crc64.c +./grub-core/lib/crc.c +./grub-core/lib/crypto.c +./grub-core/lib/efi/datetime.c +./grub-core/lib/efi/halt.c +./grub-core/lib/efi/reboot.c +./grub-core/lib/efi/relocator.c +./grub-core/lib/emu/halt.c +./grub-core/lib/envblk.c +./grub-core/lib/hexdump.c +./grub-core/lib/i386/halt.c +./grub-core/lib/i386/pc/biosnum.c +./grub-core/lib/i386/pc/vesa_modes_table.c +./grub-core/lib/i386/reboot.c +./grub-core/lib/i386/relocator.c +./grub-core/lib/ieee1275/cmos.c +./grub-core/lib/ieee1275/datetime.c +./grub-core/lib/ieee1275/halt.c +./grub-core/lib/ieee1275/reboot.c +./grub-core/lib/ieee1275/relocator.c +./grub-core/lib/legacy_parse.c +./grub-core/lib/libgcrypt/cipher/ac.c +./grub-core/lib/libgcrypt/cipher/arcfour.c +./grub-core/lib/libgcrypt/cipher/blowfish.c +./grub-core/lib/libgcrypt/cipher/camellia.c +./grub-core/lib/libgcrypt/cipher/camellia-glue.c +./grub-core/lib/libgcrypt/cipher/cast5.c +./grub-core/lib/libgcrypt/cipher/cipher.c +./grub-core/lib/libgcrypt/cipher/crc.c +./grub-core/lib/libgcrypt/cipher/des.c +./grub-core/lib/libgcrypt/cipher/dsa.c +./grub-core/lib/libgcrypt/cipher/ecc.c +./grub-core/lib/libgcrypt/cipher/elgamal.c +./grub-core/lib/libgcrypt/cipher/hash-common.c +./grub-core/lib/libgcrypt/cipher/hmac-tests.c +./grub-core/lib/libgcrypt/cipher/md4.c +./grub-core/lib/libgcrypt/cipher/md5.c +./grub-core/lib/libgcrypt/cipher/md.c +./grub-core/lib/libgcrypt/cipher/primegen.c +./grub-core/lib/libgcrypt/cipher/pubkey.c +./grub-core/lib/libgcrypt/cipher/rfc2268.c +./grub-core/lib/libgcrypt/cipher/rijndael.c +./grub-core/lib/libgcrypt/cipher/rmd160.c +./grub-core/lib/libgcrypt/cipher/rsa.c +./grub-core/lib/libgcrypt/cipher/seed.c +./grub-core/lib/libgcrypt/cipher/serpent.c +./grub-core/lib/libgcrypt/cipher/sha1.c +./grub-core/lib/libgcrypt/cipher/sha256.c +./grub-core/lib/libgcrypt/cipher/sha512.c +./grub-core/lib/libgcrypt/cipher/tiger.c +./grub-core/lib/libgcrypt/cipher/twofish.c +./grub-core/lib/libgcrypt/cipher/whirlpool.c +./grub-core/lib/libgcrypt-grub/cipher/arcfour.c +./grub-core/lib/libgcrypt-grub/cipher/blowfish.c +./grub-core/lib/libgcrypt-grub/cipher/camellia.c +./grub-core/lib/libgcrypt-grub/cipher/camellia-glue.c +./grub-core/lib/libgcrypt-grub/cipher/cast5.c +./grub-core/lib/libgcrypt-grub/cipher/crc.c +./grub-core/lib/libgcrypt-grub/cipher/des.c +./grub-core/lib/libgcrypt-grub/cipher/dsa.c +./grub-core/lib/libgcrypt-grub/cipher/ecc.c +./grub-core/lib/libgcrypt-grub/cipher/elgamal.c +./grub-core/lib/libgcrypt-grub/cipher/init.c +./grub-core/lib/libgcrypt-grub/cipher/md4.c +./grub-core/lib/libgcrypt-grub/cipher/md5.c +./grub-core/lib/libgcrypt-grub/cipher/primegen.c +./grub-core/lib/libgcrypt-grub/cipher/rfc2268.c +./grub-core/lib/libgcrypt-grub/cipher/rijndael.c +./grub-core/lib/libgcrypt-grub/cipher/rmd160.c +./grub-core/lib/libgcrypt-grub/cipher/rsa.c +./grub-core/lib/libgcrypt-grub/cipher/seed.c +./grub-core/lib/libgcrypt-grub/cipher/serpent.c +./grub-core/lib/libgcrypt-grub/cipher/sha1.c +./grub-core/lib/libgcrypt-grub/cipher/sha256.c +./grub-core/lib/libgcrypt-grub/cipher/sha512.c +./grub-core/lib/libgcrypt-grub/cipher/tiger.c +./grub-core/lib/libgcrypt-grub/cipher/twofish.c +./grub-core/lib/libgcrypt-grub/cipher/whirlpool.c +./grub-core/lib/LzFind.c +./grub-core/lib/LzmaDec.c +./grub-core/lib/LzmaEnc.c +./grub-core/lib/minilzo/minilzo.c +./grub-core/lib/mips/arc/reboot.c +./grub-core/lib/mips/loongson/reboot.c +./grub-core/lib/mips/qemu_mips/reboot.c +./grub-core/lib/mips/relocator.c +./grub-core/lib/pbkdf2.c +./grub-core/lib/powerpc/relocator.c +./grub-core/lib/priority_queue.c +./grub-core/lib/reed_solomon.c +./grub-core/lib/relocator.c +./grub-core/lib/xzembed/xz_dec_bcj.c +./grub-core/lib/xzembed/xz_dec_lzma2.c +./grub-core/lib/xzembed/xz_dec_stream.c +./grub-core/loader/aout.c +./grub-core/loader/efi/appleloader.c +./grub-core/loader/efi/chainloader.c +./grub-core/loader/i386/bsd32.c +./grub-core/loader/i386/bsd64.c +./grub-core/loader/i386/bsd.c +./grub-core/loader/i386/bsd_pagetable.c +./grub-core/loader/i386/bsdXX.c +./grub-core/loader/i386/coreboot/chainloader.c +./grub-core/loader/i386/linux.c +./grub-core/loader/i386/multiboot_mbi.c +./grub-core/loader/i386/pc/chainloader.c +./grub-core/loader/i386/pc/freedos.c +./grub-core/loader/i386/pc/linux.c +./grub-core/loader/i386/pc/ntldr.c +./grub-core/loader/i386/pc/plan9.c +./grub-core/loader/i386/xnu.c +./grub-core/loader/ia64/efi/linux.c +./grub-core/loader/macho32.c +./grub-core/loader/macho64.c +./grub-core/loader/macho.c +./grub-core/loader/machoXX.c +./grub-core/loader/mips/linux.c +./grub-core/loader/multiboot.c +./grub-core/loader/multiboot_elfxx.c +./grub-core/loader/multiboot_mbi2.c +./grub-core/loader/powerpc/ieee1275/linux.c +./grub-core/loader/sparc64/ieee1275/linux.c +./grub-core/loader/xnu.c +./grub-core/loader/xnu_resume.c +./grub-core/mmap/efi/mmap.c +./grub-core/mmap/i386/mmap.c +./grub-core/mmap/i386/pc/mmap.c +./grub-core/mmap/i386/uppermem.c +./grub-core/mmap/mips/uppermem.c +./grub-core/mmap/mmap.c +./grub-core/net/arp.c +./grub-core/net/bootp.c +./grub-core/net/dns.c +./grub-core/net/drivers/efi/efinet.c +./grub-core/net/drivers/emu/emunet.c +./grub-core/net/drivers/i386/pc/pxe.c +./grub-core/net/drivers/ieee1275/ofnet.c +./grub-core/net/ethernet.c +./grub-core/net/http.c +./grub-core/net/icmp6.c +./grub-core/net/icmp.c +./grub-core/net/ip.c +./grub-core/net/netbuff.c +./grub-core/net/net.c +./grub-core/net/tcp.c +./grub-core/net/tftp.c +./grub-core/net/udp.c +./grub-core/normal/auth.c +./grub-core/normal/autofs.c +./grub-core/normal/charset.c +./grub-core/normal/cmdline.c +./grub-core/normal/color.c +./grub-core/normal/completion.c +./grub-core/normal/context.c +./grub-core/normal/crypto.c +./grub-core/normal/datetime.c +./grub-core/normal/dyncmd.c +./grub-core/normal/main.c +./grub-core/normal/menu.c +./grub-core/normal/menu_entry.c +./grub-core/normal/menu_text.c +./grub-core/normal/misc.c +./grub-core/normal/term.c +./grub-core/partmap/acorn.c +./grub-core/partmap/amiga.c +./grub-core/partmap/apple.c +./grub-core/partmap/bsdlabel.c +./grub-core/partmap/dvh.c +./grub-core/partmap/gpt.c +./grub-core/partmap/msdos.c +./grub-core/partmap/plan.c +./grub-core/partmap/sun.c +./grub-core/partmap/sunpc.c +./grub-core/parttool/msdospart.c +./grub-core/script/argv.c +./grub-core/script/execute.c +./grub-core/script/function.c +./grub-core/script/lexer.c +./grub-core/script/main.c +./grub-core/script/script.c +./grub-core/term/arc/console.c +./grub-core/term/at_keyboard.c +./grub-core/term/efi/console.c +./grub-core/term/gfxterm.c +./grub-core/term/i386/pc/console.c +./grub-core/term/i386/pc/vga_text.c +./grub-core/term/i386/vga_common.c +./grub-core/term/ieee1275/console.c +./grub-core/term/ns8250.c +./grub-core/term/serial.c +./grub-core/term/terminfo.c +./grub-core/term/tparm.c +./grub-core/term/usb_keyboard.c +./grub-core/tests/example_functional_test.c +./grub-core/tests/lib/functional_test.c +./grub-core/tests/lib/test.c +./grub-core/tests/test_blockarg.c +./grub-core/unidata.c +./grub-core/video/bitmap.c +./grub-core/video/bitmap_scale.c +./grub-core/video/bochs.c +./grub-core/video/cirrus.c +./grub-core/video/colors.c +./grub-core/video/efi_gop.c +./grub-core/video/efi_uga.c +./grub-core/video/emu/sdl.c +./grub-core/video/fb/fbblit.c +./grub-core/video/fb/fbfill.c +./grub-core/video/fb/fbutil.c +./grub-core/video/fb/video_fb.c +./grub-core/video/i386/pc/vbe.c +./grub-core/video/i386/pc/vga.c +./grub-core/video/ieee1275.c +./grub-core/video/radeon_fuloong2e.c +./grub-core/video/readers/jpeg.c +./grub-core/video/readers/png.c +./grub-core/video/readers/tga.c +./grub-core/video/sis315_init.c +./grub-core/video/sis315pro.c +./grub-core/video/sm712.c +./grub-core/video/sm712_init.c +./grub-core/video/video.c +./tests/example_unit_test.c +./tests/lib/unit_test.c +./tests/printf_unit_test.c +./util/bin2h.c +./util/deviceiter.c +./util/devicemap.c +./util/getroot.c +./util/grub-editenv.c +./util/grub-fstest.c +./util/grub-macho2img.c +./util/grub-menulst2cfg.c +./util/grub-mkdevicemap.c +./util/grub-mkfont.c +./util/grub-mkimage.c +./util/grub-mkimagexx.c +./util/grub-mklayout.c +./util/grub-mkpasswd-pbkdf2.c +./util/grub-mkrelpath.c +./util/grub-mount.c +./util/grub-pe2elf.c +./util/grub-probe.c +./util/grub-script-check.c +./util/grub-setup.c +./util/ieee1275/grub-ofpathname.c +./util/ieee1275/ofpath.c +./util/lvm.c +./util/misc.c +./util/raid.c +./util/resolve.c diff --git a/po/README b/po/README index 801599583..5541f4229 100644 --- a/po/README +++ b/po/README @@ -8,6 +8,10 @@ that will hopefully clarify the situation. rsync -Lrtvz translationproject.org::tp/latest/grub/ po + Then create a po/LINGUAS file listing all the language codes: + + (cd po && ls *.po | cut -d. -f1 | xargs) >po/LINGUAS + GRUB's build system will automatically detect those and include them in your install. diff --git a/po/grub.d.sed b/po/grub.d.sed new file mode 100644 index 000000000..9fd729474 --- /dev/null +++ b/po/grub.d.sed @@ -0,0 +1,2 @@ +/^#: util\/grub\.d\//a\ +#, c-format diff --git a/tests/example_scripted_test.in b/tests/example_scripted_test.in index 9ac0424c0..09633e893 100644 --- a/tests/example_scripted_test.in +++ b/tests/example_scripted_test.in @@ -1,3 +1,4 @@ -#!/bin/sh -e +#!/bin/sh +set -e true diff --git a/tests/grub_cmd_echo.in b/tests/grub_cmd_echo.in index 6ac33f55e..902696778 100644 --- a/tests/grub_cmd_echo.in +++ b/tests/grub_cmd_echo.in @@ -31,3 +31,11 @@ echo foo -n echo foo -n -e echo ------- + +if test -n "$grubshell"; then insmod regexp; fi + +echo '*' +echo "*" + +foo="*" +echo "$foo" diff --git a/tests/grub_cmd_regexp.in b/tests/grub_cmd_regexp.in index 43b479fec..e7e625701 100644 --- a/tests/grub_cmd_regexp.in +++ b/tests/grub_cmd_regexp.in @@ -1,4 +1,5 @@ -#! /bin/bash -e +#! /bin/bash +set -e # Run GRUB script in a Qemu instance # Copyright (C) 2010 Free Software Foundation, Inc. diff --git a/tests/grub_script_blanklines.in b/tests/grub_script_blanklines.in index 71b869bd3..89ed763d3 100644 --- a/tests/grub_script_blanklines.in +++ b/tests/grub_script_blanklines.in @@ -1,4 +1,5 @@ -#! /bin/sh -e +#! /bin/sh +set -e @builddir@/grub-script-check <$tmp error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { true } }' diff --git a/tests/grub_script_dollar.in b/tests/grub_script_dollar.in index 3819b8bc9..2e076427a 100644 --- a/tests/grub_script_dollar.in +++ b/tests/grub_script_dollar.in @@ -1,4 +1,5 @@ -#! /bin/sh -e +#! /bin/sh +set -e @builddir@/grub-script-check << EOF echo "\\\$" diff --git a/tests/grub_script_echo1.in b/tests/grub_script_echo1.in index 9415a3f73..54395774f 100644 --- a/tests/grub_script_echo1.in +++ b/tests/grub_script_echo1.in @@ -99,3 +99,5 @@ echo one'two # # two" +if test x$grubshell = xyes; then insmod regexp; fi +echo /boot/grub/i386-pc/normal.mod diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in index d1e8d55c9..1575bff61 100644 --- a/tests/grub_script_expansion.in +++ b/tests/grub_script_expansion.in @@ -1,4 +1,5 @@ -#! /bin/bash -e +#! /bin/bash +set -e # Run GRUB script in a Qemu instance # Copyright (C) 2010 Free Software Foundation, Inc. diff --git a/tests/grub_script_final_semicolon.in b/tests/grub_script_final_semicolon.in index 99e55e545..3ac26540b 100644 --- a/tests/grub_script_final_semicolon.in +++ b/tests/grub_script_final_semicolon.in @@ -1,4 +1,5 @@ -#! /bin/sh -e +#! /bin/sh +set -e @builddir@/grub-script-check <. -parted=/sbin/parted +parted=parted grubshell=@builddir@/grub-shell create_disk_image () { @@ -51,8 +52,8 @@ list_parts () { echo } -imgfile=`mktemp` -outfile=`mktemp` +imgfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 +outfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 # # MSDOS partition types diff --git a/tests/printf_unit_test.c b/tests/printf_unit_test.c new file mode 100644 index 000000000..6e601b401 --- /dev/null +++ b/tests/printf_unit_test.c @@ -0,0 +1,43 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 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 + +static void +printf_test (void) +{ + char real[512]; + char expected[512]; + grub_snprintf (real, sizeof (real), "%d %d %d", 1, 2, 3); + snprintf (expected, sizeof (expected), "%d %d %d", 1, 2, 3); + grub_test_assert (strcmp (real, expected) == 0); + grub_snprintf (real, sizeof (real), "%3$d %2$d %1$d", 1, 2, 3); + snprintf (expected, sizeof (expected), "%3$d %2$d %1$d", 1, 2, 3); + grub_test_assert (strcmp (real, expected) == 0); + grub_snprintf (real, sizeof (real), "%d %lld %d", 1, 2LL, 3); + snprintf (expected, sizeof (expected), "%d %lld %d", 1, 2LL, 3); + grub_test_assert (strcmp (real, expected) == 0); + grub_snprintf (real, sizeof (real), "%3$d %2$lld %1$d", 1, 2LL, 3); + snprintf (expected, sizeof (expected), "%3$d %2$lld %1$d", 1, 2LL, 3); + grub_test_assert (strcmp (real, expected) == 0); +} + +GRUB_UNIT_TEST ("printf_unit_test", printf_test); diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in index ed34a5e17..80c883076 100644 --- a/tests/util/grub-shell-tester.in +++ b/tests/util/grub-shell-tester.in @@ -1,4 +1,5 @@ -#! /bin/sh -e +#! /bin/sh +set -e # Compares GRUB script output with BASH output. # Copyright (C) 2009,2010 Free Software Foundation, Inc. @@ -19,18 +20,16 @@ # Initialize some variables. transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -builddir=@builddir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +builddir="@builddir@" PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ # Force build directory components -PATH=${builddir}:$PATH +PATH="${builddir}:$PATH" export PATH # Usage: usage @@ -83,25 +82,25 @@ for option in "$@"; do done if [ "x${source}" = x ] ; then - tmpfile=`mktemp` + tmpfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 while read REPLY; do - echo $REPLY >> ${tmpfile} + echo $REPLY >> "${tmpfile}" done - source=${tmpfile} + source="${tmpfile}" fi -outfile1=`mktemp` -@builddir@/grub-shell --qemu-opts="${qemuopts}" --modules=${modules} ${source} >${outfile1} +outfile1=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 +"@builddir@/grub-shell" --qemu-opts="${qemuopts}" --modules=${modules} "${source}" >"${outfile1}" -outfile2=`mktemp` -bash ${source} >${outfile2} +outfile2=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 +bash "${source}" >"${outfile2}" -if ! diff -q ${outfile1} ${outfile2} >/dev/null +if ! diff -q "${outfile1}" "${outfile2}" >/dev/null then echo "${source}: GRUB and BASH outputs did not match (see diff -u ${outfile1} ${outfile2})" status=1 else - rm -f ${outfile1} ${outfile2} + rm -f "${outfile1}" "${outfile2}" fi exit $status diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index c8247d29d..abb3bff1f 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -1,4 +1,5 @@ -#! /bin/sh -e +#! /bin/sh +set -e # Run GRUB script in a Qemu instance # Copyright (C) 2009,2010 Free Software Foundation, Inc. @@ -19,11 +20,10 @@ # Initialize some variables. transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -builddir=@builddir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +builddir="@builddir@" PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ @@ -31,7 +31,7 @@ target_cpu=@target_cpu@ platform=@platform@ # Force build directory components -PATH=${builddir}:$PATH +PATH="${builddir}:$PATH" export PATH # Usage: usage @@ -107,23 +107,24 @@ for option in "$@"; do done if [ "x${source}" = x ] ; then - tmpfile=`mktemp` + tmpfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 while read REPLY; do echo "$REPLY" >> ${tmpfile} done source=${tmpfile} fi -cfgfile=`mktemp` +cfgfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 cat <${cfgfile} grubshell=yes insmod serial serial +terminfo serial dumb terminal_input serial terminal_output serial EOF -rom_directory=`mktemp -d` +rom_directory=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 for mod in ${modules} do @@ -132,14 +133,16 @@ done cat <>${cfgfile} source /boot/grub/testcase.cfg +# Stop serial output to suppress "ACPI shutdown failed" error. +terminal_output console halt EOF -isofile=`mktemp` +isofile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 if [ x$boot != xnet ]; then - sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage --output=${isofile} --override-directory=${builddir}/grub-core \ + 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} \ + "/boot/grub/grub.cfg=${cfgfile}" "/boot/grub/testcase.cfg=${source}" \ ${files} >/dev/null 2>&1 fi if [ x$boot = xhd ]; then @@ -161,7 +164,7 @@ if [ x$boot = xqemu ]; then fi if [ x$boot = xcoreboot ]; then - imgfile=`mktemp` + imgfile=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 cp "${GRUB_COREBOOT_ROM}" "${imgfile}" "${GRUB_CBFSTOOL}" "${imgfile}" add-payload "${rom_directory}/coreboot.elf" fallback/payload bootdev="-bios ${imgfile}" @@ -169,13 +172,13 @@ if [ x$boot = xcoreboot ]; then fi if [ x$boot = xnet ]; then - netdir=`mktemp -d` - sh @builddir@/grub-mknetdir --grub-mkimage=${builddir}/grub-mkimage --override-directory=${builddir}/grub-core --net-directory=$netdir - cp ${cfgfile} $netdir/boot/grub/grub.cfg - cp ${source} $netdir/boot/grub/testcase.cfg - ${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -boot n -net user,tftp=$netdir,bootfile=/boot/grub/$target_cpu-$platform/core.0 -net nic | cat | tr -d "\r" + netdir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + sh "@builddir@/grub-mknetdir" "--grub-mkimage=${builddir}/grub-mkimage" "--override-directory=${builddir}/grub-core" "--net-directory=$netdir" + cp "${cfgfile}" "$netdir/boot/grub/grub.cfg" + cp "${source}" "$netdir/boot/grub/testcase.cfg" + "${qemu}" ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -boot n -net "user,tftp=$netdir,bootfile=/boot/grub/$target_cpu-$platform/core.0" -net nic | cat | tr -d "\r" else - ${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -${device} ${isofile} ${bootdev} | cat | tr -d "\r" + "${qemu}" ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -${device} ${isofile} ${bootdev} | cat | tr -d "\r" fi rm -f "${isofile}" "${imgfile}" rm -rf "${rom_directory}" diff --git a/unicode/ArabicShaping.txt b/unicode/ArabicShaping.txt index b851d3839..bab6a11f9 100644 --- a/unicode/ArabicShaping.txt +++ b/unicode/ArabicShaping.txt @@ -1,18 +1,18 @@ -# ArabicShaping-5.2.0.txt -# Date: 2009-08-17, 11:11:00 PDT [KW] +# ArabicShaping-6.0.0.txt +# Date: 2010-04-30, 13:47:00 PDT [KW] # # This file is a normative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2009 Unicode, Inc. +# Copyright (c) 1991-2010 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # # This file defines the shaping classes for Arabic, Syriac, and N'Ko # positional shaping, repeating in machine readable form the # information exemplified in Tables 8-3, 8-7, 8-8, 8-11, 8-12, -# 8-13, and 13-5 of The Unicode Standard, Version 5.2. +# 8-13, and 13-5 of The Unicode Standard, Version 6.0. # -# See sections 8.2, 8.3, and 13.5 of The Unicode Standard, Version 5.2 +# See sections 8.2, 8.3, and 13.5 of The Unicode Standard, Version 6.0 # for more information. # # Each line contains four fields, separated by a semicolon. @@ -22,6 +22,8 @@ # # Field 1: gives a short schematic name for that character, # abbreviated from the normative Unicode character name. +# Note that this schematic name is considered a comment, +# and does not constitute a formal property value. # # Field 2: defines the joining type (property name: Joining_Type) # R Right_Joining @@ -44,8 +46,8 @@ # # corresponds to [Joining_Group = Teh_Marbuta]. # -# Note: For historical reasons, the property value [Joining_Group = Hamza_On_Heh_Goal] -# is anachronistically named. It used to apply to both of the following characters +# Note: The property value now designated [Joining_Group = Teh_Marbuta_Goal] +# used to apply to both of the following characters # in earlier versions of the standard: # # U+06C2 ARABIC LETTER HEH GOAL WITH HAMZA ABOVE @@ -53,8 +55,10 @@ # # However, it currently applies only to U+06C3, and *not* to U+06C2. # To avoid destabilizing existing Joining_Group property aliases, the -# value Hamza_On_Heh_Goal has not been changed, despite the fact that it -# no longer applies to Hamza On Heh Goal, but only to Teh Marbuta Goal. +# prior Joining_Group value for U+06C3 (Hamza_On_Heh_Goal) has been +# retained as a property value alias, despite the fact that it +# no longer applies to its namesake character, U+06C2. +# See PropertyValueAliases.txt. # # When other cursive scripts are added to the Unicode Standard in # the future, the joining group value of all its letters will default @@ -88,6 +92,7 @@ 0603; ARABIC SIGN SAFHA; U; No_Joining_Group 0608; ARABIC RAY; U; No_Joining_Group 060B; AFGHANI SIGN; U; No_Joining_Group +0620; YEH WITH RING; D; YEH 0621; HAMZA; U; No_Joining_Group 0622; MADDA ON ALEF; R; ALEF 0623; HAMZA ON ALEF; R; ALEF @@ -214,7 +219,7 @@ 06C0; HAMZA ON HEH; R; TEH MARBUTA 06C1; HEH GOAL; D; HEH GOAL 06C2; HAMZA ON HEH GOAL; D; HEH GOAL -06C3; TEH MARBUTA GOAL; R; HAMZA ON HEH GOAL +06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL 06C4; WAW WITH RING; R; WAW 06C5; WAW WITH BAR; R; WAW 06C6; WAW WITH SMALL V; R; WAW diff --git a/unicode/BidiMirroring.txt b/unicode/BidiMirroring.txt index 81e838a7e..902f9a6b8 100644 --- a/unicode/BidiMirroring.txt +++ b/unicode/BidiMirroring.txt @@ -1,18 +1,19 @@ -# BidiMirroring-5.2.0.txt -# Date: 2009-05-22, 12:44:00 PDT [KW] +# BidiMirroring-6.0.0.txt +# Date: 2010-06-21, 12:09:00 PDT [KW] # # Bidi_Mirroring_Glyph Property # # This file is an informative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2009 Unicode, Inc. +# Copyright (c) 1991-2010 Unicode, Inc. # For terms of use, see http://www.unicode.org/terms_of_use.html # -# This data file lists characters that have the mirrored property -# where there is another Unicode character that typically has a glyph +# This data file lists characters that have the Bidi_Mirrored=True property +# value, for which there is another Unicode character that typically has a glyph # that is the mirror image of the original character's glyph. -# The repertoire covered by the file is Unicode 5.2.0. +# +# The repertoire covered by the file is Unicode 6.0.0. # # The file contains a list of lines with mappings from one code point # to another one for character-based mirroring. @@ -25,14 +26,22 @@ # variable-length hexadecimal value with 4 to 6 digits. # A comment indicates where the characters are "BEST FIT" mirroring. # -# Code points with the "mirrored" property but no appropriate mirrors are +# Code points for which Bidi_Mirrored=True, but for which no appropriate +# characters exist with mirrored glyphs, are # listed as comments at the end of the file. +# +# Formally, the default value of the Bidi_Mirroring_Glyph property +# for each code point is the code point itself, unless a mapping to +# some other character is specified in this data file. When a code +# point has the default value for the Bidi_Mirroring_Glyph property, +# that means that no other character exists whose glyph is suitable +# for character-based mirroring. # # For information on bidi mirroring, see UAX #9: Bidirectional Algorithm, # at http://www.unicode.org/unicode/reports/tr9/ # # This file was originally created by Markus Scherer. -# Extended for Unicode 3.2, 4.0, 4.1, 5.0, 5.1, and 5.2 by Ken Whistler. +# Extended for Unicode 3.2, 4.0, 4.1, 5.0, 5.1, 5.2, and 6.0 by Ken Whistler. # # ############################################################ @@ -464,8 +473,8 @@ FF63; FF62 # [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET # 22FF; Z NOTATION BAG MEMBERSHIP # 2320; TOP HALF INTEGRAL # 2321; BOTTOM HALF INTEGRAL -# 27CC; LONG DIVISION # 27C0; THREE DIMENSIONAL ANGLE +# 27CC; LONG DIVISION # 27D3; LOWER RIGHT CORNER WITH DOT # 27D4; UPPER LEFT CORNER WITH DOT # 27DC; LEFT MULTIMAP diff --git a/unicode/COPYING b/unicode/COPYING index f81c87a27..ad63a2bbc 100644 --- a/unicode/COPYING +++ b/unicode/COPYING @@ -1,6 +1,6 @@ COPYRIGHT AND PERMISSION NOTICE -Copyright © 1991-2009 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. +Copyright © 1991-2011 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that (a) the above copyright notice(s) and this permission notice appear with all copies of the Data Files or Software, (b) both the above copyright notice(s) and this permission notice appear in associated documentation, and (c) there is clear notice in each modified Data File or in the Software as well as in the documentation associated with the Data File(s) or Software that the data or software has been modified. diff --git a/unicode/UnicodeData.txt b/unicode/UnicodeData.txt index 6b01d90a7..8d7222b13 100644 --- a/unicode/UnicodeData.txt +++ b/unicode/UnicodeData.txt @@ -611,7 +611,7 @@ 0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; 0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; -0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;; +0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;A78D;;A78D 0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;; 0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; 0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 @@ -1306,6 +1306,8 @@ 0523;CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK;Ll;0;L;;;;;N;;;0522;;0522 0524;CYRILLIC CAPITAL LETTER PE WITH DESCENDER;Lu;0;L;;;;;N;;;;0525; 0525;CYRILLIC SMALL LETTER PE WITH DESCENDER;Ll;0;L;;;;;N;;;0524;;0524 +0526;CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER;Lu;0;L;;;;;N;;;;0527; +0527;CYRILLIC SMALL LETTER SHHA WITH DESCENDER;Ll;0;L;;;;;N;;;0526;;0526 0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; 0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; 0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; @@ -1507,6 +1509,7 @@ 061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; 061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;; 061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; +0620;ARABIC LETTER KASHMIRI YEH;Lo;0;AL;;;;;N;;;;; 0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; 0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; 0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;; @@ -1569,6 +1572,7 @@ 065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;; 065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;; 065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;; +065F;ARABIC WAVY HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; @@ -1695,7 +1699,7 @@ 06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; 06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; 06DD;ARABIC END OF AYAH;Cf;0;AN;;;;;N;;;;; -06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;; +06DE;ARABIC START OF RUB EL HIZB;So;0;ON;;;;;N;;;;; 06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; 06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; 06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;; @@ -1743,7 +1747,7 @@ 070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; 070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; 070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; -070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;; +070F;SYRIAC ABBREVIATION MARK;Cf;0;AN;;;;;N;;;;; 0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; 0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; 0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; @@ -2024,6 +2028,35 @@ 083C;SAMARITAN PUNCTUATION ARKAANU;Po;0;R;;;;;N;;;;; 083D;SAMARITAN PUNCTUATION SOF MASHFAAT;Po;0;R;;;;;N;;;;; 083E;SAMARITAN PUNCTUATION ANNAAU;Po;0;R;;;;;N;;;;; +0840;MANDAIC LETTER HALQA;Lo;0;R;;;;;N;;;;; +0841;MANDAIC LETTER AB;Lo;0;R;;;;;N;;;;; +0842;MANDAIC LETTER AG;Lo;0;R;;;;;N;;;;; +0843;MANDAIC LETTER AD;Lo;0;R;;;;;N;;;;; +0844;MANDAIC LETTER AH;Lo;0;R;;;;;N;;;;; +0845;MANDAIC LETTER USHENNA;Lo;0;R;;;;;N;;;;; +0846;MANDAIC LETTER AZ;Lo;0;R;;;;;N;;;;; +0847;MANDAIC LETTER IT;Lo;0;R;;;;;N;;;;; +0848;MANDAIC LETTER ATT;Lo;0;R;;;;;N;;;;; +0849;MANDAIC LETTER AKSA;Lo;0;R;;;;;N;;;;; +084A;MANDAIC LETTER AK;Lo;0;R;;;;;N;;;;; +084B;MANDAIC LETTER AL;Lo;0;R;;;;;N;;;;; +084C;MANDAIC LETTER AM;Lo;0;R;;;;;N;;;;; +084D;MANDAIC LETTER AN;Lo;0;R;;;;;N;;;;; +084E;MANDAIC LETTER AS;Lo;0;R;;;;;N;;;;; +084F;MANDAIC LETTER IN;Lo;0;R;;;;;N;;;;; +0850;MANDAIC LETTER AP;Lo;0;R;;;;;N;;;;; +0851;MANDAIC LETTER ASZ;Lo;0;R;;;;;N;;;;; +0852;MANDAIC LETTER AQ;Lo;0;R;;;;;N;;;;; +0853;MANDAIC LETTER AR;Lo;0;R;;;;;N;;;;; +0854;MANDAIC LETTER ASH;Lo;0;R;;;;;N;;;;; +0855;MANDAIC LETTER AT;Lo;0;R;;;;;N;;;;; +0856;MANDAIC LETTER DUSHENNA;Lo;0;R;;;;;N;;;;; +0857;MANDAIC LETTER KAD;Lo;0;R;;;;;N;;;;; +0858;MANDAIC LETTER AIN;Lo;0;R;;;;;N;;;;; +0859;MANDAIC AFFRICATION MARK;Mn;220;NSM;;;;;N;;;;; +085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;; +085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;; +085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;; 0900;DEVANAGARI SIGN INVERTED CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; @@ -2082,6 +2115,8 @@ 0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; 0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;; 0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;; +093A;DEVANAGARI VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +093B;DEVANAGARI VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;; 093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; 093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; @@ -2101,12 +2136,15 @@ 094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; 094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 094E;DEVANAGARI VOWEL SIGN PRISHTHAMATRA E;Mc;0;L;;;;;N;;;;; +094F;DEVANAGARI VOWEL SIGN AW;Mc;0;L;;;;;N;;;;; 0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;; 0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;; 0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;; 0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; 0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; 0955;DEVANAGARI VOWEL SIGN CANDRA LONG E;Mn;0;NSM;;;;;N;;;;; +0956;DEVANAGARI VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +0957;DEVANAGARI VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;; 0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;; 0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;; 095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;; @@ -2134,6 +2172,11 @@ 0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0971;DEVANAGARI SIGN HIGH SPACING DOT;Lm;0;L;;;;;N;;;;; 0972;DEVANAGARI LETTER CANDRA A;Lo;0;L;;;;;N;;;;; +0973;DEVANAGARI LETTER OE;Lo;0;L;;;;;N;;;;; +0974;DEVANAGARI LETTER OOE;Lo;0;L;;;;;N;;;;; +0975;DEVANAGARI LETTER AW;Lo;0;L;;;;;N;;;;; +0976;DEVANAGARI LETTER UE;Lo;0;L;;;;;N;;;;; +0977;DEVANAGARI LETTER UUE;Lo;0;L;;;;;N;;;;; 0979;DEVANAGARI LETTER ZHA;Lo;0;L;;;;;N;;;;; 097A;DEVANAGARI LETTER HEAVY YA;Lo;0;L;;;;;N;;;;; 097B;DEVANAGARI LETTER GGA;Lo;0;L;;;;;N;;;;; @@ -2479,6 +2522,12 @@ 0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;; 0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;; +0B72;ORIYA FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; +0B73;ORIYA FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; +0B74;ORIYA FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +0B75;ORIYA FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; +0B76;ORIYA FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +0B77;ORIYA FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; 0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;; 0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;; @@ -2728,8 +2777,8 @@ 0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -0CF1;KANNADA SIGN JIHVAMULIYA;So;0;ON;;;;;N;;;;; -0CF2;KANNADA SIGN UPADHMANIYA;So;0;ON;;;;;N;;;;; +0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; 0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; 0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; @@ -2766,6 +2815,7 @@ 0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;; 0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;; 0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;; +0D29;MALAYALAM LETTER NNNA;Lo;0;L;;;;;N;;;;; 0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;; 0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;; 0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;; @@ -2782,6 +2832,7 @@ 0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; 0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; 0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; +0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;; 0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; @@ -2797,6 +2848,7 @@ 0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;; 0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; 0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;; 0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; 0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; @@ -3192,6 +3244,10 @@ 0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;;;; 0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;;;; 0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;;;; +0F8C;TIBETAN SIGN INVERTED MCHU CAN;Lo;0;L;;;;;N;;;;; +0F8D;TIBETAN SUBJOINED SIGN LCE TSA CAN;Mn;0;NSM;;;;;N;;;;; +0F8E;TIBETAN SUBJOINED SIGN MCHU CAN;Mn;0;NSM;;;;;N;;;;; +0F8F;TIBETAN SUBJOINED SIGN INVERTED MCHU CAN;Mn;0;NSM;;;;;N;;;;; 0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; 0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; 0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; @@ -3262,6 +3318,8 @@ 0FD6;LEFT-FACING SVASTI SIGN;So;0;L;;;;;N;;;;; 0FD7;RIGHT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;; 0FD8;LEFT-FACING SVASTI SIGN WITH DOTS;So;0;L;;;;;N;;;;; +0FD9;TIBETAN MARK LEADING MCHAN RTAGS;Po;0;L;;;;;N;;;;; +0FDA;TIBETAN MARK TRAILING MCHAN RTAGS;Po;0;L;;;;;N;;;;; 1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; 1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; 1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; @@ -4087,6 +4145,8 @@ 1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; 1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; 135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; +135D;ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; +135E;ETHIOPIC COMBINING VOWEL LENGTH MARK;Mn;230;NSM;;;;;N;;;;; 135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; 1360;ETHIOPIC SECTION MARK;So;0;L;;;;;N;;;;; 1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; @@ -5580,9 +5640,9 @@ 19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; -19DA;NEW TAI LUE THAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; -19DE;NEW TAI LUE SIGN LAE;Po;0;ON;;;;;N;;;;; -19DF;NEW TAI LUE SIGN LAEV;Po;0;ON;;;;;N;;;;; +19DA;NEW TAI LUE THAM DIGIT ONE;No;0;L;;;1;1;N;;;;; +19DE;NEW TAI LUE SIGN LAE;So;0;ON;;;;;N;;;;; +19DF;NEW TAI LUE SIGN LAEV;So;0;ON;;;;;N;;;;; 19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;; 19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;; 19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;; @@ -5948,6 +6008,62 @@ 1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1BC0;BATAK LETTER A;Lo;0;L;;;;;N;;;;; +1BC1;BATAK LETTER SIMALUNGUN A;Lo;0;L;;;;;N;;;;; +1BC2;BATAK LETTER HA;Lo;0;L;;;;;N;;;;; +1BC3;BATAK LETTER SIMALUNGUN HA;Lo;0;L;;;;;N;;;;; +1BC4;BATAK LETTER MANDAILING HA;Lo;0;L;;;;;N;;;;; +1BC5;BATAK LETTER BA;Lo;0;L;;;;;N;;;;; +1BC6;BATAK LETTER KARO BA;Lo;0;L;;;;;N;;;;; +1BC7;BATAK LETTER PA;Lo;0;L;;;;;N;;;;; +1BC8;BATAK LETTER SIMALUNGUN PA;Lo;0;L;;;;;N;;;;; +1BC9;BATAK LETTER NA;Lo;0;L;;;;;N;;;;; +1BCA;BATAK LETTER MANDAILING NA;Lo;0;L;;;;;N;;;;; +1BCB;BATAK LETTER WA;Lo;0;L;;;;;N;;;;; +1BCC;BATAK LETTER SIMALUNGUN WA;Lo;0;L;;;;;N;;;;; +1BCD;BATAK LETTER PAKPAK WA;Lo;0;L;;;;;N;;;;; +1BCE;BATAK LETTER GA;Lo;0;L;;;;;N;;;;; +1BCF;BATAK LETTER SIMALUNGUN GA;Lo;0;L;;;;;N;;;;; +1BD0;BATAK LETTER JA;Lo;0;L;;;;;N;;;;; +1BD1;BATAK LETTER DA;Lo;0;L;;;;;N;;;;; +1BD2;BATAK LETTER RA;Lo;0;L;;;;;N;;;;; +1BD3;BATAK LETTER SIMALUNGUN RA;Lo;0;L;;;;;N;;;;; +1BD4;BATAK LETTER MA;Lo;0;L;;;;;N;;;;; +1BD5;BATAK LETTER SIMALUNGUN MA;Lo;0;L;;;;;N;;;;; +1BD6;BATAK LETTER SOUTHERN TA;Lo;0;L;;;;;N;;;;; +1BD7;BATAK LETTER NORTHERN TA;Lo;0;L;;;;;N;;;;; +1BD8;BATAK LETTER SA;Lo;0;L;;;;;N;;;;; +1BD9;BATAK LETTER SIMALUNGUN SA;Lo;0;L;;;;;N;;;;; +1BDA;BATAK LETTER MANDAILING SA;Lo;0;L;;;;;N;;;;; +1BDB;BATAK LETTER YA;Lo;0;L;;;;;N;;;;; +1BDC;BATAK LETTER SIMALUNGUN YA;Lo;0;L;;;;;N;;;;; +1BDD;BATAK LETTER NGA;Lo;0;L;;;;;N;;;;; +1BDE;BATAK LETTER LA;Lo;0;L;;;;;N;;;;; +1BDF;BATAK LETTER SIMALUNGUN LA;Lo;0;L;;;;;N;;;;; +1BE0;BATAK LETTER NYA;Lo;0;L;;;;;N;;;;; +1BE1;BATAK LETTER CA;Lo;0;L;;;;;N;;;;; +1BE2;BATAK LETTER NDA;Lo;0;L;;;;;N;;;;; +1BE3;BATAK LETTER MBA;Lo;0;L;;;;;N;;;;; +1BE4;BATAK LETTER I;Lo;0;L;;;;;N;;;;; +1BE5;BATAK LETTER U;Lo;0;L;;;;;N;;;;; +1BE6;BATAK SIGN TOMPI;Mn;7;NSM;;;;;N;;;;; +1BE7;BATAK VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1BE8;BATAK VOWEL SIGN PAKPAK E;Mn;0;NSM;;;;;N;;;;; +1BE9;BATAK VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +1BEA;BATAK VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +1BEB;BATAK VOWEL SIGN KARO I;Mc;0;L;;;;;N;;;;; +1BEC;BATAK VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +1BED;BATAK VOWEL SIGN KARO O;Mn;0;NSM;;;;;N;;;;; +1BEE;BATAK VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +1BEF;BATAK VOWEL SIGN U FOR SIMALUNGUN SA;Mn;0;NSM;;;;;N;;;;; +1BF0;BATAK CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; +1BF1;BATAK CONSONANT SIGN H;Mn;0;NSM;;;;;N;;;;; +1BF2;BATAK PANGOLAT;Mc;9;L;;;;;N;;;;; +1BF3;BATAK PANONGONAN;Mc;9;L;;;;;N;;;;; +1BFC;BATAK SYMBOL BINDU NA METEK;Po;0;L;;;;;N;;;;; +1BFD;BATAK SYMBOL BINDU PINARBORAS;Po;0;L;;;;;N;;;;; +1BFE;BATAK SYMBOL BINDU JUDUL;Po;0;L;;;;;N;;;;; +1BFF;BATAK SYMBOL BINDU PANGOLAT;Po;0;L;;;;;N;;;;; 1C00;LEPCHA LETTER KA;Lo;0;L;;;;;N;;;;; 1C01;LEPCHA LETTER KLA;Lo;0;L;;;;;N;;;;; 1C02;LEPCHA LETTER KHA;Lo;0;L;;;;;N;;;;; @@ -6336,6 +6452,7 @@ 1DE4;COMBINING LATIN SMALL LETTER S;Mn;230;NSM;;;;;N;;;;; 1DE5;COMBINING LATIN SMALL LETTER LONG S;Mn;230;NSM;;;;;N;;;;; 1DE6;COMBINING LATIN SMALL LETTER Z;Mn;230;NSM;;;;;N;;;;; +1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; 1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; 1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; 1DFF;COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; @@ -6969,6 +7086,14 @@ 2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L; 006F;;;;N;;;;; 2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L; 0078;;;;N;;;;; 2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L; 0259;;;;N;;;;; +2095;LATIN SUBSCRIPT SMALL LETTER H;Lm;0;L; 0068;;;;N;;;;; +2096;LATIN SUBSCRIPT SMALL LETTER K;Lm;0;L; 006B;;;;N;;;;; +2097;LATIN SUBSCRIPT SMALL LETTER L;Lm;0;L; 006C;;;;N;;;;; +2098;LATIN SUBSCRIPT SMALL LETTER M;Lm;0;L; 006D;;;;N;;;;; +2099;LATIN SUBSCRIPT SMALL LETTER N;Lm;0;L; 006E;;;;N;;;;; +209A;LATIN SUBSCRIPT SMALL LETTER P;Lm;0;L; 0070;;;;N;;;;; +209B;LATIN SUBSCRIPT SMALL LETTER S;Lm;0;L; 0073;;;;N;;;;; +209C;LATIN SUBSCRIPT SMALL LETTER T;Lm;0;L; 0074;;;;N;;;;; 20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; 20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; 20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; @@ -6994,6 +7119,7 @@ 20B6;LIVRE TOURNOIS SIGN;Sc;0;ET;;;;;N;;;;; 20B7;SPESMILO SIGN;Sc;0;ET;;;;;N;;;;; 20B8;TENGE SIGN;Sc;0;ET;;;;;N;;;;; +20B9;INDIAN RUPEE SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; @@ -7051,7 +7177,7 @@ 2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L; 004E;;;;N;DOUBLE-STRUCK N;;;; 2116;NUMERO SIGN;So;0;ON; 004E 006F;;;;N;NUMERO;;;; 2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;; -2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;; +2118;SCRIPT CAPITAL P;Sm;0;ON;;;;;N;SCRIPT P;;;; 2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L; 0050;;;;N;DOUBLE-STRUCK P;;;; 211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L; 0051;;;;N;DOUBLE-STRUCK Q;;;; 211B;SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;SCRIPT R;;;; @@ -7766,6 +7892,17 @@ 23E6;AC CURRENT;So;0;ON;;;;;N;;;;; 23E7;ELECTRICAL INTERSECTION;So;0;ON;;;;;N;;;;; 23E8;DECIMAL EXPONENT SYMBOL;So;0;ON;;;;;N;;;;; +23E9;BLACK RIGHT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23EA;BLACK LEFT-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23EB;BLACK UP-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23EC;BLACK DOWN-POINTING DOUBLE TRIANGLE;So;0;ON;;;;;N;;;;; +23ED;BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +23EE;BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +23EF;BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; +23F0;ALARM CLOCK;So;0;ON;;;;;N;;;;; +23F1;STOPWATCH;So;0;ON;;;;;N;;;;; +23F2;TIMER CLOCK;So;0;ON;;;;;N;;;;; +23F3;HOURGLASS WITH FLOWING SAND;So;0;ON;;;;;N;;;;; 2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; 2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; 2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; @@ -8438,6 +8575,7 @@ 26CB;WHITE DIAMOND IN SQUARE;So;0;ON;;;;;N;;;;; 26CC;CROSSING LANES;So;0;ON;;;;;N;;;;; 26CD;DISABLED CAR;So;0;ON;;;;;N;;;;; +26CE;OPHIUCHUS;So;0;ON;;;;;N;;;;; 26CF;PICK;So;0;ON;;;;;N;;;;; 26D0;CAR SLIDING;So;0;ON;;;;;N;;;;; 26D1;HELMET WITH WHITE CROSS;So;0;ON;;;;;N;;;;; @@ -8457,7 +8595,12 @@ 26DF;BLACK TRUCK;So;0;ON;;;;;N;;;;; 26E0;RESTRICTED LEFT ENTRY-1;So;0;ON;;;;;N;;;;; 26E1;RESTRICTED LEFT ENTRY-2;So;0;ON;;;;;N;;;;; +26E2;ASTRONOMICAL SYMBOL FOR URANUS;So;0;ON;;;;;N;;;;; 26E3;HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE;So;0;ON;;;;;N;;;;; +26E4;PENTAGRAM;So;0;ON;;;;;N;;;;; +26E5;RIGHT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;; +26E6;LEFT-HANDED INTERLACED PENTAGRAM;So;0;ON;;;;;N;;;;; +26E7;INVERTED PENTAGRAM;So;0;ON;;;;;N;;;;; 26E8;BLACK CROSS ON SHIELD;So;0;ON;;;;;N;;;;; 26E9;SHINTO SHRINE;So;0;ON;;;;;N;;;;; 26EA;CHURCH;So;0;ON;;;;;N;;;;; @@ -8486,10 +8629,13 @@ 2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; 2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; 2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;; +2705;WHITE HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; 2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;; 2707;TAPE DRIVE;So;0;ON;;;;;N;;;;; 2708;AIRPLANE;So;0;ON;;;;;N;;;;; 2709;ENVELOPE;So;0;ON;;;;;N;;;;; +270A;RAISED FIST;So;0;ON;;;;;N;;;;; +270B;RAISED HAND;So;0;ON;;;;;N;;;;; 270C;VICTORY HAND;So;0;ON;;;;;N;;;;; 270D;WRITING HAND;So;0;ON;;;;;N;;;;; 270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;; @@ -8518,6 +8664,7 @@ 2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;; 2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2728;SPARKLES;So;0;ON;;;;;N;;;;; 2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; 272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;; 272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;; @@ -8553,11 +8700,16 @@ 2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; 274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; 274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274C;CROSS MARK;So;0;ON;;;;;N;;;;; 274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +274E;NEGATIVE SQUARED CROSS MARK;So;0;ON;;;;;N;;;;; 274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; 2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2753;BLACK QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2754;WHITE QUESTION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2755;WHITE EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;; 2757;HEAVY EXCLAMATION MARK SYMBOL;So;0;ON;;;;;N;;;;; 2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;; @@ -8567,6 +8719,8 @@ 275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275F;HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2760;HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;; 2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; 2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; @@ -8619,6 +8773,9 @@ 2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;; 2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;; 2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;; +2795;HEAVY PLUS SIGN;So;0;ON;;;;;N;;;;; +2796;HEAVY MINUS SIGN;So;0;ON;;;;;N;;;;; +2797;HEAVY DIVISION SIGN;So;0;ON;;;;;N;;;;; 2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;; 2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;; 279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;; @@ -8643,6 +8800,7 @@ 27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B0;CURLY LOOP;So;0;ON;;;;;N;;;;; 27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; 27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;; 27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;; @@ -8657,6 +8815,7 @@ 27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; 27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; 27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; +27BF;DOUBLE CURLY LOOP;So;0;ON;;;;;N;;;;; 27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;; 27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;; 27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;; @@ -8669,6 +8828,8 @@ 27C9;SUPERSET PRECEDING SOLIDUS;Sm;0;ON;;;;;Y;;;;; 27CA;VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; 27CC;LONG DIVISION;Sm;0;ON;;;;;Y;;;;; +27CE;SQUARED LOGICAL AND;Sm;0;ON;;;;;N;;;;; +27CF;SQUARED LOGICAL OR;Sm;0;ON;;;;;N;;;;; 27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; 27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;; 27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;; @@ -9912,6 +10073,8 @@ 2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;;;; 2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;; 2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L; 2D61;;;;N;;;;; +2D70;TIFINAGH SEPARATOR MARK;Po;0;L;;;;;N;;;;; +2D7F;TIFINAGH CONSONANT JOINER;Mn;9;NSM;;;;;N;;;;; 2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;; 2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;; 2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;; @@ -10842,6 +11005,9 @@ 31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; 31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; 31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; +31B8;BOPOMOFO LETTER GH;Lo;0;L;;;;;N;;;;; +31B9;BOPOMOFO LETTER LH;Lo;0;L;;;;;N;;;;; +31BA;BOPOMOFO LETTER ZY;Lo;0;L;;;;;N;;;;; 31C0;CJK STROKE T;So;0;ON;;;;;N;;;;; 31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;; 31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;; @@ -13072,6 +13238,8 @@ A65C;CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS;Lu;0;L;;;;;N;;;;A65D; A65D;CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS;Ll;0;L;;;;;N;;;A65C;;A65C A65E;CYRILLIC CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;A65F; A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E +A660;CYRILLIC CAPITAL LETTER REVERSED TSE;Lu;0;L;;;;;N;;;;A661; +A661;CYRILLIC SMALL LETTER REVERSED TSE;Ll;0;L;;;;;N;;;A660;;A660 A662;CYRILLIC CAPITAL LETTER SOFT DE;Lu;0;L;;;;;N;;;;A663; A663;CYRILLIC SMALL LETTER SOFT DE;Ll;0;L;;;;;N;;;A662;;A662 A664;CYRILLIC CAPITAL LETTER SOFT EL;Lu;0;L;;;;;N;;;;A665; @@ -13347,6 +13515,21 @@ A789;MODIFIER LETTER COLON;Sk;0;L;;;;;N;;;;; A78A;MODIFIER LETTER SHORT EQUALS SIGN;Sk;0;L;;;;;N;;;;; A78B;LATIN CAPITAL LETTER SALTILLO;Lu;0;L;;;;;N;;;;A78C; A78C;LATIN SMALL LETTER SALTILLO;Ll;0;L;;;;;N;;;A78B;;A78B +A78D;LATIN CAPITAL LETTER TURNED H;Lu;0;L;;;;;N;;;;0265; +A78E;LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT;Ll;0;L;;;;;N;;;;; +A790;LATIN CAPITAL LETTER N WITH DESCENDER;Lu;0;L;;;;;N;;;;A791; +A791;LATIN SMALL LETTER N WITH DESCENDER;Ll;0;L;;;;;N;;;A790;;A790 +A7A0;LATIN CAPITAL LETTER G WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A1; +A7A1;LATIN SMALL LETTER G WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A0;;A7A0 +A7A2;LATIN CAPITAL LETTER K WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A3; +A7A3;LATIN SMALL LETTER K WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A2;;A7A2 +A7A4;LATIN CAPITAL LETTER N WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A5; +A7A5;LATIN SMALL LETTER N WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A4;;A7A4 +A7A6;LATIN CAPITAL LETTER R WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A7; +A7A7;LATIN SMALL LETTER R WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A6;;A7A6 +A7A8;LATIN CAPITAL LETTER S WITH OBLIQUE STROKE;Lu;0;L;;;;;N;;;;A7A9; +A7A9;LATIN SMALL LETTER S WITH OBLIQUE STROKE;Ll;0;L;;;;;N;;;A7A8;;A7A8 +A7FA;LATIN LETTER SMALL CAPITAL TURNED M;Ll;0;L;;;;;N;;;;; A7FB;LATIN EPIGRAPHIC LETTER REVERSED F;Lo;0;L;;;;;N;;;;; A7FC;LATIN EPIGRAPHIC LETTER REVERSED P;Lo;0;L;;;;;N;;;;; A7FD;LATIN EPIGRAPHIC LETTER INVERTED M;Lo;0;L;;;;;N;;;;; @@ -13959,6 +14142,38 @@ AADC;TAI VIET SYMBOL NUENG;Lo;0;L;;;;;N;;;;; AADD;TAI VIET SYMBOL SAM;Lm;0;L;;;;;N;;;;; AADE;TAI VIET SYMBOL HO HOI;Po;0;L;;;;;N;;;;; AADF;TAI VIET SYMBOL KOI KOI;Po;0;L;;;;;N;;;;; +AB01;ETHIOPIC SYLLABLE TTHU;Lo;0;L;;;;;N;;;;; +AB02;ETHIOPIC SYLLABLE TTHI;Lo;0;L;;;;;N;;;;; +AB03;ETHIOPIC SYLLABLE TTHAA;Lo;0;L;;;;;N;;;;; +AB04;ETHIOPIC SYLLABLE TTHEE;Lo;0;L;;;;;N;;;;; +AB05;ETHIOPIC SYLLABLE TTHE;Lo;0;L;;;;;N;;;;; +AB06;ETHIOPIC SYLLABLE TTHO;Lo;0;L;;;;;N;;;;; +AB09;ETHIOPIC SYLLABLE DDHU;Lo;0;L;;;;;N;;;;; +AB0A;ETHIOPIC SYLLABLE DDHI;Lo;0;L;;;;;N;;;;; +AB0B;ETHIOPIC SYLLABLE DDHAA;Lo;0;L;;;;;N;;;;; +AB0C;ETHIOPIC SYLLABLE DDHEE;Lo;0;L;;;;;N;;;;; +AB0D;ETHIOPIC SYLLABLE DDHE;Lo;0;L;;;;;N;;;;; +AB0E;ETHIOPIC SYLLABLE DDHO;Lo;0;L;;;;;N;;;;; +AB11;ETHIOPIC SYLLABLE DZU;Lo;0;L;;;;;N;;;;; +AB12;ETHIOPIC SYLLABLE DZI;Lo;0;L;;;;;N;;;;; +AB13;ETHIOPIC SYLLABLE DZAA;Lo;0;L;;;;;N;;;;; +AB14;ETHIOPIC SYLLABLE DZEE;Lo;0;L;;;;;N;;;;; +AB15;ETHIOPIC SYLLABLE DZE;Lo;0;L;;;;;N;;;;; +AB16;ETHIOPIC SYLLABLE DZO;Lo;0;L;;;;;N;;;;; +AB20;ETHIOPIC SYLLABLE CCHHA;Lo;0;L;;;;;N;;;;; +AB21;ETHIOPIC SYLLABLE CCHHU;Lo;0;L;;;;;N;;;;; +AB22;ETHIOPIC SYLLABLE CCHHI;Lo;0;L;;;;;N;;;;; +AB23;ETHIOPIC SYLLABLE CCHHAA;Lo;0;L;;;;;N;;;;; +AB24;ETHIOPIC SYLLABLE CCHHEE;Lo;0;L;;;;;N;;;;; +AB25;ETHIOPIC SYLLABLE CCHHE;Lo;0;L;;;;;N;;;;; +AB26;ETHIOPIC SYLLABLE CCHHO;Lo;0;L;;;;;N;;;;; +AB28;ETHIOPIC SYLLABLE BBA;Lo;0;L;;;;;N;;;;; +AB29;ETHIOPIC SYLLABLE BBU;Lo;0;L;;;;;N;;;;; +AB2A;ETHIOPIC SYLLABLE BBI;Lo;0;L;;;;;N;;;;; +AB2B;ETHIOPIC SYLLABLE BBAA;Lo;0;L;;;;;N;;;;; +AB2C;ETHIOPIC SYLLABLE BBEE;Lo;0;L;;;;;N;;;;; +AB2D;ETHIOPIC SYLLABLE BBE;Lo;0;L;;;;;N;;;;; +AB2E;ETHIOPIC SYLLABLE BBO;Lo;0;L;;;;;N;;;;; ABC0;MEETEI MAYEK LETTER KOK;Lo;0;L;;;;;N;;;;; ABC1;MEETEI MAYEK LETTER SAM;Lo;0;L;;;;;N;;;;; ABC2;MEETEI MAYEK LETTER LAI;Lo;0;L;;;;;N;;;;; @@ -14723,6 +14938,22 @@ FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL; 06D2;;;;N;;;;; FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL; 06D2;;;;N;;;;; FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 06D3;;;;N;;;;; FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 06D3;;;;N;;;;; +FBB2;ARABIC SYMBOL DOT ABOVE;Sk;0;AL;;;;;N;;;;; +FBB3;ARABIC SYMBOL DOT BELOW;Sk;0;AL;;;;;N;;;;; +FBB4;ARABIC SYMBOL TWO DOTS ABOVE;Sk;0;AL;;;;;N;;;;; +FBB5;ARABIC SYMBOL TWO DOTS BELOW;Sk;0;AL;;;;;N;;;;; +FBB6;ARABIC SYMBOL THREE DOTS ABOVE;Sk;0;AL;;;;;N;;;;; +FBB7;ARABIC SYMBOL THREE DOTS BELOW;Sk;0;AL;;;;;N;;;;; +FBB8;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE;Sk;0;AL;;;;;N;;;;; +FBB9;ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW;Sk;0;AL;;;;;N;;;;; +FBBA;ARABIC SYMBOL FOUR DOTS ABOVE;Sk;0;AL;;;;;N;;;;; +FBBB;ARABIC SYMBOL FOUR DOTS BELOW;Sk;0;AL;;;;;N;;;;; +FBBC;ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW;Sk;0;AL;;;;;N;;;;; +FBBD;ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE;Sk;0;AL;;;;;N;;;;; +FBBE;ARABIC SYMBOL TWO DOTS VERTICALLY BELOW;Sk;0;AL;;;;;N;;;;; +FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;; +FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;; +FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;; FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;; FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; @@ -16933,6 +17164,114 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;; 10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;; 10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;; +11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; +11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11003;BRAHMI SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; +11004;BRAHMI SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +11005;BRAHMI LETTER A;Lo;0;L;;;;;N;;;;; +11006;BRAHMI LETTER AA;Lo;0;L;;;;;N;;;;; +11007;BRAHMI LETTER I;Lo;0;L;;;;;N;;;;; +11008;BRAHMI LETTER II;Lo;0;L;;;;;N;;;;; +11009;BRAHMI LETTER U;Lo;0;L;;;;;N;;;;; +1100A;BRAHMI LETTER UU;Lo;0;L;;;;;N;;;;; +1100B;BRAHMI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1100C;BRAHMI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1100D;BRAHMI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1100E;BRAHMI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1100F;BRAHMI LETTER E;Lo;0;L;;;;;N;;;;; +11010;BRAHMI LETTER AI;Lo;0;L;;;;;N;;;;; +11011;BRAHMI LETTER O;Lo;0;L;;;;;N;;;;; +11012;BRAHMI LETTER AU;Lo;0;L;;;;;N;;;;; +11013;BRAHMI LETTER KA;Lo;0;L;;;;;N;;;;; +11014;BRAHMI LETTER KHA;Lo;0;L;;;;;N;;;;; +11015;BRAHMI LETTER GA;Lo;0;L;;;;;N;;;;; +11016;BRAHMI LETTER GHA;Lo;0;L;;;;;N;;;;; +11017;BRAHMI LETTER NGA;Lo;0;L;;;;;N;;;;; +11018;BRAHMI LETTER CA;Lo;0;L;;;;;N;;;;; +11019;BRAHMI LETTER CHA;Lo;0;L;;;;;N;;;;; +1101A;BRAHMI LETTER JA;Lo;0;L;;;;;N;;;;; +1101B;BRAHMI LETTER JHA;Lo;0;L;;;;;N;;;;; +1101C;BRAHMI LETTER NYA;Lo;0;L;;;;;N;;;;; +1101D;BRAHMI LETTER TTA;Lo;0;L;;;;;N;;;;; +1101E;BRAHMI LETTER TTHA;Lo;0;L;;;;;N;;;;; +1101F;BRAHMI LETTER DDA;Lo;0;L;;;;;N;;;;; +11020;BRAHMI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11021;BRAHMI LETTER NNA;Lo;0;L;;;;;N;;;;; +11022;BRAHMI LETTER TA;Lo;0;L;;;;;N;;;;; +11023;BRAHMI LETTER THA;Lo;0;L;;;;;N;;;;; +11024;BRAHMI LETTER DA;Lo;0;L;;;;;N;;;;; +11025;BRAHMI LETTER DHA;Lo;0;L;;;;;N;;;;; +11026;BRAHMI LETTER NA;Lo;0;L;;;;;N;;;;; +11027;BRAHMI LETTER PA;Lo;0;L;;;;;N;;;;; +11028;BRAHMI LETTER PHA;Lo;0;L;;;;;N;;;;; +11029;BRAHMI LETTER BA;Lo;0;L;;;;;N;;;;; +1102A;BRAHMI LETTER BHA;Lo;0;L;;;;;N;;;;; +1102B;BRAHMI LETTER MA;Lo;0;L;;;;;N;;;;; +1102C;BRAHMI LETTER YA;Lo;0;L;;;;;N;;;;; +1102D;BRAHMI LETTER RA;Lo;0;L;;;;;N;;;;; +1102E;BRAHMI LETTER LA;Lo;0;L;;;;;N;;;;; +1102F;BRAHMI LETTER VA;Lo;0;L;;;;;N;;;;; +11030;BRAHMI LETTER SHA;Lo;0;L;;;;;N;;;;; +11031;BRAHMI LETTER SSA;Lo;0;L;;;;;N;;;;; +11032;BRAHMI LETTER SA;Lo;0;L;;;;;N;;;;; +11033;BRAHMI LETTER HA;Lo;0;L;;;;;N;;;;; +11034;BRAHMI LETTER LLA;Lo;0;L;;;;;N;;;;; +11035;BRAHMI LETTER OLD TAMIL LLLA;Lo;0;L;;;;;N;;;;; +11036;BRAHMI LETTER OLD TAMIL RRA;Lo;0;L;;;;;N;;;;; +11037;BRAHMI LETTER OLD TAMIL NNNA;Lo;0;L;;;;;N;;;;; +11038;BRAHMI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11039;BRAHMI VOWEL SIGN BHATTIPROLU AA;Mn;0;NSM;;;;;N;;;;; +1103A;BRAHMI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1103B;BRAHMI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +1103C;BRAHMI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1103D;BRAHMI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1103E;BRAHMI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +1103F;BRAHMI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11040;BRAHMI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11041;BRAHMI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +11042;BRAHMI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11043;BRAHMI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11044;BRAHMI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11045;BRAHMI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11046;BRAHMI VIRAMA;Mn;9;NSM;;;;;N;;;;; +11047;BRAHMI DANDA;Po;0;L;;;;;N;;;;; +11048;BRAHMI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11049;BRAHMI PUNCTUATION DOT;Po;0;L;;;;;N;;;;; +1104A;BRAHMI PUNCTUATION DOUBLE DOT;Po;0;L;;;;;N;;;;; +1104B;BRAHMI PUNCTUATION LINE;Po;0;L;;;;;N;;;;; +1104C;BRAHMI PUNCTUATION CRESCENT BAR;Po;0;L;;;;;N;;;;; +1104D;BRAHMI PUNCTUATION LOTUS;Po;0;L;;;;;N;;;;; +11052;BRAHMI NUMBER ONE;No;0;ON;;;1;1;N;;;;; +11053;BRAHMI NUMBER TWO;No;0;ON;;;2;2;N;;;;; +11054;BRAHMI NUMBER THREE;No;0;ON;;;3;3;N;;;;; +11055;BRAHMI NUMBER FOUR;No;0;ON;;;4;4;N;;;;; +11056;BRAHMI NUMBER FIVE;No;0;ON;;;5;5;N;;;;; +11057;BRAHMI NUMBER SIX;No;0;ON;;;6;6;N;;;;; +11058;BRAHMI NUMBER SEVEN;No;0;ON;;;7;7;N;;;;; +11059;BRAHMI NUMBER EIGHT;No;0;ON;;;8;8;N;;;;; +1105A;BRAHMI NUMBER NINE;No;0;ON;;;9;9;N;;;;; +1105B;BRAHMI NUMBER TEN;No;0;ON;;;;10;N;;;;; +1105C;BRAHMI NUMBER TWENTY;No;0;ON;;;;20;N;;;;; +1105D;BRAHMI NUMBER THIRTY;No;0;ON;;;;30;N;;;;; +1105E;BRAHMI NUMBER FORTY;No;0;ON;;;;40;N;;;;; +1105F;BRAHMI NUMBER FIFTY;No;0;ON;;;;50;N;;;;; +11060;BRAHMI NUMBER SIXTY;No;0;ON;;;;60;N;;;;; +11061;BRAHMI NUMBER SEVENTY;No;0;ON;;;;70;N;;;;; +11062;BRAHMI NUMBER EIGHTY;No;0;ON;;;;80;N;;;;; +11063;BRAHMI NUMBER NINETY;No;0;ON;;;;90;N;;;;; +11064;BRAHMI NUMBER ONE HUNDRED;No;0;ON;;;;100;N;;;;; +11065;BRAHMI NUMBER ONE THOUSAND;No;0;ON;;;;1000;N;;;;; +11066;BRAHMI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11067;BRAHMI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11068;BRAHMI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11069;BRAHMI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1106A;BRAHMI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1106B;BRAHMI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1106C;BRAHMI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1106D;BRAHMI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1106E;BRAHMI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1106F;BRAHMI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 11080;KAITHI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 11081;KAITHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; 11082;KAITHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -19052,6 +19391,577 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1342C;EGYPTIAN HIEROGLYPH AA030;Lo;0;L;;;;;N;;;;; 1342D;EGYPTIAN HIEROGLYPH AA031;Lo;0;L;;;;;N;;;;; 1342E;EGYPTIAN HIEROGLYPH AA032;Lo;0;L;;;;;N;;;;; +16800;BAMUM LETTER PHASE-A NGKUE MFON;Lo;0;L;;;;;N;;;;; +16801;BAMUM LETTER PHASE-A GBIEE FON;Lo;0;L;;;;;N;;;;; +16802;BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; +16803;BAMUM LETTER PHASE-A PON MFON PIPAEMBA;Lo;0;L;;;;;N;;;;; +16804;BAMUM LETTER PHASE-A NAA MFON;Lo;0;L;;;;;N;;;;; +16805;BAMUM LETTER PHASE-A SHUENSHUET;Lo;0;L;;;;;N;;;;; +16806;BAMUM LETTER PHASE-A TITA MFON;Lo;0;L;;;;;N;;;;; +16807;BAMUM LETTER PHASE-A NZA MFON;Lo;0;L;;;;;N;;;;; +16808;BAMUM LETTER PHASE-A SHINDA PA NJI;Lo;0;L;;;;;N;;;;; +16809;BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE;Lo;0;L;;;;;N;;;;; +1680A;BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA;Lo;0;L;;;;;N;;;;; +1680B;BAMUM LETTER PHASE-A MAEMBGBIEE;Lo;0;L;;;;;N;;;;; +1680C;BAMUM LETTER PHASE-A TU MAEMBA;Lo;0;L;;;;;N;;;;; +1680D;BAMUM LETTER PHASE-A NGANGU;Lo;0;L;;;;;N;;;;; +1680E;BAMUM LETTER PHASE-A MAEMVEUX;Lo;0;L;;;;;N;;;;; +1680F;BAMUM LETTER PHASE-A MANSUAE;Lo;0;L;;;;;N;;;;; +16810;BAMUM LETTER PHASE-A MVEUAENGAM;Lo;0;L;;;;;N;;;;; +16811;BAMUM LETTER PHASE-A SEUNYAM;Lo;0;L;;;;;N;;;;; +16812;BAMUM LETTER PHASE-A NTOQPEN;Lo;0;L;;;;;N;;;;; +16813;BAMUM LETTER PHASE-A KEUKEUTNDA;Lo;0;L;;;;;N;;;;; +16814;BAMUM LETTER PHASE-A NKINDI;Lo;0;L;;;;;N;;;;; +16815;BAMUM LETTER PHASE-A SUU;Lo;0;L;;;;;N;;;;; +16816;BAMUM LETTER PHASE-A NGKUENZEUM;Lo;0;L;;;;;N;;;;; +16817;BAMUM LETTER PHASE-A LAPAQ;Lo;0;L;;;;;N;;;;; +16818;BAMUM LETTER PHASE-A LET KUT;Lo;0;L;;;;;N;;;;; +16819;BAMUM LETTER PHASE-A NTAP MFAA;Lo;0;L;;;;;N;;;;; +1681A;BAMUM LETTER PHASE-A MAEKEUP;Lo;0;L;;;;;N;;;;; +1681B;BAMUM LETTER PHASE-A PASHAE;Lo;0;L;;;;;N;;;;; +1681C;BAMUM LETTER PHASE-A GHEUAERAE;Lo;0;L;;;;;N;;;;; +1681D;BAMUM LETTER PHASE-A PAMSHAE;Lo;0;L;;;;;N;;;;; +1681E;BAMUM LETTER PHASE-A MON NGGEUAET;Lo;0;L;;;;;N;;;;; +1681F;BAMUM LETTER PHASE-A NZUN MEUT;Lo;0;L;;;;;N;;;;; +16820;BAMUM LETTER PHASE-A U YUQ NAE;Lo;0;L;;;;;N;;;;; +16821;BAMUM LETTER PHASE-A GHEUAEGHEUAE;Lo;0;L;;;;;N;;;;; +16822;BAMUM LETTER PHASE-A NTAP NTAA;Lo;0;L;;;;;N;;;;; +16823;BAMUM LETTER PHASE-A SISA;Lo;0;L;;;;;N;;;;; +16824;BAMUM LETTER PHASE-A MGBASA;Lo;0;L;;;;;N;;;;; +16825;BAMUM LETTER PHASE-A MEUNJOMNDEUQ;Lo;0;L;;;;;N;;;;; +16826;BAMUM LETTER PHASE-A MOOMPUQ;Lo;0;L;;;;;N;;;;; +16827;BAMUM LETTER PHASE-A KAFA;Lo;0;L;;;;;N;;;;; +16828;BAMUM LETTER PHASE-A PA LEERAEWA;Lo;0;L;;;;;N;;;;; +16829;BAMUM LETTER PHASE-A NDA LEERAEWA;Lo;0;L;;;;;N;;;;; +1682A;BAMUM LETTER PHASE-A PET;Lo;0;L;;;;;N;;;;; +1682B;BAMUM LETTER PHASE-A MAEMKPEN;Lo;0;L;;;;;N;;;;; +1682C;BAMUM LETTER PHASE-A NIKA;Lo;0;L;;;;;N;;;;; +1682D;BAMUM LETTER PHASE-A PUP;Lo;0;L;;;;;N;;;;; +1682E;BAMUM LETTER PHASE-A TUAEP;Lo;0;L;;;;;N;;;;; +1682F;BAMUM LETTER PHASE-A LUAEP;Lo;0;L;;;;;N;;;;; +16830;BAMUM LETTER PHASE-A SONJAM;Lo;0;L;;;;;N;;;;; +16831;BAMUM LETTER PHASE-A TEUTEUWEN;Lo;0;L;;;;;N;;;;; +16832;BAMUM LETTER PHASE-A MAENYI;Lo;0;L;;;;;N;;;;; +16833;BAMUM LETTER PHASE-A KET;Lo;0;L;;;;;N;;;;; +16834;BAMUM LETTER PHASE-A NDAANGGEUAET;Lo;0;L;;;;;N;;;;; +16835;BAMUM LETTER PHASE-A KUOQ;Lo;0;L;;;;;N;;;;; +16836;BAMUM LETTER PHASE-A MOOMEUT;Lo;0;L;;;;;N;;;;; +16837;BAMUM LETTER PHASE-A SHUM;Lo;0;L;;;;;N;;;;; +16838;BAMUM LETTER PHASE-A LOMMAE;Lo;0;L;;;;;N;;;;; +16839;BAMUM LETTER PHASE-A FIRI;Lo;0;L;;;;;N;;;;; +1683A;BAMUM LETTER PHASE-A ROM;Lo;0;L;;;;;N;;;;; +1683B;BAMUM LETTER PHASE-A KPOQ;Lo;0;L;;;;;N;;;;; +1683C;BAMUM LETTER PHASE-A SOQ;Lo;0;L;;;;;N;;;;; +1683D;BAMUM LETTER PHASE-A MAP PIEET;Lo;0;L;;;;;N;;;;; +1683E;BAMUM LETTER PHASE-A SHIRAE;Lo;0;L;;;;;N;;;;; +1683F;BAMUM LETTER PHASE-A NTAP;Lo;0;L;;;;;N;;;;; +16840;BAMUM LETTER PHASE-A SHOQ NSHUT YUM;Lo;0;L;;;;;N;;;;; +16841;BAMUM LETTER PHASE-A NYIT MONGKEUAEQ;Lo;0;L;;;;;N;;;;; +16842;BAMUM LETTER PHASE-A PAARAE;Lo;0;L;;;;;N;;;;; +16843;BAMUM LETTER PHASE-A NKAARAE;Lo;0;L;;;;;N;;;;; +16844;BAMUM LETTER PHASE-A UNKNOWN;Lo;0;L;;;;;N;;;;; +16845;BAMUM LETTER PHASE-A NGGEN;Lo;0;L;;;;;N;;;;; +16846;BAMUM LETTER PHASE-A MAESI;Lo;0;L;;;;;N;;;;; +16847;BAMUM LETTER PHASE-A NJAM;Lo;0;L;;;;;N;;;;; +16848;BAMUM LETTER PHASE-A MBANYI;Lo;0;L;;;;;N;;;;; +16849;BAMUM LETTER PHASE-A NYET;Lo;0;L;;;;;N;;;;; +1684A;BAMUM LETTER PHASE-A TEUAEN;Lo;0;L;;;;;N;;;;; +1684B;BAMUM LETTER PHASE-A SOT;Lo;0;L;;;;;N;;;;; +1684C;BAMUM LETTER PHASE-A PAAM;Lo;0;L;;;;;N;;;;; +1684D;BAMUM LETTER PHASE-A NSHIEE;Lo;0;L;;;;;N;;;;; +1684E;BAMUM LETTER PHASE-A MAEM;Lo;0;L;;;;;N;;;;; +1684F;BAMUM LETTER PHASE-A NYI;Lo;0;L;;;;;N;;;;; +16850;BAMUM LETTER PHASE-A KAQ;Lo;0;L;;;;;N;;;;; +16851;BAMUM LETTER PHASE-A NSHA;Lo;0;L;;;;;N;;;;; +16852;BAMUM LETTER PHASE-A VEE;Lo;0;L;;;;;N;;;;; +16853;BAMUM LETTER PHASE-A LU;Lo;0;L;;;;;N;;;;; +16854;BAMUM LETTER PHASE-A NEN;Lo;0;L;;;;;N;;;;; +16855;BAMUM LETTER PHASE-A NAQ;Lo;0;L;;;;;N;;;;; +16856;BAMUM LETTER PHASE-A MBAQ;Lo;0;L;;;;;N;;;;; +16857;BAMUM LETTER PHASE-B NSHUET;Lo;0;L;;;;;N;;;;; +16858;BAMUM LETTER PHASE-B TU MAEMGBIEE;Lo;0;L;;;;;N;;;;; +16859;BAMUM LETTER PHASE-B SIEE;Lo;0;L;;;;;N;;;;; +1685A;BAMUM LETTER PHASE-B SET TU;Lo;0;L;;;;;N;;;;; +1685B;BAMUM LETTER PHASE-B LOM NTEUM;Lo;0;L;;;;;N;;;;; +1685C;BAMUM LETTER PHASE-B MBA MAELEE;Lo;0;L;;;;;N;;;;; +1685D;BAMUM LETTER PHASE-B KIEEM;Lo;0;L;;;;;N;;;;; +1685E;BAMUM LETTER PHASE-B YEURAE;Lo;0;L;;;;;N;;;;; +1685F;BAMUM LETTER PHASE-B MBAARAE;Lo;0;L;;;;;N;;;;; +16860;BAMUM LETTER PHASE-B KAM;Lo;0;L;;;;;N;;;;; +16861;BAMUM LETTER PHASE-B PEESHI;Lo;0;L;;;;;N;;;;; +16862;BAMUM LETTER PHASE-B YAFU LEERAEWA;Lo;0;L;;;;;N;;;;; +16863;BAMUM LETTER PHASE-B LAM NSHUT NYAM;Lo;0;L;;;;;N;;;;; +16864;BAMUM LETTER PHASE-B NTIEE SHEUOQ;Lo;0;L;;;;;N;;;;; +16865;BAMUM LETTER PHASE-B NDU NJAA;Lo;0;L;;;;;N;;;;; +16866;BAMUM LETTER PHASE-B GHEUGHEUAEM;Lo;0;L;;;;;N;;;;; +16867;BAMUM LETTER PHASE-B PIT;Lo;0;L;;;;;N;;;;; +16868;BAMUM LETTER PHASE-B TU NSIEE;Lo;0;L;;;;;N;;;;; +16869;BAMUM LETTER PHASE-B SHET NJAQ;Lo;0;L;;;;;N;;;;; +1686A;BAMUM LETTER PHASE-B SHEUAEQTU;Lo;0;L;;;;;N;;;;; +1686B;BAMUM LETTER PHASE-B MFON TEUAEQ;Lo;0;L;;;;;N;;;;; +1686C;BAMUM LETTER PHASE-B MBIT MBAAKET;Lo;0;L;;;;;N;;;;; +1686D;BAMUM LETTER PHASE-B NYI NTEUM;Lo;0;L;;;;;N;;;;; +1686E;BAMUM LETTER PHASE-B KEUPUQ;Lo;0;L;;;;;N;;;;; +1686F;BAMUM LETTER PHASE-B GHEUGHEN;Lo;0;L;;;;;N;;;;; +16870;BAMUM LETTER PHASE-B KEUYEUX;Lo;0;L;;;;;N;;;;; +16871;BAMUM LETTER PHASE-B LAANAE;Lo;0;L;;;;;N;;;;; +16872;BAMUM LETTER PHASE-B PARUM;Lo;0;L;;;;;N;;;;; +16873;BAMUM LETTER PHASE-B VEUM;Lo;0;L;;;;;N;;;;; +16874;BAMUM LETTER PHASE-B NGKINDI MVOP;Lo;0;L;;;;;N;;;;; +16875;BAMUM LETTER PHASE-B NGGEU MBU;Lo;0;L;;;;;N;;;;; +16876;BAMUM LETTER PHASE-B WUAET;Lo;0;L;;;;;N;;;;; +16877;BAMUM LETTER PHASE-B SAKEUAE;Lo;0;L;;;;;N;;;;; +16878;BAMUM LETTER PHASE-B TAAM;Lo;0;L;;;;;N;;;;; +16879;BAMUM LETTER PHASE-B MEUQ;Lo;0;L;;;;;N;;;;; +1687A;BAMUM LETTER PHASE-B NGGUOQ;Lo;0;L;;;;;N;;;;; +1687B;BAMUM LETTER PHASE-B NGGUOQ LARGE;Lo;0;L;;;;;N;;;;; +1687C;BAMUM LETTER PHASE-B MFIYAQ;Lo;0;L;;;;;N;;;;; +1687D;BAMUM LETTER PHASE-B SUE;Lo;0;L;;;;;N;;;;; +1687E;BAMUM LETTER PHASE-B MBEURI;Lo;0;L;;;;;N;;;;; +1687F;BAMUM LETTER PHASE-B MONTIEEN;Lo;0;L;;;;;N;;;;; +16880;BAMUM LETTER PHASE-B NYAEMAE;Lo;0;L;;;;;N;;;;; +16881;BAMUM LETTER PHASE-B PUNGAAM;Lo;0;L;;;;;N;;;;; +16882;BAMUM LETTER PHASE-B MEUT NGGEET;Lo;0;L;;;;;N;;;;; +16883;BAMUM LETTER PHASE-B FEUX;Lo;0;L;;;;;N;;;;; +16884;BAMUM LETTER PHASE-B MBUOQ;Lo;0;L;;;;;N;;;;; +16885;BAMUM LETTER PHASE-B FEE;Lo;0;L;;;;;N;;;;; +16886;BAMUM LETTER PHASE-B KEUAEM;Lo;0;L;;;;;N;;;;; +16887;BAMUM LETTER PHASE-B MA NJEUAENA;Lo;0;L;;;;;N;;;;; +16888;BAMUM LETTER PHASE-B MA NJUQA;Lo;0;L;;;;;N;;;;; +16889;BAMUM LETTER PHASE-B LET;Lo;0;L;;;;;N;;;;; +1688A;BAMUM LETTER PHASE-B NGGAAM;Lo;0;L;;;;;N;;;;; +1688B;BAMUM LETTER PHASE-B NSEN;Lo;0;L;;;;;N;;;;; +1688C;BAMUM LETTER PHASE-B MA;Lo;0;L;;;;;N;;;;; +1688D;BAMUM LETTER PHASE-B KIQ;Lo;0;L;;;;;N;;;;; +1688E;BAMUM LETTER PHASE-B NGOM;Lo;0;L;;;;;N;;;;; +1688F;BAMUM LETTER PHASE-C NGKUE MAEMBA;Lo;0;L;;;;;N;;;;; +16890;BAMUM LETTER PHASE-C NZA;Lo;0;L;;;;;N;;;;; +16891;BAMUM LETTER PHASE-C YUM;Lo;0;L;;;;;N;;;;; +16892;BAMUM LETTER PHASE-C WANGKUOQ;Lo;0;L;;;;;N;;;;; +16893;BAMUM LETTER PHASE-C NGGEN;Lo;0;L;;;;;N;;;;; +16894;BAMUM LETTER PHASE-C NDEUAEREE;Lo;0;L;;;;;N;;;;; +16895;BAMUM LETTER PHASE-C NGKAQ;Lo;0;L;;;;;N;;;;; +16896;BAMUM LETTER PHASE-C GHARAE;Lo;0;L;;;;;N;;;;; +16897;BAMUM LETTER PHASE-C MBEEKEET;Lo;0;L;;;;;N;;;;; +16898;BAMUM LETTER PHASE-C GBAYI;Lo;0;L;;;;;N;;;;; +16899;BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN;Lo;0;L;;;;;N;;;;; +1689A;BAMUM LETTER PHASE-C NTU MBIT;Lo;0;L;;;;;N;;;;; +1689B;BAMUM LETTER PHASE-C MBEUM;Lo;0;L;;;;;N;;;;; +1689C;BAMUM LETTER PHASE-C PIRIEEN;Lo;0;L;;;;;N;;;;; +1689D;BAMUM LETTER PHASE-C NDOMBU;Lo;0;L;;;;;N;;;;; +1689E;BAMUM LETTER PHASE-C MBAA CABBAGE-TREE;Lo;0;L;;;;;N;;;;; +1689F;BAMUM LETTER PHASE-C KEUSHEUAEP;Lo;0;L;;;;;N;;;;; +168A0;BAMUM LETTER PHASE-C GHAP;Lo;0;L;;;;;N;;;;; +168A1;BAMUM LETTER PHASE-C KEUKAQ;Lo;0;L;;;;;N;;;;; +168A2;BAMUM LETTER PHASE-C YU MUOMAE;Lo;0;L;;;;;N;;;;; +168A3;BAMUM LETTER PHASE-C NZEUM;Lo;0;L;;;;;N;;;;; +168A4;BAMUM LETTER PHASE-C MBUE;Lo;0;L;;;;;N;;;;; +168A5;BAMUM LETTER PHASE-C NSEUAEN;Lo;0;L;;;;;N;;;;; +168A6;BAMUM LETTER PHASE-C MBIT;Lo;0;L;;;;;N;;;;; +168A7;BAMUM LETTER PHASE-C YEUQ;Lo;0;L;;;;;N;;;;; +168A8;BAMUM LETTER PHASE-C KPARAQ;Lo;0;L;;;;;N;;;;; +168A9;BAMUM LETTER PHASE-C KAA;Lo;0;L;;;;;N;;;;; +168AA;BAMUM LETTER PHASE-C SEUX;Lo;0;L;;;;;N;;;;; +168AB;BAMUM LETTER PHASE-C NDIDA;Lo;0;L;;;;;N;;;;; +168AC;BAMUM LETTER PHASE-C TAASHAE;Lo;0;L;;;;;N;;;;; +168AD;BAMUM LETTER PHASE-C NJUEQ;Lo;0;L;;;;;N;;;;; +168AE;BAMUM LETTER PHASE-C TITA YUE;Lo;0;L;;;;;N;;;;; +168AF;BAMUM LETTER PHASE-C SUAET;Lo;0;L;;;;;N;;;;; +168B0;BAMUM LETTER PHASE-C NGGUAEN NYAM;Lo;0;L;;;;;N;;;;; +168B1;BAMUM LETTER PHASE-C VEUX;Lo;0;L;;;;;N;;;;; +168B2;BAMUM LETTER PHASE-C NANSANAQ;Lo;0;L;;;;;N;;;;; +168B3;BAMUM LETTER PHASE-C MA KEUAERI;Lo;0;L;;;;;N;;;;; +168B4;BAMUM LETTER PHASE-C NTAA;Lo;0;L;;;;;N;;;;; +168B5;BAMUM LETTER PHASE-C NGGUON;Lo;0;L;;;;;N;;;;; +168B6;BAMUM LETTER PHASE-C LAP;Lo;0;L;;;;;N;;;;; +168B7;BAMUM LETTER PHASE-C MBIRIEEN;Lo;0;L;;;;;N;;;;; +168B8;BAMUM LETTER PHASE-C MGBASAQ;Lo;0;L;;;;;N;;;;; +168B9;BAMUM LETTER PHASE-C NTEUNGBA;Lo;0;L;;;;;N;;;;; +168BA;BAMUM LETTER PHASE-C TEUTEUX;Lo;0;L;;;;;N;;;;; +168BB;BAMUM LETTER PHASE-C NGGUM;Lo;0;L;;;;;N;;;;; +168BC;BAMUM LETTER PHASE-C FUE;Lo;0;L;;;;;N;;;;; +168BD;BAMUM LETTER PHASE-C NDEUT;Lo;0;L;;;;;N;;;;; +168BE;BAMUM LETTER PHASE-C NSA;Lo;0;L;;;;;N;;;;; +168BF;BAMUM LETTER PHASE-C NSHAQ;Lo;0;L;;;;;N;;;;; +168C0;BAMUM LETTER PHASE-C BUNG;Lo;0;L;;;;;N;;;;; +168C1;BAMUM LETTER PHASE-C VEUAEPEN;Lo;0;L;;;;;N;;;;; +168C2;BAMUM LETTER PHASE-C MBERAE;Lo;0;L;;;;;N;;;;; +168C3;BAMUM LETTER PHASE-C RU;Lo;0;L;;;;;N;;;;; +168C4;BAMUM LETTER PHASE-C NJAEM;Lo;0;L;;;;;N;;;;; +168C5;BAMUM LETTER PHASE-C LAM;Lo;0;L;;;;;N;;;;; +168C6;BAMUM LETTER PHASE-C TITUAEP;Lo;0;L;;;;;N;;;;; +168C7;BAMUM LETTER PHASE-C NSUOT NGOM;Lo;0;L;;;;;N;;;;; +168C8;BAMUM LETTER PHASE-C NJEEEE;Lo;0;L;;;;;N;;;;; +168C9;BAMUM LETTER PHASE-C KET;Lo;0;L;;;;;N;;;;; +168CA;BAMUM LETTER PHASE-C NGGU;Lo;0;L;;;;;N;;;;; +168CB;BAMUM LETTER PHASE-C MAESI;Lo;0;L;;;;;N;;;;; +168CC;BAMUM LETTER PHASE-C MBUAEM;Lo;0;L;;;;;N;;;;; +168CD;BAMUM LETTER PHASE-C LU;Lo;0;L;;;;;N;;;;; +168CE;BAMUM LETTER PHASE-C KUT;Lo;0;L;;;;;N;;;;; +168CF;BAMUM LETTER PHASE-C NJAM;Lo;0;L;;;;;N;;;;; +168D0;BAMUM LETTER PHASE-C NGOM;Lo;0;L;;;;;N;;;;; +168D1;BAMUM LETTER PHASE-C WUP;Lo;0;L;;;;;N;;;;; +168D2;BAMUM LETTER PHASE-C NGGUEET;Lo;0;L;;;;;N;;;;; +168D3;BAMUM LETTER PHASE-C NSOM;Lo;0;L;;;;;N;;;;; +168D4;BAMUM LETTER PHASE-C NTEN;Lo;0;L;;;;;N;;;;; +168D5;BAMUM LETTER PHASE-C KUOP NKAARAE;Lo;0;L;;;;;N;;;;; +168D6;BAMUM LETTER PHASE-C NSUN;Lo;0;L;;;;;N;;;;; +168D7;BAMUM LETTER PHASE-C NDAM;Lo;0;L;;;;;N;;;;; +168D8;BAMUM LETTER PHASE-C MA NSIEE;Lo;0;L;;;;;N;;;;; +168D9;BAMUM LETTER PHASE-C YAA;Lo;0;L;;;;;N;;;;; +168DA;BAMUM LETTER PHASE-C NDAP;Lo;0;L;;;;;N;;;;; +168DB;BAMUM LETTER PHASE-C SHUEQ;Lo;0;L;;;;;N;;;;; +168DC;BAMUM LETTER PHASE-C SETFON;Lo;0;L;;;;;N;;;;; +168DD;BAMUM LETTER PHASE-C MBI;Lo;0;L;;;;;N;;;;; +168DE;BAMUM LETTER PHASE-C MAEMBA;Lo;0;L;;;;;N;;;;; +168DF;BAMUM LETTER PHASE-C MBANYI;Lo;0;L;;;;;N;;;;; +168E0;BAMUM LETTER PHASE-C KEUSEUX;Lo;0;L;;;;;N;;;;; +168E1;BAMUM LETTER PHASE-C MBEUX;Lo;0;L;;;;;N;;;;; +168E2;BAMUM LETTER PHASE-C KEUM;Lo;0;L;;;;;N;;;;; +168E3;BAMUM LETTER PHASE-C MBAA PICKET;Lo;0;L;;;;;N;;;;; +168E4;BAMUM LETTER PHASE-C YUWOQ;Lo;0;L;;;;;N;;;;; +168E5;BAMUM LETTER PHASE-C NJEUX;Lo;0;L;;;;;N;;;;; +168E6;BAMUM LETTER PHASE-C MIEE;Lo;0;L;;;;;N;;;;; +168E7;BAMUM LETTER PHASE-C MUAE;Lo;0;L;;;;;N;;;;; +168E8;BAMUM LETTER PHASE-C SHIQ;Lo;0;L;;;;;N;;;;; +168E9;BAMUM LETTER PHASE-C KEN LAW;Lo;0;L;;;;;N;;;;; +168EA;BAMUM LETTER PHASE-C KEN FATIGUE;Lo;0;L;;;;;N;;;;; +168EB;BAMUM LETTER PHASE-C NGAQ;Lo;0;L;;;;;N;;;;; +168EC;BAMUM LETTER PHASE-C NAQ;Lo;0;L;;;;;N;;;;; +168ED;BAMUM LETTER PHASE-C LIQ;Lo;0;L;;;;;N;;;;; +168EE;BAMUM LETTER PHASE-C PIN;Lo;0;L;;;;;N;;;;; +168EF;BAMUM LETTER PHASE-C PEN;Lo;0;L;;;;;N;;;;; +168F0;BAMUM LETTER PHASE-C TET;Lo;0;L;;;;;N;;;;; +168F1;BAMUM LETTER PHASE-D MBUO;Lo;0;L;;;;;N;;;;; +168F2;BAMUM LETTER PHASE-D WAP;Lo;0;L;;;;;N;;;;; +168F3;BAMUM LETTER PHASE-D NJI;Lo;0;L;;;;;N;;;;; +168F4;BAMUM LETTER PHASE-D MFON;Lo;0;L;;;;;N;;;;; +168F5;BAMUM LETTER PHASE-D NJIEE;Lo;0;L;;;;;N;;;;; +168F6;BAMUM LETTER PHASE-D LIEE;Lo;0;L;;;;;N;;;;; +168F7;BAMUM LETTER PHASE-D NJEUT;Lo;0;L;;;;;N;;;;; +168F8;BAMUM LETTER PHASE-D NSHEE;Lo;0;L;;;;;N;;;;; +168F9;BAMUM LETTER PHASE-D NGGAAMAE;Lo;0;L;;;;;N;;;;; +168FA;BAMUM LETTER PHASE-D NYAM;Lo;0;L;;;;;N;;;;; +168FB;BAMUM LETTER PHASE-D WUAEN;Lo;0;L;;;;;N;;;;; +168FC;BAMUM LETTER PHASE-D NGKUN;Lo;0;L;;;;;N;;;;; +168FD;BAMUM LETTER PHASE-D SHEE;Lo;0;L;;;;;N;;;;; +168FE;BAMUM LETTER PHASE-D NGKAP;Lo;0;L;;;;;N;;;;; +168FF;BAMUM LETTER PHASE-D KEUAETMEUN;Lo;0;L;;;;;N;;;;; +16900;BAMUM LETTER PHASE-D TEUT;Lo;0;L;;;;;N;;;;; +16901;BAMUM LETTER PHASE-D SHEUAE;Lo;0;L;;;;;N;;;;; +16902;BAMUM LETTER PHASE-D NJAP;Lo;0;L;;;;;N;;;;; +16903;BAMUM LETTER PHASE-D SUE;Lo;0;L;;;;;N;;;;; +16904;BAMUM LETTER PHASE-D KET;Lo;0;L;;;;;N;;;;; +16905;BAMUM LETTER PHASE-D YAEMMAE;Lo;0;L;;;;;N;;;;; +16906;BAMUM LETTER PHASE-D KUOM;Lo;0;L;;;;;N;;;;; +16907;BAMUM LETTER PHASE-D SAP;Lo;0;L;;;;;N;;;;; +16908;BAMUM LETTER PHASE-D MFEUT;Lo;0;L;;;;;N;;;;; +16909;BAMUM LETTER PHASE-D NDEUX;Lo;0;L;;;;;N;;;;; +1690A;BAMUM LETTER PHASE-D MALEERI;Lo;0;L;;;;;N;;;;; +1690B;BAMUM LETTER PHASE-D MEUT;Lo;0;L;;;;;N;;;;; +1690C;BAMUM LETTER PHASE-D SEUAEQ;Lo;0;L;;;;;N;;;;; +1690D;BAMUM LETTER PHASE-D YEN;Lo;0;L;;;;;N;;;;; +1690E;BAMUM LETTER PHASE-D NJEUAEM;Lo;0;L;;;;;N;;;;; +1690F;BAMUM LETTER PHASE-D KEUOT MBUAE;Lo;0;L;;;;;N;;;;; +16910;BAMUM LETTER PHASE-D NGKEURI;Lo;0;L;;;;;N;;;;; +16911;BAMUM LETTER PHASE-D TU;Lo;0;L;;;;;N;;;;; +16912;BAMUM LETTER PHASE-D GHAA;Lo;0;L;;;;;N;;;;; +16913;BAMUM LETTER PHASE-D NGKYEE;Lo;0;L;;;;;N;;;;; +16914;BAMUM LETTER PHASE-D FEUFEUAET;Lo;0;L;;;;;N;;;;; +16915;BAMUM LETTER PHASE-D NDEE;Lo;0;L;;;;;N;;;;; +16916;BAMUM LETTER PHASE-D MGBOFUM;Lo;0;L;;;;;N;;;;; +16917;BAMUM LETTER PHASE-D LEUAEP;Lo;0;L;;;;;N;;;;; +16918;BAMUM LETTER PHASE-D NDON;Lo;0;L;;;;;N;;;;; +16919;BAMUM LETTER PHASE-D MONI;Lo;0;L;;;;;N;;;;; +1691A;BAMUM LETTER PHASE-D MGBEUN;Lo;0;L;;;;;N;;;;; +1691B;BAMUM LETTER PHASE-D PUUT;Lo;0;L;;;;;N;;;;; +1691C;BAMUM LETTER PHASE-D MGBIEE;Lo;0;L;;;;;N;;;;; +1691D;BAMUM LETTER PHASE-D MFO;Lo;0;L;;;;;N;;;;; +1691E;BAMUM LETTER PHASE-D LUM;Lo;0;L;;;;;N;;;;; +1691F;BAMUM LETTER PHASE-D NSIEEP;Lo;0;L;;;;;N;;;;; +16920;BAMUM LETTER PHASE-D MBAA;Lo;0;L;;;;;N;;;;; +16921;BAMUM LETTER PHASE-D KWAET;Lo;0;L;;;;;N;;;;; +16922;BAMUM LETTER PHASE-D NYET;Lo;0;L;;;;;N;;;;; +16923;BAMUM LETTER PHASE-D TEUAEN;Lo;0;L;;;;;N;;;;; +16924;BAMUM LETTER PHASE-D SOT;Lo;0;L;;;;;N;;;;; +16925;BAMUM LETTER PHASE-D YUWOQ;Lo;0;L;;;;;N;;;;; +16926;BAMUM LETTER PHASE-D KEUM;Lo;0;L;;;;;N;;;;; +16927;BAMUM LETTER PHASE-D RAEM;Lo;0;L;;;;;N;;;;; +16928;BAMUM LETTER PHASE-D TEEEE;Lo;0;L;;;;;N;;;;; +16929;BAMUM LETTER PHASE-D NGKEUAEQ;Lo;0;L;;;;;N;;;;; +1692A;BAMUM LETTER PHASE-D MFEUAE;Lo;0;L;;;;;N;;;;; +1692B;BAMUM LETTER PHASE-D NSIEET;Lo;0;L;;;;;N;;;;; +1692C;BAMUM LETTER PHASE-D KEUP;Lo;0;L;;;;;N;;;;; +1692D;BAMUM LETTER PHASE-D PIP;Lo;0;L;;;;;N;;;;; +1692E;BAMUM LETTER PHASE-D PEUTAE;Lo;0;L;;;;;N;;;;; +1692F;BAMUM LETTER PHASE-D NYUE;Lo;0;L;;;;;N;;;;; +16930;BAMUM LETTER PHASE-D LET;Lo;0;L;;;;;N;;;;; +16931;BAMUM LETTER PHASE-D NGGAAM;Lo;0;L;;;;;N;;;;; +16932;BAMUM LETTER PHASE-D MFIEE;Lo;0;L;;;;;N;;;;; +16933;BAMUM LETTER PHASE-D NGGWAEN;Lo;0;L;;;;;N;;;;; +16934;BAMUM LETTER PHASE-D YUOM;Lo;0;L;;;;;N;;;;; +16935;BAMUM LETTER PHASE-D PAP;Lo;0;L;;;;;N;;;;; +16936;BAMUM LETTER PHASE-D YUOP;Lo;0;L;;;;;N;;;;; +16937;BAMUM LETTER PHASE-D NDAM;Lo;0;L;;;;;N;;;;; +16938;BAMUM LETTER PHASE-D NTEUM;Lo;0;L;;;;;N;;;;; +16939;BAMUM LETTER PHASE-D SUAE;Lo;0;L;;;;;N;;;;; +1693A;BAMUM LETTER PHASE-D KUN;Lo;0;L;;;;;N;;;;; +1693B;BAMUM LETTER PHASE-D NGGEUX;Lo;0;L;;;;;N;;;;; +1693C;BAMUM LETTER PHASE-D NGKIEE;Lo;0;L;;;;;N;;;;; +1693D;BAMUM LETTER PHASE-D TUOT;Lo;0;L;;;;;N;;;;; +1693E;BAMUM LETTER PHASE-D MEUN;Lo;0;L;;;;;N;;;;; +1693F;BAMUM LETTER PHASE-D KUQ;Lo;0;L;;;;;N;;;;; +16940;BAMUM LETTER PHASE-D NSUM;Lo;0;L;;;;;N;;;;; +16941;BAMUM LETTER PHASE-D TEUN;Lo;0;L;;;;;N;;;;; +16942;BAMUM LETTER PHASE-D MAENJET;Lo;0;L;;;;;N;;;;; +16943;BAMUM LETTER PHASE-D NGGAP;Lo;0;L;;;;;N;;;;; +16944;BAMUM LETTER PHASE-D LEUM;Lo;0;L;;;;;N;;;;; +16945;BAMUM LETTER PHASE-D NGGUOM;Lo;0;L;;;;;N;;;;; +16946;BAMUM LETTER PHASE-D NSHUT;Lo;0;L;;;;;N;;;;; +16947;BAMUM LETTER PHASE-D NJUEQ;Lo;0;L;;;;;N;;;;; +16948;BAMUM LETTER PHASE-D GHEUAE;Lo;0;L;;;;;N;;;;; +16949;BAMUM LETTER PHASE-D KU;Lo;0;L;;;;;N;;;;; +1694A;BAMUM LETTER PHASE-D REN OLD;Lo;0;L;;;;;N;;;;; +1694B;BAMUM LETTER PHASE-D TAE;Lo;0;L;;;;;N;;;;; +1694C;BAMUM LETTER PHASE-D TOQ;Lo;0;L;;;;;N;;;;; +1694D;BAMUM LETTER PHASE-D NYI;Lo;0;L;;;;;N;;;;; +1694E;BAMUM LETTER PHASE-D RII;Lo;0;L;;;;;N;;;;; +1694F;BAMUM LETTER PHASE-D LEEEE;Lo;0;L;;;;;N;;;;; +16950;BAMUM LETTER PHASE-D MEEEE;Lo;0;L;;;;;N;;;;; +16951;BAMUM LETTER PHASE-D M;Lo;0;L;;;;;N;;;;; +16952;BAMUM LETTER PHASE-D SUU;Lo;0;L;;;;;N;;;;; +16953;BAMUM LETTER PHASE-D MU;Lo;0;L;;;;;N;;;;; +16954;BAMUM LETTER PHASE-D SHII;Lo;0;L;;;;;N;;;;; +16955;BAMUM LETTER PHASE-D SHEUX;Lo;0;L;;;;;N;;;;; +16956;BAMUM LETTER PHASE-D KYEE;Lo;0;L;;;;;N;;;;; +16957;BAMUM LETTER PHASE-D NU;Lo;0;L;;;;;N;;;;; +16958;BAMUM LETTER PHASE-D SHU;Lo;0;L;;;;;N;;;;; +16959;BAMUM LETTER PHASE-D NTEE;Lo;0;L;;;;;N;;;;; +1695A;BAMUM LETTER PHASE-D PEE;Lo;0;L;;;;;N;;;;; +1695B;BAMUM LETTER PHASE-D NI;Lo;0;L;;;;;N;;;;; +1695C;BAMUM LETTER PHASE-D SHOQ;Lo;0;L;;;;;N;;;;; +1695D;BAMUM LETTER PHASE-D PUQ;Lo;0;L;;;;;N;;;;; +1695E;BAMUM LETTER PHASE-D MVOP;Lo;0;L;;;;;N;;;;; +1695F;BAMUM LETTER PHASE-D LOQ;Lo;0;L;;;;;N;;;;; +16960;BAMUM LETTER PHASE-D REN MUCH;Lo;0;L;;;;;N;;;;; +16961;BAMUM LETTER PHASE-D TI;Lo;0;L;;;;;N;;;;; +16962;BAMUM LETTER PHASE-D NTUU;Lo;0;L;;;;;N;;;;; +16963;BAMUM LETTER PHASE-D MBAA SEVEN;Lo;0;L;;;;;N;;;;; +16964;BAMUM LETTER PHASE-D SAQ;Lo;0;L;;;;;N;;;;; +16965;BAMUM LETTER PHASE-D FAA;Lo;0;L;;;;;N;;;;; +16966;BAMUM LETTER PHASE-E NDAP;Lo;0;L;;;;;N;;;;; +16967;BAMUM LETTER PHASE-E TOON;Lo;0;L;;;;;N;;;;; +16968;BAMUM LETTER PHASE-E MBEUM;Lo;0;L;;;;;N;;;;; +16969;BAMUM LETTER PHASE-E LAP;Lo;0;L;;;;;N;;;;; +1696A;BAMUM LETTER PHASE-E VOM;Lo;0;L;;;;;N;;;;; +1696B;BAMUM LETTER PHASE-E LOON;Lo;0;L;;;;;N;;;;; +1696C;BAMUM LETTER PHASE-E PAA;Lo;0;L;;;;;N;;;;; +1696D;BAMUM LETTER PHASE-E SOM;Lo;0;L;;;;;N;;;;; +1696E;BAMUM LETTER PHASE-E RAQ;Lo;0;L;;;;;N;;;;; +1696F;BAMUM LETTER PHASE-E NSHUOP;Lo;0;L;;;;;N;;;;; +16970;BAMUM LETTER PHASE-E NDUN;Lo;0;L;;;;;N;;;;; +16971;BAMUM LETTER PHASE-E PUAE;Lo;0;L;;;;;N;;;;; +16972;BAMUM LETTER PHASE-E TAM;Lo;0;L;;;;;N;;;;; +16973;BAMUM LETTER PHASE-E NGKA;Lo;0;L;;;;;N;;;;; +16974;BAMUM LETTER PHASE-E KPEUX;Lo;0;L;;;;;N;;;;; +16975;BAMUM LETTER PHASE-E WUO;Lo;0;L;;;;;N;;;;; +16976;BAMUM LETTER PHASE-E SEE;Lo;0;L;;;;;N;;;;; +16977;BAMUM LETTER PHASE-E NGGEUAET;Lo;0;L;;;;;N;;;;; +16978;BAMUM LETTER PHASE-E PAAM;Lo;0;L;;;;;N;;;;; +16979;BAMUM LETTER PHASE-E TOO;Lo;0;L;;;;;N;;;;; +1697A;BAMUM LETTER PHASE-E KUOP;Lo;0;L;;;;;N;;;;; +1697B;BAMUM LETTER PHASE-E LOM;Lo;0;L;;;;;N;;;;; +1697C;BAMUM LETTER PHASE-E NSHIEE;Lo;0;L;;;;;N;;;;; +1697D;BAMUM LETTER PHASE-E NGOP;Lo;0;L;;;;;N;;;;; +1697E;BAMUM LETTER PHASE-E MAEM;Lo;0;L;;;;;N;;;;; +1697F;BAMUM LETTER PHASE-E NGKEUX;Lo;0;L;;;;;N;;;;; +16980;BAMUM LETTER PHASE-E NGOQ;Lo;0;L;;;;;N;;;;; +16981;BAMUM LETTER PHASE-E NSHUE;Lo;0;L;;;;;N;;;;; +16982;BAMUM LETTER PHASE-E RIMGBA;Lo;0;L;;;;;N;;;;; +16983;BAMUM LETTER PHASE-E NJEUX;Lo;0;L;;;;;N;;;;; +16984;BAMUM LETTER PHASE-E PEEM;Lo;0;L;;;;;N;;;;; +16985;BAMUM LETTER PHASE-E SAA;Lo;0;L;;;;;N;;;;; +16986;BAMUM LETTER PHASE-E NGGURAE;Lo;0;L;;;;;N;;;;; +16987;BAMUM LETTER PHASE-E MGBA;Lo;0;L;;;;;N;;;;; +16988;BAMUM LETTER PHASE-E GHEUX;Lo;0;L;;;;;N;;;;; +16989;BAMUM LETTER PHASE-E NGKEUAEM;Lo;0;L;;;;;N;;;;; +1698A;BAMUM LETTER PHASE-E NJAEMLI;Lo;0;L;;;;;N;;;;; +1698B;BAMUM LETTER PHASE-E MAP;Lo;0;L;;;;;N;;;;; +1698C;BAMUM LETTER PHASE-E LOOT;Lo;0;L;;;;;N;;;;; +1698D;BAMUM LETTER PHASE-E NGGEEEE;Lo;0;L;;;;;N;;;;; +1698E;BAMUM LETTER PHASE-E NDIQ;Lo;0;L;;;;;N;;;;; +1698F;BAMUM LETTER PHASE-E TAEN NTEUM;Lo;0;L;;;;;N;;;;; +16990;BAMUM LETTER PHASE-E SET;Lo;0;L;;;;;N;;;;; +16991;BAMUM LETTER PHASE-E PUM;Lo;0;L;;;;;N;;;;; +16992;BAMUM LETTER PHASE-E NDAA SOFTNESS;Lo;0;L;;;;;N;;;;; +16993;BAMUM LETTER PHASE-E NGGUAESHAE NYAM;Lo;0;L;;;;;N;;;;; +16994;BAMUM LETTER PHASE-E YIEE;Lo;0;L;;;;;N;;;;; +16995;BAMUM LETTER PHASE-E GHEUN;Lo;0;L;;;;;N;;;;; +16996;BAMUM LETTER PHASE-E TUAE;Lo;0;L;;;;;N;;;;; +16997;BAMUM LETTER PHASE-E YEUAE;Lo;0;L;;;;;N;;;;; +16998;BAMUM LETTER PHASE-E PO;Lo;0;L;;;;;N;;;;; +16999;BAMUM LETTER PHASE-E TUMAE;Lo;0;L;;;;;N;;;;; +1699A;BAMUM LETTER PHASE-E KEUAE;Lo;0;L;;;;;N;;;;; +1699B;BAMUM LETTER PHASE-E SUAEN;Lo;0;L;;;;;N;;;;; +1699C;BAMUM LETTER PHASE-E TEUAEQ;Lo;0;L;;;;;N;;;;; +1699D;BAMUM LETTER PHASE-E VEUAE;Lo;0;L;;;;;N;;;;; +1699E;BAMUM LETTER PHASE-E WEUX;Lo;0;L;;;;;N;;;;; +1699F;BAMUM LETTER PHASE-E LAAM;Lo;0;L;;;;;N;;;;; +169A0;BAMUM LETTER PHASE-E PU;Lo;0;L;;;;;N;;;;; +169A1;BAMUM LETTER PHASE-E TAAQ;Lo;0;L;;;;;N;;;;; +169A2;BAMUM LETTER PHASE-E GHAAMAE;Lo;0;L;;;;;N;;;;; +169A3;BAMUM LETTER PHASE-E NGEUREUT;Lo;0;L;;;;;N;;;;; +169A4;BAMUM LETTER PHASE-E SHEUAEQ;Lo;0;L;;;;;N;;;;; +169A5;BAMUM LETTER PHASE-E MGBEN;Lo;0;L;;;;;N;;;;; +169A6;BAMUM LETTER PHASE-E MBEE;Lo;0;L;;;;;N;;;;; +169A7;BAMUM LETTER PHASE-E NZAQ;Lo;0;L;;;;;N;;;;; +169A8;BAMUM LETTER PHASE-E NKOM;Lo;0;L;;;;;N;;;;; +169A9;BAMUM LETTER PHASE-E GBET;Lo;0;L;;;;;N;;;;; +169AA;BAMUM LETTER PHASE-E TUM;Lo;0;L;;;;;N;;;;; +169AB;BAMUM LETTER PHASE-E KUET;Lo;0;L;;;;;N;;;;; +169AC;BAMUM LETTER PHASE-E YAP;Lo;0;L;;;;;N;;;;; +169AD;BAMUM LETTER PHASE-E NYI CLEAVER;Lo;0;L;;;;;N;;;;; +169AE;BAMUM LETTER PHASE-E YIT;Lo;0;L;;;;;N;;;;; +169AF;BAMUM LETTER PHASE-E MFEUQ;Lo;0;L;;;;;N;;;;; +169B0;BAMUM LETTER PHASE-E NDIAQ;Lo;0;L;;;;;N;;;;; +169B1;BAMUM LETTER PHASE-E PIEEQ;Lo;0;L;;;;;N;;;;; +169B2;BAMUM LETTER PHASE-E YUEQ;Lo;0;L;;;;;N;;;;; +169B3;BAMUM LETTER PHASE-E LEUAEM;Lo;0;L;;;;;N;;;;; +169B4;BAMUM LETTER PHASE-E FUE;Lo;0;L;;;;;N;;;;; +169B5;BAMUM LETTER PHASE-E GBEUX;Lo;0;L;;;;;N;;;;; +169B6;BAMUM LETTER PHASE-E NGKUP;Lo;0;L;;;;;N;;;;; +169B7;BAMUM LETTER PHASE-E KET;Lo;0;L;;;;;N;;;;; +169B8;BAMUM LETTER PHASE-E MAE;Lo;0;L;;;;;N;;;;; +169B9;BAMUM LETTER PHASE-E NGKAAMI;Lo;0;L;;;;;N;;;;; +169BA;BAMUM LETTER PHASE-E GHET;Lo;0;L;;;;;N;;;;; +169BB;BAMUM LETTER PHASE-E FA;Lo;0;L;;;;;N;;;;; +169BC;BAMUM LETTER PHASE-E NTUM;Lo;0;L;;;;;N;;;;; +169BD;BAMUM LETTER PHASE-E PEUT;Lo;0;L;;;;;N;;;;; +169BE;BAMUM LETTER PHASE-E YEUM;Lo;0;L;;;;;N;;;;; +169BF;BAMUM LETTER PHASE-E NGGEUAE;Lo;0;L;;;;;N;;;;; +169C0;BAMUM LETTER PHASE-E NYI BETWEEN;Lo;0;L;;;;;N;;;;; +169C1;BAMUM LETTER PHASE-E NZUQ;Lo;0;L;;;;;N;;;;; +169C2;BAMUM LETTER PHASE-E POON;Lo;0;L;;;;;N;;;;; +169C3;BAMUM LETTER PHASE-E MIEE;Lo;0;L;;;;;N;;;;; +169C4;BAMUM LETTER PHASE-E FUET;Lo;0;L;;;;;N;;;;; +169C5;BAMUM LETTER PHASE-E NAE;Lo;0;L;;;;;N;;;;; +169C6;BAMUM LETTER PHASE-E MUAE;Lo;0;L;;;;;N;;;;; +169C7;BAMUM LETTER PHASE-E GHEUAE;Lo;0;L;;;;;N;;;;; +169C8;BAMUM LETTER PHASE-E FU I;Lo;0;L;;;;;N;;;;; +169C9;BAMUM LETTER PHASE-E MVI;Lo;0;L;;;;;N;;;;; +169CA;BAMUM LETTER PHASE-E PUAQ;Lo;0;L;;;;;N;;;;; +169CB;BAMUM LETTER PHASE-E NGKUM;Lo;0;L;;;;;N;;;;; +169CC;BAMUM LETTER PHASE-E KUT;Lo;0;L;;;;;N;;;;; +169CD;BAMUM LETTER PHASE-E PIET;Lo;0;L;;;;;N;;;;; +169CE;BAMUM LETTER PHASE-E NTAP;Lo;0;L;;;;;N;;;;; +169CF;BAMUM LETTER PHASE-E YEUAET;Lo;0;L;;;;;N;;;;; +169D0;BAMUM LETTER PHASE-E NGGUP;Lo;0;L;;;;;N;;;;; +169D1;BAMUM LETTER PHASE-E PA PEOPLE;Lo;0;L;;;;;N;;;;; +169D2;BAMUM LETTER PHASE-E FU CALL;Lo;0;L;;;;;N;;;;; +169D3;BAMUM LETTER PHASE-E FOM;Lo;0;L;;;;;N;;;;; +169D4;BAMUM LETTER PHASE-E NJEE;Lo;0;L;;;;;N;;;;; +169D5;BAMUM LETTER PHASE-E A;Lo;0;L;;;;;N;;;;; +169D6;BAMUM LETTER PHASE-E TOQ;Lo;0;L;;;;;N;;;;; +169D7;BAMUM LETTER PHASE-E O;Lo;0;L;;;;;N;;;;; +169D8;BAMUM LETTER PHASE-E I;Lo;0;L;;;;;N;;;;; +169D9;BAMUM LETTER PHASE-E LAQ;Lo;0;L;;;;;N;;;;; +169DA;BAMUM LETTER PHASE-E PA PLURAL;Lo;0;L;;;;;N;;;;; +169DB;BAMUM LETTER PHASE-E TAA;Lo;0;L;;;;;N;;;;; +169DC;BAMUM LETTER PHASE-E TAQ;Lo;0;L;;;;;N;;;;; +169DD;BAMUM LETTER PHASE-E NDAA MY HOUSE;Lo;0;L;;;;;N;;;;; +169DE;BAMUM LETTER PHASE-E SHIQ;Lo;0;L;;;;;N;;;;; +169DF;BAMUM LETTER PHASE-E YEUX;Lo;0;L;;;;;N;;;;; +169E0;BAMUM LETTER PHASE-E NGUAE;Lo;0;L;;;;;N;;;;; +169E1;BAMUM LETTER PHASE-E YUAEN;Lo;0;L;;;;;N;;;;; +169E2;BAMUM LETTER PHASE-E YOQ SWIMMING;Lo;0;L;;;;;N;;;;; +169E3;BAMUM LETTER PHASE-E YOQ COVER;Lo;0;L;;;;;N;;;;; +169E4;BAMUM LETTER PHASE-E YUQ;Lo;0;L;;;;;N;;;;; +169E5;BAMUM LETTER PHASE-E YUN;Lo;0;L;;;;;N;;;;; +169E6;BAMUM LETTER PHASE-E KEUX;Lo;0;L;;;;;N;;;;; +169E7;BAMUM LETTER PHASE-E PEUX;Lo;0;L;;;;;N;;;;; +169E8;BAMUM LETTER PHASE-E NJEE EPOCH;Lo;0;L;;;;;N;;;;; +169E9;BAMUM LETTER PHASE-E PUE;Lo;0;L;;;;;N;;;;; +169EA;BAMUM LETTER PHASE-E WUE;Lo;0;L;;;;;N;;;;; +169EB;BAMUM LETTER PHASE-E FEE;Lo;0;L;;;;;N;;;;; +169EC;BAMUM LETTER PHASE-E VEE;Lo;0;L;;;;;N;;;;; +169ED;BAMUM LETTER PHASE-E LU;Lo;0;L;;;;;N;;;;; +169EE;BAMUM LETTER PHASE-E MI;Lo;0;L;;;;;N;;;;; +169EF;BAMUM LETTER PHASE-E REUX;Lo;0;L;;;;;N;;;;; +169F0;BAMUM LETTER PHASE-E RAE;Lo;0;L;;;;;N;;;;; +169F1;BAMUM LETTER PHASE-E NGUAET;Lo;0;L;;;;;N;;;;; +169F2;BAMUM LETTER PHASE-E NGA;Lo;0;L;;;;;N;;;;; +169F3;BAMUM LETTER PHASE-E SHO;Lo;0;L;;;;;N;;;;; +169F4;BAMUM LETTER PHASE-E SHOQ;Lo;0;L;;;;;N;;;;; +169F5;BAMUM LETTER PHASE-E FU REMEDY;Lo;0;L;;;;;N;;;;; +169F6;BAMUM LETTER PHASE-E NA;Lo;0;L;;;;;N;;;;; +169F7;BAMUM LETTER PHASE-E PI;Lo;0;L;;;;;N;;;;; +169F8;BAMUM LETTER PHASE-E LOQ;Lo;0;L;;;;;N;;;;; +169F9;BAMUM LETTER PHASE-E KO;Lo;0;L;;;;;N;;;;; +169FA;BAMUM LETTER PHASE-E MEN;Lo;0;L;;;;;N;;;;; +169FB;BAMUM LETTER PHASE-E MA;Lo;0;L;;;;;N;;;;; +169FC;BAMUM LETTER PHASE-E MAQ;Lo;0;L;;;;;N;;;;; +169FD;BAMUM LETTER PHASE-E TEU;Lo;0;L;;;;;N;;;;; +169FE;BAMUM LETTER PHASE-E KI;Lo;0;L;;;;;N;;;;; +169FF;BAMUM LETTER PHASE-E MON;Lo;0;L;;;;;N;;;;; +16A00;BAMUM LETTER PHASE-E TEN;Lo;0;L;;;;;N;;;;; +16A01;BAMUM LETTER PHASE-E FAQ;Lo;0;L;;;;;N;;;;; +16A02;BAMUM LETTER PHASE-E GHOM;Lo;0;L;;;;;N;;;;; +16A03;BAMUM LETTER PHASE-F KA;Lo;0;L;;;;;N;;;;; +16A04;BAMUM LETTER PHASE-F U;Lo;0;L;;;;;N;;;;; +16A05;BAMUM LETTER PHASE-F KU;Lo;0;L;;;;;N;;;;; +16A06;BAMUM LETTER PHASE-F EE;Lo;0;L;;;;;N;;;;; +16A07;BAMUM LETTER PHASE-F REE;Lo;0;L;;;;;N;;;;; +16A08;BAMUM LETTER PHASE-F TAE;Lo;0;L;;;;;N;;;;; +16A09;BAMUM LETTER PHASE-F NYI;Lo;0;L;;;;;N;;;;; +16A0A;BAMUM LETTER PHASE-F LA;Lo;0;L;;;;;N;;;;; +16A0B;BAMUM LETTER PHASE-F RII;Lo;0;L;;;;;N;;;;; +16A0C;BAMUM LETTER PHASE-F RIEE;Lo;0;L;;;;;N;;;;; +16A0D;BAMUM LETTER PHASE-F MEEEE;Lo;0;L;;;;;N;;;;; +16A0E;BAMUM LETTER PHASE-F TAA;Lo;0;L;;;;;N;;;;; +16A0F;BAMUM LETTER PHASE-F NDAA;Lo;0;L;;;;;N;;;;; +16A10;BAMUM LETTER PHASE-F NJAEM;Lo;0;L;;;;;N;;;;; +16A11;BAMUM LETTER PHASE-F M;Lo;0;L;;;;;N;;;;; +16A12;BAMUM LETTER PHASE-F SUU;Lo;0;L;;;;;N;;;;; +16A13;BAMUM LETTER PHASE-F SHII;Lo;0;L;;;;;N;;;;; +16A14;BAMUM LETTER PHASE-F SI;Lo;0;L;;;;;N;;;;; +16A15;BAMUM LETTER PHASE-F SEUX;Lo;0;L;;;;;N;;;;; +16A16;BAMUM LETTER PHASE-F KYEE;Lo;0;L;;;;;N;;;;; +16A17;BAMUM LETTER PHASE-F KET;Lo;0;L;;;;;N;;;;; +16A18;BAMUM LETTER PHASE-F NUAE;Lo;0;L;;;;;N;;;;; +16A19;BAMUM LETTER PHASE-F NU;Lo;0;L;;;;;N;;;;; +16A1A;BAMUM LETTER PHASE-F NJUAE;Lo;0;L;;;;;N;;;;; +16A1B;BAMUM LETTER PHASE-F YOQ;Lo;0;L;;;;;N;;;;; +16A1C;BAMUM LETTER PHASE-F SHU;Lo;0;L;;;;;N;;;;; +16A1D;BAMUM LETTER PHASE-F YA;Lo;0;L;;;;;N;;;;; +16A1E;BAMUM LETTER PHASE-F NSHA;Lo;0;L;;;;;N;;;;; +16A1F;BAMUM LETTER PHASE-F PEUX;Lo;0;L;;;;;N;;;;; +16A20;BAMUM LETTER PHASE-F NTEE;Lo;0;L;;;;;N;;;;; +16A21;BAMUM LETTER PHASE-F WUE;Lo;0;L;;;;;N;;;;; +16A22;BAMUM LETTER PHASE-F PEE;Lo;0;L;;;;;N;;;;; +16A23;BAMUM LETTER PHASE-F RU;Lo;0;L;;;;;N;;;;; +16A24;BAMUM LETTER PHASE-F NI;Lo;0;L;;;;;N;;;;; +16A25;BAMUM LETTER PHASE-F REUX;Lo;0;L;;;;;N;;;;; +16A26;BAMUM LETTER PHASE-F KEN;Lo;0;L;;;;;N;;;;; +16A27;BAMUM LETTER PHASE-F NGKWAEN;Lo;0;L;;;;;N;;;;; +16A28;BAMUM LETTER PHASE-F NGGA;Lo;0;L;;;;;N;;;;; +16A29;BAMUM LETTER PHASE-F SHO;Lo;0;L;;;;;N;;;;; +16A2A;BAMUM LETTER PHASE-F PUAE;Lo;0;L;;;;;N;;;;; +16A2B;BAMUM LETTER PHASE-F FOM;Lo;0;L;;;;;N;;;;; +16A2C;BAMUM LETTER PHASE-F WA;Lo;0;L;;;;;N;;;;; +16A2D;BAMUM LETTER PHASE-F LI;Lo;0;L;;;;;N;;;;; +16A2E;BAMUM LETTER PHASE-F LOQ;Lo;0;L;;;;;N;;;;; +16A2F;BAMUM LETTER PHASE-F KO;Lo;0;L;;;;;N;;;;; +16A30;BAMUM LETTER PHASE-F MBEN;Lo;0;L;;;;;N;;;;; +16A31;BAMUM LETTER PHASE-F REN;Lo;0;L;;;;;N;;;;; +16A32;BAMUM LETTER PHASE-F MA;Lo;0;L;;;;;N;;;;; +16A33;BAMUM LETTER PHASE-F MO;Lo;0;L;;;;;N;;;;; +16A34;BAMUM LETTER PHASE-F MBAA;Lo;0;L;;;;;N;;;;; +16A35;BAMUM LETTER PHASE-F TET;Lo;0;L;;;;;N;;;;; +16A36;BAMUM LETTER PHASE-F KPA;Lo;0;L;;;;;N;;;;; +16A37;BAMUM LETTER PHASE-F SAMBA;Lo;0;L;;;;;N;;;;; +16A38;BAMUM LETTER PHASE-F VUEQ;Lo;0;L;;;;;N;;;;; +1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; +1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; 1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; 1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; 1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; @@ -20833,6 +21743,65 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F091;DOMINO TILE VERTICAL-06-04;So;0;ON;;;;;N;;;;; 1F092;DOMINO TILE VERTICAL-06-05;So;0;ON;;;;;N;;;;; 1F093;DOMINO TILE VERTICAL-06-06;So;0;ON;;;;;N;;;;; +1F0A0;PLAYING CARD BACK;So;0;ON;;;;;N;;;;; +1F0A1;PLAYING CARD ACE OF SPADES;So;0;ON;;;;;N;;;;; +1F0A2;PLAYING CARD TWO OF SPADES;So;0;ON;;;;;N;;;;; +1F0A3;PLAYING CARD THREE OF SPADES;So;0;ON;;;;;N;;;;; +1F0A4;PLAYING CARD FOUR OF SPADES;So;0;ON;;;;;N;;;;; +1F0A5;PLAYING CARD FIVE OF SPADES;So;0;ON;;;;;N;;;;; +1F0A6;PLAYING CARD SIX OF SPADES;So;0;ON;;;;;N;;;;; +1F0A7;PLAYING CARD SEVEN OF SPADES;So;0;ON;;;;;N;;;;; +1F0A8;PLAYING CARD EIGHT OF SPADES;So;0;ON;;;;;N;;;;; +1F0A9;PLAYING CARD NINE OF SPADES;So;0;ON;;;;;N;;;;; +1F0AA;PLAYING CARD TEN OF SPADES;So;0;ON;;;;;N;;;;; +1F0AB;PLAYING CARD JACK OF SPADES;So;0;ON;;;;;N;;;;; +1F0AC;PLAYING CARD KNIGHT OF SPADES;So;0;ON;;;;;N;;;;; +1F0AD;PLAYING CARD QUEEN OF SPADES;So;0;ON;;;;;N;;;;; +1F0AE;PLAYING CARD KING OF SPADES;So;0;ON;;;;;N;;;;; +1F0B1;PLAYING CARD ACE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B2;PLAYING CARD TWO OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B3;PLAYING CARD THREE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B4;PLAYING CARD FOUR OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B5;PLAYING CARD FIVE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B6;PLAYING CARD SIX OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B7;PLAYING CARD SEVEN OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B8;PLAYING CARD EIGHT OF HEARTS;So;0;ON;;;;;N;;;;; +1F0B9;PLAYING CARD NINE OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BA;PLAYING CARD TEN OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BB;PLAYING CARD JACK OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BC;PLAYING CARD KNIGHT OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BD;PLAYING CARD QUEEN OF HEARTS;So;0;ON;;;;;N;;;;; +1F0BE;PLAYING CARD KING OF HEARTS;So;0;ON;;;;;N;;;;; +1F0C1;PLAYING CARD ACE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C2;PLAYING CARD TWO OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C3;PLAYING CARD THREE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C4;PLAYING CARD FOUR OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C5;PLAYING CARD FIVE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C6;PLAYING CARD SIX OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C7;PLAYING CARD SEVEN OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C8;PLAYING CARD EIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0C9;PLAYING CARD NINE OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CA;PLAYING CARD TEN OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CB;PLAYING CARD JACK OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CC;PLAYING CARD KNIGHT OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CD;PLAYING CARD QUEEN OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CE;PLAYING CARD KING OF DIAMONDS;So;0;ON;;;;;N;;;;; +1F0CF;PLAYING CARD BLACK JOKER;So;0;ON;;;;;N;;;;; +1F0D1;PLAYING CARD ACE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D2;PLAYING CARD TWO OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D3;PLAYING CARD THREE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D4;PLAYING CARD FOUR OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D5;PLAYING CARD FIVE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D6;PLAYING CARD SIX OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D7;PLAYING CARD SEVEN OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D8;PLAYING CARD EIGHT OF CLUBS;So;0;ON;;;;;N;;;;; +1F0D9;PLAYING CARD NINE OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DA;PLAYING CARD TEN OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DB;PLAYING CARD JACK OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DC;PLAYING CARD KNIGHT OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DD;PLAYING CARD QUEEN OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DE;PLAYING CARD KING OF CLUBS;So;0;ON;;;;;N;;;;; +1F0DF;PLAYING CARD WHITE JOKER;So;0;ON;;;;;N;;;;; 1F100;DIGIT ZERO FULL STOP;No;0;EN; 0030 002E;;0;0;N;;;;; 1F101;DIGIT ZERO COMMA;No;0;EN; 0030 002C;;0;0;N;;;;; 1F102;DIGIT ONE COMMA;No;0;EN; 0031 002C;;1;1;N;;;;; @@ -20875,28 +21844,136 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;; 1F12D;CIRCLED CD;So;0;L; 0043 0044;;;;N;;;;; 1F12E;CIRCLED WZ;So;0;L; 0057 005A;;;;N;;;;; +1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;; 1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;; +1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;; +1F133;SQUARED LATIN CAPITAL LETTER D;So;0;L; 0044;;;;N;;;;; +1F134;SQUARED LATIN CAPITAL LETTER E;So;0;L; 0045;;;;N;;;;; +1F135;SQUARED LATIN CAPITAL LETTER F;So;0;L; 0046;;;;N;;;;; +1F136;SQUARED LATIN CAPITAL LETTER G;So;0;L; 0047;;;;N;;;;; +1F137;SQUARED LATIN CAPITAL LETTER H;So;0;L; 0048;;;;N;;;;; +1F138;SQUARED LATIN CAPITAL LETTER I;So;0;L; 0049;;;;N;;;;; +1F139;SQUARED LATIN CAPITAL LETTER J;So;0;L; 004A;;;;N;;;;; +1F13A;SQUARED LATIN CAPITAL LETTER K;So;0;L; 004B;;;;N;;;;; +1F13B;SQUARED LATIN CAPITAL LETTER L;So;0;L; 004C;;;;N;;;;; +1F13C;SQUARED LATIN CAPITAL LETTER M;So;0;L; 004D;;;;N;;;;; 1F13D;SQUARED LATIN CAPITAL LETTER N;So;0;L; 004E;;;;N;;;;; +1F13E;SQUARED LATIN CAPITAL LETTER O;So;0;L; 004F;;;;N;;;;; 1F13F;SQUARED LATIN CAPITAL LETTER P;So;0;L; 0050;;;;N;;;;; +1F140;SQUARED LATIN CAPITAL LETTER Q;So;0;L; 0051;;;;N;;;;; +1F141;SQUARED LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;; 1F142;SQUARED LATIN CAPITAL LETTER S;So;0;L; 0053;;;;N;;;;; +1F143;SQUARED LATIN CAPITAL LETTER T;So;0;L; 0054;;;;N;;;;; +1F144;SQUARED LATIN CAPITAL LETTER U;So;0;L; 0055;;;;N;;;;; +1F145;SQUARED LATIN CAPITAL LETTER V;So;0;L; 0056;;;;N;;;;; 1F146;SQUARED LATIN CAPITAL LETTER W;So;0;L; 0057;;;;N;;;;; +1F147;SQUARED LATIN CAPITAL LETTER X;So;0;L; 0058;;;;N;;;;; +1F148;SQUARED LATIN CAPITAL LETTER Y;So;0;L; 0059;;;;N;;;;; +1F149;SQUARED LATIN CAPITAL LETTER Z;So;0;L; 005A;;;;N;;;;; 1F14A;SQUARED HV;So;0;L; 0048 0056;;;;N;;;;; 1F14B;SQUARED MV;So;0;L; 004D 0056;;;;N;;;;; 1F14C;SQUARED SD;So;0;L; 0053 0044;;;;N;;;;; 1F14D;SQUARED SS;So;0;L; 0053 0053;;;;N;;;;; 1F14E;SQUARED PPV;So;0;L; 0050 0050 0056;;;;N;;;;; +1F14F;SQUARED WC;So;0;L; 0057 0043;;;;N;;;;; +1F150;NEGATIVE CIRCLED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; +1F151;NEGATIVE CIRCLED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; +1F152;NEGATIVE CIRCLED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; +1F153;NEGATIVE CIRCLED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;; +1F154;NEGATIVE CIRCLED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;; +1F155;NEGATIVE CIRCLED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;; +1F156;NEGATIVE CIRCLED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;; 1F157;NEGATIVE CIRCLED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;; +1F158;NEGATIVE CIRCLED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;; +1F159;NEGATIVE CIRCLED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;; +1F15A;NEGATIVE CIRCLED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;; +1F15B;NEGATIVE CIRCLED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;; +1F15C;NEGATIVE CIRCLED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;; +1F15D;NEGATIVE CIRCLED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;; +1F15E;NEGATIVE CIRCLED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;; 1F15F;NEGATIVE CIRCLED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; +1F160;NEGATIVE CIRCLED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;; +1F161;NEGATIVE CIRCLED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;; +1F162;NEGATIVE CIRCLED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;; +1F163;NEGATIVE CIRCLED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;; +1F164;NEGATIVE CIRCLED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;; +1F165;NEGATIVE CIRCLED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;; +1F166;NEGATIVE CIRCLED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;; +1F167;NEGATIVE CIRCLED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; +1F168;NEGATIVE CIRCLED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; +1F169;NEGATIVE CIRCLED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; +1F170;NEGATIVE SQUARED LATIN CAPITAL LETTER A;So;0;L;;;;;N;;;;; +1F171;NEGATIVE SQUARED LATIN CAPITAL LETTER B;So;0;L;;;;;N;;;;; +1F172;NEGATIVE SQUARED LATIN CAPITAL LETTER C;So;0;L;;;;;N;;;;; +1F173;NEGATIVE SQUARED LATIN CAPITAL LETTER D;So;0;L;;;;;N;;;;; +1F174;NEGATIVE SQUARED LATIN CAPITAL LETTER E;So;0;L;;;;;N;;;;; +1F175;NEGATIVE SQUARED LATIN CAPITAL LETTER F;So;0;L;;;;;N;;;;; +1F176;NEGATIVE SQUARED LATIN CAPITAL LETTER G;So;0;L;;;;;N;;;;; +1F177;NEGATIVE SQUARED LATIN CAPITAL LETTER H;So;0;L;;;;;N;;;;; +1F178;NEGATIVE SQUARED LATIN CAPITAL LETTER I;So;0;L;;;;;N;;;;; 1F179;NEGATIVE SQUARED LATIN CAPITAL LETTER J;So;0;L;;;;;N;;;;; +1F17A;NEGATIVE SQUARED LATIN CAPITAL LETTER K;So;0;L;;;;;N;;;;; 1F17B;NEGATIVE SQUARED LATIN CAPITAL LETTER L;So;0;L;;;;;N;;;;; 1F17C;NEGATIVE SQUARED LATIN CAPITAL LETTER M;So;0;L;;;;;N;;;;; +1F17D;NEGATIVE SQUARED LATIN CAPITAL LETTER N;So;0;L;;;;;N;;;;; +1F17E;NEGATIVE SQUARED LATIN CAPITAL LETTER O;So;0;L;;;;;N;;;;; 1F17F;NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; +1F180;NEGATIVE SQUARED LATIN CAPITAL LETTER Q;So;0;L;;;;;N;;;;; +1F181;NEGATIVE SQUARED LATIN CAPITAL LETTER R;So;0;L;;;;;N;;;;; +1F182;NEGATIVE SQUARED LATIN CAPITAL LETTER S;So;0;L;;;;;N;;;;; +1F183;NEGATIVE SQUARED LATIN CAPITAL LETTER T;So;0;L;;;;;N;;;;; +1F184;NEGATIVE SQUARED LATIN CAPITAL LETTER U;So;0;L;;;;;N;;;;; +1F185;NEGATIVE SQUARED LATIN CAPITAL LETTER V;So;0;L;;;;;N;;;;; +1F186;NEGATIVE SQUARED LATIN CAPITAL LETTER W;So;0;L;;;;;N;;;;; +1F187;NEGATIVE SQUARED LATIN CAPITAL LETTER X;So;0;L;;;;;N;;;;; +1F188;NEGATIVE SQUARED LATIN CAPITAL LETTER Y;So;0;L;;;;;N;;;;; +1F189;NEGATIVE SQUARED LATIN CAPITAL LETTER Z;So;0;L;;;;;N;;;;; 1F18A;CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P;So;0;L;;;;;N;;;;; 1F18B;NEGATIVE SQUARED IC;So;0;L;;;;;N;;;;; 1F18C;NEGATIVE SQUARED PA;So;0;L;;;;;N;;;;; 1F18D;NEGATIVE SQUARED SA;So;0;L;;;;;N;;;;; +1F18E;NEGATIVE SQUARED AB;So;0;L;;;;;N;;;;; +1F18F;NEGATIVE SQUARED WC;So;0;L;;;;;N;;;;; 1F190;SQUARE DJ;So;0;L; 0044 004A;;;;N;;;;; +1F191;SQUARED CL;So;0;L;;;;;N;;;;; +1F192;SQUARED COOL;So;0;L;;;;;N;;;;; +1F193;SQUARED FREE;So;0;L;;;;;N;;;;; +1F194;SQUARED ID;So;0;L;;;;;N;;;;; +1F195;SQUARED NEW;So;0;L;;;;;N;;;;; +1F196;SQUARED NG;So;0;L;;;;;N;;;;; +1F197;SQUARED OK;So;0;L;;;;;N;;;;; +1F198;SQUARED SOS;So;0;L;;;;;N;;;;; +1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;; +1F19A;SQUARED VS;So;0;L;;;;;N;;;;; +1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;; +1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;; +1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;; +1F1E9;REGIONAL INDICATOR SYMBOL LETTER D;So;0;L;;;;;N;;;;; +1F1EA;REGIONAL INDICATOR SYMBOL LETTER E;So;0;L;;;;;N;;;;; +1F1EB;REGIONAL INDICATOR SYMBOL LETTER F;So;0;L;;;;;N;;;;; +1F1EC;REGIONAL INDICATOR SYMBOL LETTER G;So;0;L;;;;;N;;;;; +1F1ED;REGIONAL INDICATOR SYMBOL LETTER H;So;0;L;;;;;N;;;;; +1F1EE;REGIONAL INDICATOR SYMBOL LETTER I;So;0;L;;;;;N;;;;; +1F1EF;REGIONAL INDICATOR SYMBOL LETTER J;So;0;L;;;;;N;;;;; +1F1F0;REGIONAL INDICATOR SYMBOL LETTER K;So;0;L;;;;;N;;;;; +1F1F1;REGIONAL INDICATOR SYMBOL LETTER L;So;0;L;;;;;N;;;;; +1F1F2;REGIONAL INDICATOR SYMBOL LETTER M;So;0;L;;;;;N;;;;; +1F1F3;REGIONAL INDICATOR SYMBOL LETTER N;So;0;L;;;;;N;;;;; +1F1F4;REGIONAL INDICATOR SYMBOL LETTER O;So;0;L;;;;;N;;;;; +1F1F5;REGIONAL INDICATOR SYMBOL LETTER P;So;0;L;;;;;N;;;;; +1F1F6;REGIONAL INDICATOR SYMBOL LETTER Q;So;0;L;;;;;N;;;;; +1F1F7;REGIONAL INDICATOR SYMBOL LETTER R;So;0;L;;;;;N;;;;; +1F1F8;REGIONAL INDICATOR SYMBOL LETTER S;So;0;L;;;;;N;;;;; +1F1F9;REGIONAL INDICATOR SYMBOL LETTER T;So;0;L;;;;;N;;;;; +1F1FA;REGIONAL INDICATOR SYMBOL LETTER U;So;0;L;;;;;N;;;;; +1F1FB;REGIONAL INDICATOR SYMBOL LETTER V;So;0;L;;;;;N;;;;; +1F1FC;REGIONAL INDICATOR SYMBOL LETTER W;So;0;L;;;;;N;;;;; +1F1FD;REGIONAL INDICATOR SYMBOL LETTER X;So;0;L;;;;;N;;;;; +1F1FE;REGIONAL INDICATOR SYMBOL LETTER Y;So;0;L;;;;;N;;;;; +1F1FF;REGIONAL INDICATOR SYMBOL LETTER Z;So;0;L;;;;;N;;;;; 1F200;SQUARE HIRAGANA HOKA;So;0;L; 307B 304B;;;;N;;;;; +1F201;SQUARED KATAKANA KOKO;So;0;L; 30B3 30B3;;;;N;;;;; +1F202;SQUARED KATAKANA SA;So;0;L; 30B5;;;;N;;;;; 1F210;SQUARED CJK UNIFIED IDEOGRAPH-624B;So;0;L; 624B;;;;N;;;;; 1F211;SQUARED CJK UNIFIED IDEOGRAPH-5B57;So;0;L; 5B57;;;;N;;;;; 1F212;SQUARED CJK UNIFIED IDEOGRAPH-53CC;So;0;L; 53CC;;;;N;;;;; @@ -20931,6 +22008,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F22F;SQUARED CJK UNIFIED IDEOGRAPH-6307;So;0;L; 6307;;;;N;;;;; 1F230;SQUARED CJK UNIFIED IDEOGRAPH-8D70;So;0;L; 8D70;;;;N;;;;; 1F231;SQUARED CJK UNIFIED IDEOGRAPH-6253;So;0;L; 6253;;;;N;;;;; +1F232;SQUARED CJK UNIFIED IDEOGRAPH-7981;So;0;L; 7981;;;;N;;;;; +1F233;SQUARED CJK UNIFIED IDEOGRAPH-7A7A;So;0;L; 7A7A;;;;N;;;;; +1F234;SQUARED CJK UNIFIED IDEOGRAPH-5408;So;0;L; 5408;;;;N;;;;; +1F235;SQUARED CJK UNIFIED IDEOGRAPH-6E80;So;0;L; 6E80;;;;N;;;;; +1F236;SQUARED CJK UNIFIED IDEOGRAPH-6709;So;0;L; 6709;;;;N;;;;; +1F237;SQUARED CJK UNIFIED IDEOGRAPH-6708;So;0;L; 6708;;;;N;;;;; +1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L; 7533;;;;N;;;;; +1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L; 5272;;;;N;;;;; +1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L; 55B6;;;;N;;;;; 1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L; 3014 672C 3015;;;;N;;;;; 1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L; 3014 4E09 3015;;;;N;;;;; 1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L; 3014 4E8C 3015;;;;N;;;;; @@ -20940,10 +22026,792 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F246;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7;So;0;L; 3014 76D7 3015;;;;N;;;;; 1F247;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD;So;0;L; 3014 52DD 3015;;;;N;;;;; 1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L; 3014 6557 3015;;;;N;;;;; +1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L; 5F97;;;;N;;;;; +1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L; 53EF;;;;N;;;;; +1F300;CYCLONE;So;0;ON;;;;;N;;;;; +1F301;FOGGY;So;0;ON;;;;;N;;;;; +1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;; +1F303;NIGHT WITH STARS;So;0;ON;;;;;N;;;;; +1F304;SUNRISE OVER MOUNTAINS;So;0;ON;;;;;N;;;;; +1F305;SUNRISE;So;0;ON;;;;;N;;;;; +1F306;CITYSCAPE AT DUSK;So;0;ON;;;;;N;;;;; +1F307;SUNSET OVER BUILDINGS;So;0;ON;;;;;N;;;;; +1F308;RAINBOW;So;0;ON;;;;;N;;;;; +1F309;BRIDGE AT NIGHT;So;0;ON;;;;;N;;;;; +1F30A;WATER WAVE;So;0;ON;;;;;N;;;;; +1F30B;VOLCANO;So;0;ON;;;;;N;;;;; +1F30C;MILKY WAY;So;0;ON;;;;;N;;;;; +1F30D;EARTH GLOBE EUROPE-AFRICA;So;0;ON;;;;;N;;;;; +1F30E;EARTH GLOBE AMERICAS;So;0;ON;;;;;N;;;;; +1F30F;EARTH GLOBE ASIA-AUSTRALIA;So;0;ON;;;;;N;;;;; +1F310;GLOBE WITH MERIDIANS;So;0;ON;;;;;N;;;;; +1F311;NEW MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F312;WAXING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F313;FIRST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F314;WAXING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F315;FULL MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F316;WANING GIBBOUS MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F317;LAST QUARTER MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F318;WANING CRESCENT MOON SYMBOL;So;0;ON;;;;;N;;;;; +1F319;CRESCENT MOON;So;0;ON;;;;;N;;;;; +1F31A;NEW MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31B;FIRST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31C;LAST QUARTER MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31D;FULL MOON WITH FACE;So;0;ON;;;;;N;;;;; +1F31E;SUN WITH FACE;So;0;ON;;;;;N;;;;; +1F31F;GLOWING STAR;So;0;ON;;;;;N;;;;; +1F320;SHOOTING STAR;So;0;ON;;;;;N;;;;; +1F330;CHESTNUT;So;0;ON;;;;;N;;;;; +1F331;SEEDLING;So;0;ON;;;;;N;;;;; +1F332;EVERGREEN TREE;So;0;ON;;;;;N;;;;; +1F333;DECIDUOUS TREE;So;0;ON;;;;;N;;;;; +1F334;PALM TREE;So;0;ON;;;;;N;;;;; +1F335;CACTUS;So;0;ON;;;;;N;;;;; +1F337;TULIP;So;0;ON;;;;;N;;;;; +1F338;CHERRY BLOSSOM;So;0;ON;;;;;N;;;;; +1F339;ROSE;So;0;ON;;;;;N;;;;; +1F33A;HIBISCUS;So;0;ON;;;;;N;;;;; +1F33B;SUNFLOWER;So;0;ON;;;;;N;;;;; +1F33C;BLOSSOM;So;0;ON;;;;;N;;;;; +1F33D;EAR OF MAIZE;So;0;ON;;;;;N;;;;; +1F33E;EAR OF RICE;So;0;ON;;;;;N;;;;; +1F33F;HERB;So;0;ON;;;;;N;;;;; +1F340;FOUR LEAF CLOVER;So;0;ON;;;;;N;;;;; +1F341;MAPLE LEAF;So;0;ON;;;;;N;;;;; +1F342;FALLEN LEAF;So;0;ON;;;;;N;;;;; +1F343;LEAF FLUTTERING IN WIND;So;0;ON;;;;;N;;;;; +1F344;MUSHROOM;So;0;ON;;;;;N;;;;; +1F345;TOMATO;So;0;ON;;;;;N;;;;; +1F346;AUBERGINE;So;0;ON;;;;;N;;;;; +1F347;GRAPES;So;0;ON;;;;;N;;;;; +1F348;MELON;So;0;ON;;;;;N;;;;; +1F349;WATERMELON;So;0;ON;;;;;N;;;;; +1F34A;TANGERINE;So;0;ON;;;;;N;;;;; +1F34B;LEMON;So;0;ON;;;;;N;;;;; +1F34C;BANANA;So;0;ON;;;;;N;;;;; +1F34D;PINEAPPLE;So;0;ON;;;;;N;;;;; +1F34E;RED APPLE;So;0;ON;;;;;N;;;;; +1F34F;GREEN APPLE;So;0;ON;;;;;N;;;;; +1F350;PEAR;So;0;ON;;;;;N;;;;; +1F351;PEACH;So;0;ON;;;;;N;;;;; +1F352;CHERRIES;So;0;ON;;;;;N;;;;; +1F353;STRAWBERRY;So;0;ON;;;;;N;;;;; +1F354;HAMBURGER;So;0;ON;;;;;N;;;;; +1F355;SLICE OF PIZZA;So;0;ON;;;;;N;;;;; +1F356;MEAT ON BONE;So;0;ON;;;;;N;;;;; +1F357;POULTRY LEG;So;0;ON;;;;;N;;;;; +1F358;RICE CRACKER;So;0;ON;;;;;N;;;;; +1F359;RICE BALL;So;0;ON;;;;;N;;;;; +1F35A;COOKED RICE;So;0;ON;;;;;N;;;;; +1F35B;CURRY AND RICE;So;0;ON;;;;;N;;;;; +1F35C;STEAMING BOWL;So;0;ON;;;;;N;;;;; +1F35D;SPAGHETTI;So;0;ON;;;;;N;;;;; +1F35E;BREAD;So;0;ON;;;;;N;;;;; +1F35F;FRENCH FRIES;So;0;ON;;;;;N;;;;; +1F360;ROASTED SWEET POTATO;So;0;ON;;;;;N;;;;; +1F361;DANGO;So;0;ON;;;;;N;;;;; +1F362;ODEN;So;0;ON;;;;;N;;;;; +1F363;SUSHI;So;0;ON;;;;;N;;;;; +1F364;FRIED SHRIMP;So;0;ON;;;;;N;;;;; +1F365;FISH CAKE WITH SWIRL DESIGN;So;0;ON;;;;;N;;;;; +1F366;SOFT ICE CREAM;So;0;ON;;;;;N;;;;; +1F367;SHAVED ICE;So;0;ON;;;;;N;;;;; +1F368;ICE CREAM;So;0;ON;;;;;N;;;;; +1F369;DOUGHNUT;So;0;ON;;;;;N;;;;; +1F36A;COOKIE;So;0;ON;;;;;N;;;;; +1F36B;CHOCOLATE BAR;So;0;ON;;;;;N;;;;; +1F36C;CANDY;So;0;ON;;;;;N;;;;; +1F36D;LOLLIPOP;So;0;ON;;;;;N;;;;; +1F36E;CUSTARD;So;0;ON;;;;;N;;;;; +1F36F;HONEY POT;So;0;ON;;;;;N;;;;; +1F370;SHORTCAKE;So;0;ON;;;;;N;;;;; +1F371;BENTO BOX;So;0;ON;;;;;N;;;;; +1F372;POT OF FOOD;So;0;ON;;;;;N;;;;; +1F373;COOKING;So;0;ON;;;;;N;;;;; +1F374;FORK AND KNIFE;So;0;ON;;;;;N;;;;; +1F375;TEACUP WITHOUT HANDLE;So;0;ON;;;;;N;;;;; +1F376;SAKE BOTTLE AND CUP;So;0;ON;;;;;N;;;;; +1F377;WINE GLASS;So;0;ON;;;;;N;;;;; +1F378;COCKTAIL GLASS;So;0;ON;;;;;N;;;;; +1F379;TROPICAL DRINK;So;0;ON;;;;;N;;;;; +1F37A;BEER MUG;So;0;ON;;;;;N;;;;; +1F37B;CLINKING BEER MUGS;So;0;ON;;;;;N;;;;; +1F37C;BABY BOTTLE;So;0;ON;;;;;N;;;;; +1F380;RIBBON;So;0;ON;;;;;N;;;;; +1F381;WRAPPED PRESENT;So;0;ON;;;;;N;;;;; +1F382;BIRTHDAY CAKE;So;0;ON;;;;;N;;;;; +1F383;JACK-O-LANTERN;So;0;ON;;;;;N;;;;; +1F384;CHRISTMAS TREE;So;0;ON;;;;;N;;;;; +1F385;FATHER CHRISTMAS;So;0;ON;;;;;N;;;;; +1F386;FIREWORKS;So;0;ON;;;;;N;;;;; +1F387;FIREWORK SPARKLER;So;0;ON;;;;;N;;;;; +1F388;BALLOON;So;0;ON;;;;;N;;;;; +1F389;PARTY POPPER;So;0;ON;;;;;N;;;;; +1F38A;CONFETTI BALL;So;0;ON;;;;;N;;;;; +1F38B;TANABATA TREE;So;0;ON;;;;;N;;;;; +1F38C;CROSSED FLAGS;So;0;ON;;;;;N;;;;; +1F38D;PINE DECORATION;So;0;ON;;;;;N;;;;; +1F38E;JAPANESE DOLLS;So;0;ON;;;;;N;;;;; +1F38F;CARP STREAMER;So;0;ON;;;;;N;;;;; +1F390;WIND CHIME;So;0;ON;;;;;N;;;;; +1F391;MOON VIEWING CEREMONY;So;0;ON;;;;;N;;;;; +1F392;SCHOOL SATCHEL;So;0;ON;;;;;N;;;;; +1F393;GRADUATION CAP;So;0;ON;;;;;N;;;;; +1F3A0;CAROUSEL HORSE;So;0;ON;;;;;N;;;;; +1F3A1;FERRIS WHEEL;So;0;ON;;;;;N;;;;; +1F3A2;ROLLER COASTER;So;0;ON;;;;;N;;;;; +1F3A3;FISHING POLE AND FISH;So;0;ON;;;;;N;;;;; +1F3A4;MICROPHONE;So;0;ON;;;;;N;;;;; +1F3A5;MOVIE CAMERA;So;0;ON;;;;;N;;;;; +1F3A6;CINEMA;So;0;ON;;;;;N;;;;; +1F3A7;HEADPHONE;So;0;ON;;;;;N;;;;; +1F3A8;ARTIST PALETTE;So;0;ON;;;;;N;;;;; +1F3A9;TOP HAT;So;0;ON;;;;;N;;;;; +1F3AA;CIRCUS TENT;So;0;ON;;;;;N;;;;; +1F3AB;TICKET;So;0;ON;;;;;N;;;;; +1F3AC;CLAPPER BOARD;So;0;ON;;;;;N;;;;; +1F3AD;PERFORMING ARTS;So;0;ON;;;;;N;;;;; +1F3AE;VIDEO GAME;So;0;ON;;;;;N;;;;; +1F3AF;DIRECT HIT;So;0;ON;;;;;N;;;;; +1F3B0;SLOT MACHINE;So;0;ON;;;;;N;;;;; +1F3B1;BILLIARDS;So;0;ON;;;;;N;;;;; +1F3B2;GAME DIE;So;0;ON;;;;;N;;;;; +1F3B3;BOWLING;So;0;ON;;;;;N;;;;; +1F3B4;FLOWER PLAYING CARDS;So;0;ON;;;;;N;;;;; +1F3B5;MUSICAL NOTE;So;0;ON;;;;;N;;;;; +1F3B6;MULTIPLE MUSICAL NOTES;So;0;ON;;;;;N;;;;; +1F3B7;SAXOPHONE;So;0;ON;;;;;N;;;;; +1F3B8;GUITAR;So;0;ON;;;;;N;;;;; +1F3B9;MUSICAL KEYBOARD;So;0;ON;;;;;N;;;;; +1F3BA;TRUMPET;So;0;ON;;;;;N;;;;; +1F3BB;VIOLIN;So;0;ON;;;;;N;;;;; +1F3BC;MUSICAL SCORE;So;0;ON;;;;;N;;;;; +1F3BD;RUNNING SHIRT WITH SASH;So;0;ON;;;;;N;;;;; +1F3BE;TENNIS RACQUET AND BALL;So;0;ON;;;;;N;;;;; +1F3BF;SKI AND SKI BOOT;So;0;ON;;;;;N;;;;; +1F3C0;BASKETBALL AND HOOP;So;0;ON;;;;;N;;;;; +1F3C1;CHEQUERED FLAG;So;0;ON;;;;;N;;;;; +1F3C2;SNOWBOARDER;So;0;ON;;;;;N;;;;; +1F3C3;RUNNER;So;0;ON;;;;;N;;;;; +1F3C4;SURFER;So;0;ON;;;;;N;;;;; +1F3C6;TROPHY;So;0;ON;;;;;N;;;;; +1F3C7;HORSE RACING;So;0;ON;;;;;N;;;;; +1F3C8;AMERICAN FOOTBALL;So;0;ON;;;;;N;;;;; +1F3C9;RUGBY FOOTBALL;So;0;ON;;;;;N;;;;; +1F3CA;SWIMMER;So;0;ON;;;;;N;;;;; +1F3E0;HOUSE BUILDING;So;0;ON;;;;;N;;;;; +1F3E1;HOUSE WITH GARDEN;So;0;ON;;;;;N;;;;; +1F3E2;OFFICE BUILDING;So;0;ON;;;;;N;;;;; +1F3E3;JAPANESE POST OFFICE;So;0;ON;;;;;N;;;;; +1F3E4;EUROPEAN POST OFFICE;So;0;ON;;;;;N;;;;; +1F3E5;HOSPITAL;So;0;ON;;;;;N;;;;; +1F3E6;BANK;So;0;ON;;;;;N;;;;; +1F3E7;AUTOMATED TELLER MACHINE;So;0;ON;;;;;N;;;;; +1F3E8;HOTEL;So;0;ON;;;;;N;;;;; +1F3E9;LOVE HOTEL;So;0;ON;;;;;N;;;;; +1F3EA;CONVENIENCE STORE;So;0;ON;;;;;N;;;;; +1F3EB;SCHOOL;So;0;ON;;;;;N;;;;; +1F3EC;DEPARTMENT STORE;So;0;ON;;;;;N;;;;; +1F3ED;FACTORY;So;0;ON;;;;;N;;;;; +1F3EE;IZAKAYA LANTERN;So;0;ON;;;;;N;;;;; +1F3EF;JAPANESE CASTLE;So;0;ON;;;;;N;;;;; +1F3F0;EUROPEAN CASTLE;So;0;ON;;;;;N;;;;; +1F400;RAT;So;0;ON;;;;;N;;;;; +1F401;MOUSE;So;0;ON;;;;;N;;;;; +1F402;OX;So;0;ON;;;;;N;;;;; +1F403;WATER BUFFALO;So;0;ON;;;;;N;;;;; +1F404;COW;So;0;ON;;;;;N;;;;; +1F405;TIGER;So;0;ON;;;;;N;;;;; +1F406;LEOPARD;So;0;ON;;;;;N;;;;; +1F407;RABBIT;So;0;ON;;;;;N;;;;; +1F408;CAT;So;0;ON;;;;;N;;;;; +1F409;DRAGON;So;0;ON;;;;;N;;;;; +1F40A;CROCODILE;So;0;ON;;;;;N;;;;; +1F40B;WHALE;So;0;ON;;;;;N;;;;; +1F40C;SNAIL;So;0;ON;;;;;N;;;;; +1F40D;SNAKE;So;0;ON;;;;;N;;;;; +1F40E;HORSE;So;0;ON;;;;;N;;;;; +1F40F;RAM;So;0;ON;;;;;N;;;;; +1F410;GOAT;So;0;ON;;;;;N;;;;; +1F411;SHEEP;So;0;ON;;;;;N;;;;; +1F412;MONKEY;So;0;ON;;;;;N;;;;; +1F413;ROOSTER;So;0;ON;;;;;N;;;;; +1F414;CHICKEN;So;0;ON;;;;;N;;;;; +1F415;DOG;So;0;ON;;;;;N;;;;; +1F416;PIG;So;0;ON;;;;;N;;;;; +1F417;BOAR;So;0;ON;;;;;N;;;;; +1F418;ELEPHANT;So;0;ON;;;;;N;;;;; +1F419;OCTOPUS;So;0;ON;;;;;N;;;;; +1F41A;SPIRAL SHELL;So;0;ON;;;;;N;;;;; +1F41B;BUG;So;0;ON;;;;;N;;;;; +1F41C;ANT;So;0;ON;;;;;N;;;;; +1F41D;HONEYBEE;So;0;ON;;;;;N;;;;; +1F41E;LADY BEETLE;So;0;ON;;;;;N;;;;; +1F41F;FISH;So;0;ON;;;;;N;;;;; +1F420;TROPICAL FISH;So;0;ON;;;;;N;;;;; +1F421;BLOWFISH;So;0;ON;;;;;N;;;;; +1F422;TURTLE;So;0;ON;;;;;N;;;;; +1F423;HATCHING CHICK;So;0;ON;;;;;N;;;;; +1F424;BABY CHICK;So;0;ON;;;;;N;;;;; +1F425;FRONT-FACING BABY CHICK;So;0;ON;;;;;N;;;;; +1F426;BIRD;So;0;ON;;;;;N;;;;; +1F427;PENGUIN;So;0;ON;;;;;N;;;;; +1F428;KOALA;So;0;ON;;;;;N;;;;; +1F429;POODLE;So;0;ON;;;;;N;;;;; +1F42A;DROMEDARY CAMEL;So;0;ON;;;;;N;;;;; +1F42B;BACTRIAN CAMEL;So;0;ON;;;;;N;;;;; +1F42C;DOLPHIN;So;0;ON;;;;;N;;;;; +1F42D;MOUSE FACE;So;0;ON;;;;;N;;;;; +1F42E;COW FACE;So;0;ON;;;;;N;;;;; +1F42F;TIGER FACE;So;0;ON;;;;;N;;;;; +1F430;RABBIT FACE;So;0;ON;;;;;N;;;;; +1F431;CAT FACE;So;0;ON;;;;;N;;;;; +1F432;DRAGON FACE;So;0;ON;;;;;N;;;;; +1F433;SPOUTING WHALE;So;0;ON;;;;;N;;;;; +1F434;HORSE FACE;So;0;ON;;;;;N;;;;; +1F435;MONKEY FACE;So;0;ON;;;;;N;;;;; +1F436;DOG FACE;So;0;ON;;;;;N;;;;; +1F437;PIG FACE;So;0;ON;;;;;N;;;;; +1F438;FROG FACE;So;0;ON;;;;;N;;;;; +1F439;HAMSTER FACE;So;0;ON;;;;;N;;;;; +1F43A;WOLF FACE;So;0;ON;;;;;N;;;;; +1F43B;BEAR FACE;So;0;ON;;;;;N;;;;; +1F43C;PANDA FACE;So;0;ON;;;;;N;;;;; +1F43D;PIG NOSE;So;0;ON;;;;;N;;;;; +1F43E;PAW PRINTS;So;0;ON;;;;;N;;;;; +1F440;EYES;So;0;ON;;;;;N;;;;; +1F442;EAR;So;0;ON;;;;;N;;;;; +1F443;NOSE;So;0;ON;;;;;N;;;;; +1F444;MOUTH;So;0;ON;;;;;N;;;;; +1F445;TONGUE;So;0;ON;;;;;N;;;;; +1F446;WHITE UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F447;WHITE DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F448;WHITE LEFT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F449;WHITE RIGHT POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F44A;FISTED HAND SIGN;So;0;ON;;;;;N;;;;; +1F44B;WAVING HAND SIGN;So;0;ON;;;;;N;;;;; +1F44C;OK HAND SIGN;So;0;ON;;;;;N;;;;; +1F44D;THUMBS UP SIGN;So;0;ON;;;;;N;;;;; +1F44E;THUMBS DOWN SIGN;So;0;ON;;;;;N;;;;; +1F44F;CLAPPING HANDS SIGN;So;0;ON;;;;;N;;;;; +1F450;OPEN HANDS SIGN;So;0;ON;;;;;N;;;;; +1F451;CROWN;So;0;ON;;;;;N;;;;; +1F452;WOMANS HAT;So;0;ON;;;;;N;;;;; +1F453;EYEGLASSES;So;0;ON;;;;;N;;;;; +1F454;NECKTIE;So;0;ON;;;;;N;;;;; +1F455;T-SHIRT;So;0;ON;;;;;N;;;;; +1F456;JEANS;So;0;ON;;;;;N;;;;; +1F457;DRESS;So;0;ON;;;;;N;;;;; +1F458;KIMONO;So;0;ON;;;;;N;;;;; +1F459;BIKINI;So;0;ON;;;;;N;;;;; +1F45A;WOMANS CLOTHES;So;0;ON;;;;;N;;;;; +1F45B;PURSE;So;0;ON;;;;;N;;;;; +1F45C;HANDBAG;So;0;ON;;;;;N;;;;; +1F45D;POUCH;So;0;ON;;;;;N;;;;; +1F45E;MANS SHOE;So;0;ON;;;;;N;;;;; +1F45F;ATHLETIC SHOE;So;0;ON;;;;;N;;;;; +1F460;HIGH-HEELED SHOE;So;0;ON;;;;;N;;;;; +1F461;WOMANS SANDAL;So;0;ON;;;;;N;;;;; +1F462;WOMANS BOOTS;So;0;ON;;;;;N;;;;; +1F463;FOOTPRINTS;So;0;ON;;;;;N;;;;; +1F464;BUST IN SILHOUETTE;So;0;ON;;;;;N;;;;; +1F465;BUSTS IN SILHOUETTE;So;0;ON;;;;;N;;;;; +1F466;BOY;So;0;ON;;;;;N;;;;; +1F467;GIRL;So;0;ON;;;;;N;;;;; +1F468;MAN;So;0;ON;;;;;N;;;;; +1F469;WOMAN;So;0;ON;;;;;N;;;;; +1F46A;FAMILY;So;0;ON;;;;;N;;;;; +1F46B;MAN AND WOMAN HOLDING HANDS;So;0;ON;;;;;N;;;;; +1F46C;TWO MEN HOLDING HANDS;So;0;ON;;;;;N;;;;; +1F46D;TWO WOMEN HOLDING HANDS;So;0;ON;;;;;N;;;;; +1F46E;POLICE OFFICER;So;0;ON;;;;;N;;;;; +1F46F;WOMAN WITH BUNNY EARS;So;0;ON;;;;;N;;;;; +1F470;BRIDE WITH VEIL;So;0;ON;;;;;N;;;;; +1F471;PERSON WITH BLOND HAIR;So;0;ON;;;;;N;;;;; +1F472;MAN WITH GUA PI MAO;So;0;ON;;;;;N;;;;; +1F473;MAN WITH TURBAN;So;0;ON;;;;;N;;;;; +1F474;OLDER MAN;So;0;ON;;;;;N;;;;; +1F475;OLDER WOMAN;So;0;ON;;;;;N;;;;; +1F476;BABY;So;0;ON;;;;;N;;;;; +1F477;CONSTRUCTION WORKER;So;0;ON;;;;;N;;;;; +1F478;PRINCESS;So;0;ON;;;;;N;;;;; +1F479;JAPANESE OGRE;So;0;ON;;;;;N;;;;; +1F47A;JAPANESE GOBLIN;So;0;ON;;;;;N;;;;; +1F47B;GHOST;So;0;ON;;;;;N;;;;; +1F47C;BABY ANGEL;So;0;ON;;;;;N;;;;; +1F47D;EXTRATERRESTRIAL ALIEN;So;0;ON;;;;;N;;;;; +1F47E;ALIEN MONSTER;So;0;ON;;;;;N;;;;; +1F47F;IMP;So;0;ON;;;;;N;;;;; +1F480;SKULL;So;0;ON;;;;;N;;;;; +1F481;INFORMATION DESK PERSON;So;0;ON;;;;;N;;;;; +1F482;GUARDSMAN;So;0;ON;;;;;N;;;;; +1F483;DANCER;So;0;ON;;;;;N;;;;; +1F484;LIPSTICK;So;0;ON;;;;;N;;;;; +1F485;NAIL POLISH;So;0;ON;;;;;N;;;;; +1F486;FACE MASSAGE;So;0;ON;;;;;N;;;;; +1F487;HAIRCUT;So;0;ON;;;;;N;;;;; +1F488;BARBER POLE;So;0;ON;;;;;N;;;;; +1F489;SYRINGE;So;0;ON;;;;;N;;;;; +1F48A;PILL;So;0;ON;;;;;N;;;;; +1F48B;KISS MARK;So;0;ON;;;;;N;;;;; +1F48C;LOVE LETTER;So;0;L;;;;;N;;;;; +1F48D;RING;So;0;ON;;;;;N;;;;; +1F48E;GEM STONE;So;0;ON;;;;;N;;;;; +1F48F;KISS;So;0;ON;;;;;N;;;;; +1F490;BOUQUET;So;0;ON;;;;;N;;;;; +1F491;COUPLE WITH HEART;So;0;ON;;;;;N;;;;; +1F492;WEDDING;So;0;ON;;;;;N;;;;; +1F493;BEATING HEART;So;0;ON;;;;;N;;;;; +1F494;BROKEN HEART;So;0;ON;;;;;N;;;;; +1F495;TWO HEARTS;So;0;ON;;;;;N;;;;; +1F496;SPARKLING HEART;So;0;ON;;;;;N;;;;; +1F497;GROWING HEART;So;0;ON;;;;;N;;;;; +1F498;HEART WITH ARROW;So;0;ON;;;;;N;;;;; +1F499;BLUE HEART;So;0;ON;;;;;N;;;;; +1F49A;GREEN HEART;So;0;ON;;;;;N;;;;; +1F49B;YELLOW HEART;So;0;ON;;;;;N;;;;; +1F49C;PURPLE HEART;So;0;ON;;;;;N;;;;; +1F49D;HEART WITH RIBBON;So;0;ON;;;;;N;;;;; +1F49E;REVOLVING HEARTS;So;0;ON;;;;;N;;;;; +1F49F;HEART DECORATION;So;0;ON;;;;;N;;;;; +1F4A0;DIAMOND SHAPE WITH A DOT INSIDE;So;0;ON;;;;;N;;;;; +1F4A1;ELECTRIC LIGHT BULB;So;0;ON;;;;;N;;;;; +1F4A2;ANGER SYMBOL;So;0;ON;;;;;N;;;;; +1F4A3;BOMB;So;0;ON;;;;;N;;;;; +1F4A4;SLEEPING SYMBOL;So;0;ON;;;;;N;;;;; +1F4A5;COLLISION SYMBOL;So;0;ON;;;;;N;;;;; +1F4A6;SPLASHING SWEAT SYMBOL;So;0;ON;;;;;N;;;;; +1F4A7;DROPLET;So;0;ON;;;;;N;;;;; +1F4A8;DASH SYMBOL;So;0;ON;;;;;N;;;;; +1F4A9;PILE OF POO;So;0;ON;;;;;N;;;;; +1F4AA;FLEXED BICEPS;So;0;ON;;;;;N;;;;; +1F4AB;DIZZY SYMBOL;So;0;ON;;;;;N;;;;; +1F4AC;SPEECH BALLOON;So;0;ON;;;;;N;;;;; +1F4AD;THOUGHT BALLOON;So;0;ON;;;;;N;;;;; +1F4AE;WHITE FLOWER;So;0;ON;;;;;N;;;;; +1F4AF;HUNDRED POINTS SYMBOL;So;0;ON;;;;;N;;;;; +1F4B0;MONEY BAG;So;0;ON;;;;;N;;;;; +1F4B1;CURRENCY EXCHANGE;So;0;ON;;;;;N;;;;; +1F4B2;HEAVY DOLLAR SIGN;So;0;ON;;;;;N;;;;; +1F4B3;CREDIT CARD;So;0;ON;;;;;N;;;;; +1F4B4;BANKNOTE WITH YEN SIGN;So;0;ON;;;;;N;;;;; +1F4B5;BANKNOTE WITH DOLLAR SIGN;So;0;ON;;;;;N;;;;; +1F4B6;BANKNOTE WITH EURO SIGN;So;0;ON;;;;;N;;;;; +1F4B7;BANKNOTE WITH POUND SIGN;So;0;ON;;;;;N;;;;; +1F4B8;MONEY WITH WINGS;So;0;ON;;;;;N;;;;; +1F4B9;CHART WITH UPWARDS TREND AND YEN SIGN;So;0;ON;;;;;N;;;;; +1F4BA;SEAT;So;0;ON;;;;;N;;;;; +1F4BB;PERSONAL COMPUTER;So;0;ON;;;;;N;;;;; +1F4BC;BRIEFCASE;So;0;ON;;;;;N;;;;; +1F4BD;MINIDISC;So;0;ON;;;;;N;;;;; +1F4BE;FLOPPY DISK;So;0;ON;;;;;N;;;;; +1F4BF;OPTICAL DISC;So;0;ON;;;;;N;;;;; +1F4C0;DVD;So;0;ON;;;;;N;;;;; +1F4C1;FILE FOLDER;So;0;ON;;;;;N;;;;; +1F4C2;OPEN FILE FOLDER;So;0;ON;;;;;N;;;;; +1F4C3;PAGE WITH CURL;So;0;ON;;;;;N;;;;; +1F4C4;PAGE FACING UP;So;0;ON;;;;;N;;;;; +1F4C5;CALENDAR;So;0;ON;;;;;N;;;;; +1F4C6;TEAR-OFF CALENDAR;So;0;ON;;;;;N;;;;; +1F4C7;CARD INDEX;So;0;ON;;;;;N;;;;; +1F4C8;CHART WITH UPWARDS TREND;So;0;ON;;;;;N;;;;; +1F4C9;CHART WITH DOWNWARDS TREND;So;0;ON;;;;;N;;;;; +1F4CA;BAR CHART;So;0;ON;;;;;N;;;;; +1F4CB;CLIPBOARD;So;0;ON;;;;;N;;;;; +1F4CC;PUSHPIN;So;0;ON;;;;;N;;;;; +1F4CD;ROUND PUSHPIN;So;0;ON;;;;;N;;;;; +1F4CE;PAPERCLIP;So;0;ON;;;;;N;;;;; +1F4CF;STRAIGHT RULER;So;0;ON;;;;;N;;;;; +1F4D0;TRIANGULAR RULER;So;0;ON;;;;;N;;;;; +1F4D1;BOOKMARK TABS;So;0;ON;;;;;N;;;;; +1F4D2;LEDGER;So;0;ON;;;;;N;;;;; +1F4D3;NOTEBOOK;So;0;ON;;;;;N;;;;; +1F4D4;NOTEBOOK WITH DECORATIVE COVER;So;0;ON;;;;;N;;;;; +1F4D5;CLOSED BOOK;So;0;ON;;;;;N;;;;; +1F4D6;OPEN BOOK;So;0;ON;;;;;N;;;;; +1F4D7;GREEN BOOK;So;0;ON;;;;;N;;;;; +1F4D8;BLUE BOOK;So;0;ON;;;;;N;;;;; +1F4D9;ORANGE BOOK;So;0;ON;;;;;N;;;;; +1F4DA;BOOKS;So;0;ON;;;;;N;;;;; +1F4DB;NAME BADGE;So;0;ON;;;;;N;;;;; +1F4DC;SCROLL;So;0;ON;;;;;N;;;;; +1F4DD;MEMO;So;0;ON;;;;;N;;;;; +1F4DE;TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; +1F4DF;PAGER;So;0;ON;;;;;N;;;;; +1F4E0;FAX MACHINE;So;0;ON;;;;;N;;;;; +1F4E1;SATELLITE ANTENNA;So;0;ON;;;;;N;;;;; +1F4E2;PUBLIC ADDRESS LOUDSPEAKER;So;0;ON;;;;;N;;;;; +1F4E3;CHEERING MEGAPHONE;So;0;ON;;;;;N;;;;; +1F4E4;OUTBOX TRAY;So;0;ON;;;;;N;;;;; +1F4E5;INBOX TRAY;So;0;ON;;;;;N;;;;; +1F4E6;PACKAGE;So;0;ON;;;;;N;;;;; +1F4E7;E-MAIL SYMBOL;So;0;ON;;;;;N;;;;; +1F4E8;INCOMING ENVELOPE;So;0;ON;;;;;N;;;;; +1F4E9;ENVELOPE WITH DOWNWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F4EA;CLOSED MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;; +1F4EB;CLOSED MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;; +1F4EC;OPEN MAILBOX WITH RAISED FLAG;So;0;ON;;;;;N;;;;; +1F4ED;OPEN MAILBOX WITH LOWERED FLAG;So;0;ON;;;;;N;;;;; +1F4EE;POSTBOX;So;0;ON;;;;;N;;;;; +1F4EF;POSTAL HORN;So;0;ON;;;;;N;;;;; +1F4F0;NEWSPAPER;So;0;ON;;;;;N;;;;; +1F4F1;MOBILE PHONE;So;0;ON;;;;;N;;;;; +1F4F2;MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT;So;0;ON;;;;;N;;;;; +1F4F3;VIBRATION MODE;So;0;ON;;;;;N;;;;; +1F4F4;MOBILE PHONE OFF;So;0;ON;;;;;N;;;;; +1F4F5;NO MOBILE PHONES;So;0;ON;;;;;N;;;;; +1F4F6;ANTENNA WITH BARS;So;0;ON;;;;;N;;;;; +1F4F7;CAMERA;So;0;ON;;;;;N;;;;; +1F4F9;VIDEO CAMERA;So;0;ON;;;;;N;;;;; +1F4FA;TELEVISION;So;0;ON;;;;;N;;;;; +1F4FB;RADIO;So;0;ON;;;;;N;;;;; +1F4FC;VIDEOCASSETTE;So;0;ON;;;;;N;;;;; +1F500;TWISTED RIGHTWARDS ARROWS;So;0;ON;;;;;N;;;;; +1F501;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F502;CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY;So;0;ON;;;;;N;;;;; +1F503;CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F504;ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS;So;0;ON;;;;;N;;;;; +1F505;LOW BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;; +1F506;HIGH BRIGHTNESS SYMBOL;So;0;ON;;;;;N;;;;; +1F507;SPEAKER WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;; +1F508;SPEAKER;So;0;ON;;;;;N;;;;; +1F509;SPEAKER WITH ONE SOUND WAVE;So;0;ON;;;;;N;;;;; +1F50A;SPEAKER WITH THREE SOUND WAVES;So;0;ON;;;;;N;;;;; +1F50B;BATTERY;So;0;ON;;;;;N;;;;; +1F50C;ELECTRIC PLUG;So;0;ON;;;;;N;;;;; +1F50D;LEFT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;; +1F50E;RIGHT-POINTING MAGNIFYING GLASS;So;0;ON;;;;;N;;;;; +1F50F;LOCK WITH INK PEN;So;0;ON;;;;;N;;;;; +1F510;CLOSED LOCK WITH KEY;So;0;ON;;;;;N;;;;; +1F511;KEY;So;0;ON;;;;;N;;;;; +1F512;LOCK;So;0;ON;;;;;N;;;;; +1F513;OPEN LOCK;So;0;ON;;;;;N;;;;; +1F514;BELL;So;0;ON;;;;;N;;;;; +1F515;BELL WITH CANCELLATION STROKE;So;0;ON;;;;;N;;;;; +1F516;BOOKMARK;So;0;ON;;;;;N;;;;; +1F517;LINK SYMBOL;So;0;ON;;;;;N;;;;; +1F518;RADIO BUTTON;So;0;ON;;;;;N;;;;; +1F519;BACK WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51A;END WITH LEFTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51B;ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51C;SOON WITH RIGHTWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51D;TOP WITH UPWARDS ARROW ABOVE;So;0;ON;;;;;N;;;;; +1F51E;NO ONE UNDER EIGHTEEN SYMBOL;So;0;ON;;;;;N;;;;; +1F51F;KEYCAP TEN;So;0;ON;;;;;N;;;;; +1F520;INPUT SYMBOL FOR LATIN CAPITAL LETTERS;So;0;ON;;;;;N;;;;; +1F521;INPUT SYMBOL FOR LATIN SMALL LETTERS;So;0;ON;;;;;N;;;;; +1F522;INPUT SYMBOL FOR NUMBERS;So;0;ON;;;;;N;;;;; +1F523;INPUT SYMBOL FOR SYMBOLS;So;0;ON;;;;;N;;;;; +1F524;INPUT SYMBOL FOR LATIN LETTERS;So;0;L;;;;;N;;;;; +1F525;FIRE;So;0;ON;;;;;N;;;;; +1F526;ELECTRIC TORCH;So;0;ON;;;;;N;;;;; +1F527;WRENCH;So;0;ON;;;;;N;;;;; +1F528;HAMMER;So;0;ON;;;;;N;;;;; +1F529;NUT AND BOLT;So;0;ON;;;;;N;;;;; +1F52A;HOCHO;So;0;ON;;;;;N;;;;; +1F52B;PISTOL;So;0;ON;;;;;N;;;;; +1F52C;MICROSCOPE;So;0;ON;;;;;N;;;;; +1F52D;TELESCOPE;So;0;ON;;;;;N;;;;; +1F52E;CRYSTAL BALL;So;0;ON;;;;;N;;;;; +1F52F;SIX POINTED STAR WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; +1F530;JAPANESE SYMBOL FOR BEGINNER;So;0;ON;;;;;N;;;;; +1F531;TRIDENT EMBLEM;So;0;ON;;;;;N;;;;; +1F532;BLACK SQUARE BUTTON;So;0;ON;;;;;N;;;;; +1F533;WHITE SQUARE BUTTON;So;0;ON;;;;;N;;;;; +1F534;LARGE RED CIRCLE;So;0;ON;;;;;N;;;;; +1F535;LARGE BLUE CIRCLE;So;0;ON;;;;;N;;;;; +1F536;LARGE ORANGE DIAMOND;So;0;ON;;;;;N;;;;; +1F537;LARGE BLUE DIAMOND;So;0;ON;;;;;N;;;;; +1F538;SMALL ORANGE DIAMOND;So;0;ON;;;;;N;;;;; +1F539;SMALL BLUE DIAMOND;So;0;ON;;;;;N;;;;; +1F53A;UP-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53B;DOWN-POINTING RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53C;UP-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F53D;DOWN-POINTING SMALL RED TRIANGLE;So;0;ON;;;;;N;;;;; +1F550;CLOCK FACE ONE OCLOCK;So;0;ON;;;;;N;;;;; +1F551;CLOCK FACE TWO OCLOCK;So;0;ON;;;;;N;;;;; +1F552;CLOCK FACE THREE OCLOCK;So;0;ON;;;;;N;;;;; +1F553;CLOCK FACE FOUR OCLOCK;So;0;ON;;;;;N;;;;; +1F554;CLOCK FACE FIVE OCLOCK;So;0;ON;;;;;N;;;;; +1F555;CLOCK FACE SIX OCLOCK;So;0;ON;;;;;N;;;;; +1F556;CLOCK FACE SEVEN OCLOCK;So;0;ON;;;;;N;;;;; +1F557;CLOCK FACE EIGHT OCLOCK;So;0;ON;;;;;N;;;;; +1F558;CLOCK FACE NINE OCLOCK;So;0;ON;;;;;N;;;;; +1F559;CLOCK FACE TEN OCLOCK;So;0;ON;;;;;N;;;;; +1F55A;CLOCK FACE ELEVEN OCLOCK;So;0;ON;;;;;N;;;;; +1F55B;CLOCK FACE TWELVE OCLOCK;So;0;ON;;;;;N;;;;; +1F55C;CLOCK FACE ONE-THIRTY;So;0;ON;;;;;N;;;;; +1F55D;CLOCK FACE TWO-THIRTY;So;0;ON;;;;;N;;;;; +1F55E;CLOCK FACE THREE-THIRTY;So;0;ON;;;;;N;;;;; +1F55F;CLOCK FACE FOUR-THIRTY;So;0;ON;;;;;N;;;;; +1F560;CLOCK FACE FIVE-THIRTY;So;0;ON;;;;;N;;;;; +1F561;CLOCK FACE SIX-THIRTY;So;0;ON;;;;;N;;;;; +1F562;CLOCK FACE SEVEN-THIRTY;So;0;ON;;;;;N;;;;; +1F563;CLOCK FACE EIGHT-THIRTY;So;0;ON;;;;;N;;;;; +1F564;CLOCK FACE NINE-THIRTY;So;0;ON;;;;;N;;;;; +1F565;CLOCK FACE TEN-THIRTY;So;0;ON;;;;;N;;;;; +1F566;CLOCK FACE ELEVEN-THIRTY;So;0;ON;;;;;N;;;;; +1F567;CLOCK FACE TWELVE-THIRTY;So;0;ON;;;;;N;;;;; +1F5FB;MOUNT FUJI;So;0;ON;;;;;N;;;;; +1F5FC;TOKYO TOWER;So;0;ON;;;;;N;;;;; +1F5FD;STATUE OF LIBERTY;So;0;ON;;;;;N;;;;; +1F5FE;SILHOUETTE OF JAPAN;So;0;ON;;;;;N;;;;; +1F5FF;MOYAI;So;0;ON;;;;;N;;;;; +1F601;GRINNING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F602;FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; +1F603;SMILING FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F604;SMILING FACE WITH OPEN MOUTH AND SMILING EYES;So;0;ON;;;;;N;;;;; +1F605;SMILING FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; +1F606;SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; +1F607;SMILING FACE WITH HALO;So;0;ON;;;;;N;;;;; +1F608;SMILING FACE WITH HORNS;So;0;ON;;;;;N;;;;; +1F609;WINKING FACE;So;0;ON;;;;;N;;;;; +1F60A;SMILING FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F60B;FACE SAVOURING DELICIOUS FOOD;So;0;ON;;;;;N;;;;; +1F60C;RELIEVED FACE;So;0;ON;;;;;N;;;;; +1F60D;SMILING FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;; +1F60E;SMILING FACE WITH SUNGLASSES;So;0;ON;;;;;N;;;;; +1F60F;SMIRKING FACE;So;0;ON;;;;;N;;;;; +1F610;NEUTRAL FACE;So;0;ON;;;;;N;;;;; +1F612;UNAMUSED FACE;So;0;ON;;;;;N;;;;; +1F613;FACE WITH COLD SWEAT;So;0;ON;;;;;N;;;;; +1F614;PENSIVE FACE;So;0;ON;;;;;N;;;;; +1F616;CONFOUNDED FACE;So;0;ON;;;;;N;;;;; +1F618;FACE THROWING A KISS;So;0;ON;;;;;N;;;;; +1F61A;KISSING FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1F61C;FACE WITH STUCK-OUT TONGUE AND WINKING EYE;So;0;ON;;;;;N;;;;; +1F61D;FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES;So;0;ON;;;;;N;;;;; +1F61E;DISAPPOINTED FACE;So;0;ON;;;;;N;;;;; +1F620;ANGRY FACE;So;0;ON;;;;;N;;;;; +1F621;POUTING FACE;So;0;ON;;;;;N;;;;; +1F622;CRYING FACE;So;0;ON;;;;;N;;;;; +1F623;PERSEVERING FACE;So;0;ON;;;;;N;;;;; +1F624;FACE WITH LOOK OF TRIUMPH;So;0;ON;;;;;N;;;;; +1F625;DISAPPOINTED BUT RELIEVED FACE;So;0;ON;;;;;N;;;;; +1F628;FEARFUL FACE;So;0;ON;;;;;N;;;;; +1F629;WEARY FACE;So;0;ON;;;;;N;;;;; +1F62A;SLEEPY FACE;So;0;ON;;;;;N;;;;; +1F62B;TIRED FACE;So;0;ON;;;;;N;;;;; +1F62D;LOUDLY CRYING FACE;So;0;ON;;;;;N;;;;; +1F630;FACE WITH OPEN MOUTH AND COLD SWEAT;So;0;ON;;;;;N;;;;; +1F631;FACE SCREAMING IN FEAR;So;0;ON;;;;;N;;;;; +1F632;ASTONISHED FACE;So;0;ON;;;;;N;;;;; +1F633;FLUSHED FACE;So;0;ON;;;;;N;;;;; +1F635;DIZZY FACE;So;0;ON;;;;;N;;;;; +1F636;FACE WITHOUT MOUTH;So;0;ON;;;;;N;;;;; +1F637;FACE WITH MEDICAL MASK;So;0;ON;;;;;N;;;;; +1F638;GRINNING CAT FACE WITH SMILING EYES;So;0;ON;;;;;N;;;;; +1F639;CAT FACE WITH TEARS OF JOY;So;0;ON;;;;;N;;;;; +1F63A;SMILING CAT FACE WITH OPEN MOUTH;So;0;ON;;;;;N;;;;; +1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES;So;0;ON;;;;;N;;;;; +1F63C;CAT FACE WITH WRY SMILE;So;0;ON;;;;;N;;;;; +1F63D;KISSING CAT FACE WITH CLOSED EYES;So;0;ON;;;;;N;;;;; +1F63E;POUTING CAT FACE;So;0;ON;;;;;N;;;;; +1F63F;CRYING CAT FACE;So;0;ON;;;;;N;;;;; +1F640;WEARY CAT FACE;So;0;ON;;;;;N;;;;; +1F645;FACE WITH NO GOOD GESTURE;So;0;ON;;;;;N;;;;; +1F646;FACE WITH OK GESTURE;So;0;ON;;;;;N;;;;; +1F647;PERSON BOWING DEEPLY;So;0;ON;;;;;N;;;;; +1F648;SEE-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; +1F649;HEAR-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; +1F64A;SPEAK-NO-EVIL MONKEY;So;0;ON;;;;;N;;;;; +1F64B;HAPPY PERSON RAISING ONE HAND;So;0;ON;;;;;N;;;;; +1F64C;PERSON RAISING BOTH HANDS IN CELEBRATION;So;0;ON;;;;;N;;;;; +1F64D;PERSON FROWNING;So;0;ON;;;;;N;;;;; +1F64E;PERSON WITH POUTING FACE;So;0;ON;;;;;N;;;;; +1F64F;PERSON WITH FOLDED HANDS;So;0;ON;;;;;N;;;;; +1F680;ROCKET;So;0;ON;;;;;N;;;;; +1F681;HELICOPTER;So;0;ON;;;;;N;;;;; +1F682;STEAM LOCOMOTIVE;So;0;ON;;;;;N;;;;; +1F683;RAILWAY CAR;So;0;ON;;;;;N;;;;; +1F684;HIGH-SPEED TRAIN;So;0;ON;;;;;N;;;;; +1F685;HIGH-SPEED TRAIN WITH BULLET NOSE;So;0;ON;;;;;N;;;;; +1F686;TRAIN;So;0;ON;;;;;N;;;;; +1F687;METRO;So;0;ON;;;;;N;;;;; +1F688;LIGHT RAIL;So;0;ON;;;;;N;;;;; +1F689;STATION;So;0;ON;;;;;N;;;;; +1F68A;TRAM;So;0;ON;;;;;N;;;;; +1F68B;TRAM CAR;So;0;ON;;;;;N;;;;; +1F68C;BUS;So;0;ON;;;;;N;;;;; +1F68D;ONCOMING BUS;So;0;ON;;;;;N;;;;; +1F68E;TROLLEYBUS;So;0;ON;;;;;N;;;;; +1F68F;BUS STOP;So;0;ON;;;;;N;;;;; +1F690;MINIBUS;So;0;ON;;;;;N;;;;; +1F691;AMBULANCE;So;0;ON;;;;;N;;;;; +1F692;FIRE ENGINE;So;0;ON;;;;;N;;;;; +1F693;POLICE CAR;So;0;ON;;;;;N;;;;; +1F694;ONCOMING POLICE CAR;So;0;ON;;;;;N;;;;; +1F695;TAXI;So;0;ON;;;;;N;;;;; +1F696;ONCOMING TAXI;So;0;ON;;;;;N;;;;; +1F697;AUTOMOBILE;So;0;ON;;;;;N;;;;; +1F698;ONCOMING AUTOMOBILE;So;0;ON;;;;;N;;;;; +1F699;RECREATIONAL VEHICLE;So;0;ON;;;;;N;;;;; +1F69A;DELIVERY TRUCK;So;0;ON;;;;;N;;;;; +1F69B;ARTICULATED LORRY;So;0;ON;;;;;N;;;;; +1F69C;TRACTOR;So;0;ON;;;;;N;;;;; +1F69D;MONORAIL;So;0;ON;;;;;N;;;;; +1F69E;MOUNTAIN RAILWAY;So;0;ON;;;;;N;;;;; +1F69F;SUSPENSION RAILWAY;So;0;ON;;;;;N;;;;; +1F6A0;MOUNTAIN CABLEWAY;So;0;ON;;;;;N;;;;; +1F6A1;AERIAL TRAMWAY;So;0;ON;;;;;N;;;;; +1F6A2;SHIP;So;0;ON;;;;;N;;;;; +1F6A3;ROWBOAT;So;0;ON;;;;;N;;;;; +1F6A4;SPEEDBOAT;So;0;ON;;;;;N;;;;; +1F6A5;HORIZONTAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;; +1F6A6;VERTICAL TRAFFIC LIGHT;So;0;ON;;;;;N;;;;; +1F6A7;CONSTRUCTION SIGN;So;0;ON;;;;;N;;;;; +1F6A8;POLICE CARS REVOLVING LIGHT;So;0;ON;;;;;N;;;;; +1F6A9;TRIANGULAR FLAG ON POST;So;0;ON;;;;;N;;;;; +1F6AA;DOOR;So;0;ON;;;;;N;;;;; +1F6AB;NO ENTRY SIGN;So;0;ON;;;;;N;;;;; +1F6AC;SMOKING SYMBOL;So;0;ON;;;;;N;;;;; +1F6AD;NO SMOKING SYMBOL;So;0;ON;;;;;N;;;;; +1F6AE;PUT LITTER IN ITS PLACE SYMBOL;So;0;ON;;;;;N;;;;; +1F6AF;DO NOT LITTER SYMBOL;So;0;ON;;;;;N;;;;; +1F6B0;POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;; +1F6B1;NON-POTABLE WATER SYMBOL;So;0;ON;;;;;N;;;;; +1F6B2;BICYCLE;So;0;ON;;;;;N;;;;; +1F6B3;NO BICYCLES;So;0;ON;;;;;N;;;;; +1F6B4;BICYCLIST;So;0;ON;;;;;N;;;;; +1F6B5;MOUNTAIN BICYCLIST;So;0;ON;;;;;N;;;;; +1F6B6;PEDESTRIAN;So;0;ON;;;;;N;;;;; +1F6B7;NO PEDESTRIANS;So;0;ON;;;;;N;;;;; +1F6B8;CHILDREN CROSSING;So;0;ON;;;;;N;;;;; +1F6B9;MENS SYMBOL;So;0;ON;;;;;N;;;;; +1F6BA;WOMENS SYMBOL;So;0;ON;;;;;N;;;;; +1F6BB;RESTROOM;So;0;ON;;;;;N;;;;; +1F6BC;BABY SYMBOL;So;0;ON;;;;;N;;;;; +1F6BD;TOILET;So;0;ON;;;;;N;;;;; +1F6BE;WATER CLOSET;So;0;ON;;;;;N;;;;; +1F6BF;SHOWER;So;0;ON;;;;;N;;;;; +1F6C0;BATH;So;0;ON;;;;;N;;;;; +1F6C1;BATHTUB;So;0;ON;;;;;N;;;;; +1F6C2;PASSPORT CONTROL;So;0;ON;;;;;N;;;;; +1F6C3;CUSTOMS;So;0;ON;;;;;N;;;;; +1F6C4;BAGGAGE CLAIM;So;0;ON;;;;;N;;;;; +1F6C5;LEFT LUGGAGE;So;0;ON;;;;;N;;;;; +1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; +1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; +1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; +1F703;ALCHEMICAL SYMBOL FOR EARTH;So;0;ON;;;;;N;;;;; +1F704;ALCHEMICAL SYMBOL FOR WATER;So;0;ON;;;;;N;;;;; +1F705;ALCHEMICAL SYMBOL FOR AQUAFORTIS;So;0;ON;;;;;N;;;;; +1F706;ALCHEMICAL SYMBOL FOR AQUA REGIA;So;0;ON;;;;;N;;;;; +1F707;ALCHEMICAL SYMBOL FOR AQUA REGIA-2;So;0;ON;;;;;N;;;;; +1F708;ALCHEMICAL SYMBOL FOR AQUA VITAE;So;0;ON;;;;;N;;;;; +1F709;ALCHEMICAL SYMBOL FOR AQUA VITAE-2;So;0;ON;;;;;N;;;;; +1F70A;ALCHEMICAL SYMBOL FOR VINEGAR;So;0;ON;;;;;N;;;;; +1F70B;ALCHEMICAL SYMBOL FOR VINEGAR-2;So;0;ON;;;;;N;;;;; +1F70C;ALCHEMICAL SYMBOL FOR VINEGAR-3;So;0;ON;;;;;N;;;;; +1F70D;ALCHEMICAL SYMBOL FOR SULFUR;So;0;ON;;;;;N;;;;; +1F70E;ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR;So;0;ON;;;;;N;;;;; +1F70F;ALCHEMICAL SYMBOL FOR BLACK SULFUR;So;0;ON;;;;;N;;;;; +1F710;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE;So;0;ON;;;;;N;;;;; +1F711;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2;So;0;ON;;;;;N;;;;; +1F712;ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3;So;0;ON;;;;;N;;;;; +1F713;ALCHEMICAL SYMBOL FOR CINNABAR;So;0;ON;;;;;N;;;;; +1F714;ALCHEMICAL SYMBOL FOR SALT;So;0;ON;;;;;N;;;;; +1F715;ALCHEMICAL SYMBOL FOR NITRE;So;0;ON;;;;;N;;;;; +1F716;ALCHEMICAL SYMBOL FOR VITRIOL;So;0;ON;;;;;N;;;;; +1F717;ALCHEMICAL SYMBOL FOR VITRIOL-2;So;0;ON;;;;;N;;;;; +1F718;ALCHEMICAL SYMBOL FOR ROCK SALT;So;0;ON;;;;;N;;;;; +1F719;ALCHEMICAL SYMBOL FOR ROCK SALT-2;So;0;ON;;;;;N;;;;; +1F71A;ALCHEMICAL SYMBOL FOR GOLD;So;0;ON;;;;;N;;;;; +1F71B;ALCHEMICAL SYMBOL FOR SILVER;So;0;ON;;;;;N;;;;; +1F71C;ALCHEMICAL SYMBOL FOR IRON ORE;So;0;ON;;;;;N;;;;; +1F71D;ALCHEMICAL SYMBOL FOR IRON ORE-2;So;0;ON;;;;;N;;;;; +1F71E;ALCHEMICAL SYMBOL FOR CROCUS OF IRON;So;0;ON;;;;;N;;;;; +1F71F;ALCHEMICAL SYMBOL FOR REGULUS OF IRON;So;0;ON;;;;;N;;;;; +1F720;ALCHEMICAL SYMBOL FOR COPPER ORE;So;0;ON;;;;;N;;;;; +1F721;ALCHEMICAL SYMBOL FOR IRON-COPPER ORE;So;0;ON;;;;;N;;;;; +1F722;ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER;So;0;ON;;;;;N;;;;; +1F723;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER;So;0;ON;;;;;N;;;;; +1F724;ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2;So;0;ON;;;;;N;;;;; +1F725;ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;; +1F726;ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE;So;0;ON;;;;;N;;;;; +1F727;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER;So;0;ON;;;;;N;;;;; +1F728;ALCHEMICAL SYMBOL FOR VERDIGRIS;So;0;ON;;;;;N;;;;; +1F729;ALCHEMICAL SYMBOL FOR TIN ORE;So;0;ON;;;;;N;;;;; +1F72A;ALCHEMICAL SYMBOL FOR LEAD ORE;So;0;ON;;;;;N;;;;; +1F72B;ALCHEMICAL SYMBOL FOR ANTIMONY ORE;So;0;ON;;;;;N;;;;; +1F72C;ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F72D;ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F72E;ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F72F;ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F730;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY;So;0;ON;;;;;N;;;;; +1F731;ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2;So;0;ON;;;;;N;;;;; +1F732;ALCHEMICAL SYMBOL FOR REGULUS;So;0;ON;;;;;N;;;;; +1F733;ALCHEMICAL SYMBOL FOR REGULUS-2;So;0;ON;;;;;N;;;;; +1F734;ALCHEMICAL SYMBOL FOR REGULUS-3;So;0;ON;;;;;N;;;;; +1F735;ALCHEMICAL SYMBOL FOR REGULUS-4;So;0;ON;;;;;N;;;;; +1F736;ALCHEMICAL SYMBOL FOR ALKALI;So;0;ON;;;;;N;;;;; +1F737;ALCHEMICAL SYMBOL FOR ALKALI-2;So;0;ON;;;;;N;;;;; +1F738;ALCHEMICAL SYMBOL FOR MARCASITE;So;0;ON;;;;;N;;;;; +1F739;ALCHEMICAL SYMBOL FOR SAL-AMMONIAC;So;0;ON;;;;;N;;;;; +1F73A;ALCHEMICAL SYMBOL FOR ARSENIC;So;0;ON;;;;;N;;;;; +1F73B;ALCHEMICAL SYMBOL FOR REALGAR;So;0;ON;;;;;N;;;;; +1F73C;ALCHEMICAL SYMBOL FOR REALGAR-2;So;0;ON;;;;;N;;;;; +1F73D;ALCHEMICAL SYMBOL FOR AURIPIGMENT;So;0;ON;;;;;N;;;;; +1F73E;ALCHEMICAL SYMBOL FOR BISMUTH ORE;So;0;ON;;;;;N;;;;; +1F73F;ALCHEMICAL SYMBOL FOR TARTAR;So;0;ON;;;;;N;;;;; +1F740;ALCHEMICAL SYMBOL FOR TARTAR-2;So;0;ON;;;;;N;;;;; +1F741;ALCHEMICAL SYMBOL FOR QUICK LIME;So;0;ON;;;;;N;;;;; +1F742;ALCHEMICAL SYMBOL FOR BORAX;So;0;ON;;;;;N;;;;; +1F743;ALCHEMICAL SYMBOL FOR BORAX-2;So;0;ON;;;;;N;;;;; +1F744;ALCHEMICAL SYMBOL FOR BORAX-3;So;0;ON;;;;;N;;;;; +1F745;ALCHEMICAL SYMBOL FOR ALUM;So;0;ON;;;;;N;;;;; +1F746;ALCHEMICAL SYMBOL FOR OIL;So;0;ON;;;;;N;;;;; +1F747;ALCHEMICAL SYMBOL FOR SPIRIT;So;0;ON;;;;;N;;;;; +1F748;ALCHEMICAL SYMBOL FOR TINCTURE;So;0;ON;;;;;N;;;;; +1F749;ALCHEMICAL SYMBOL FOR GUM;So;0;ON;;;;;N;;;;; +1F74A;ALCHEMICAL SYMBOL FOR WAX;So;0;ON;;;;;N;;;;; +1F74B;ALCHEMICAL SYMBOL FOR POWDER;So;0;ON;;;;;N;;;;; +1F74C;ALCHEMICAL SYMBOL FOR CALX;So;0;ON;;;;;N;;;;; +1F74D;ALCHEMICAL SYMBOL FOR TUTTY;So;0;ON;;;;;N;;;;; +1F74E;ALCHEMICAL SYMBOL FOR CAPUT MORTUUM;So;0;ON;;;;;N;;;;; +1F74F;ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE;So;0;ON;;;;;N;;;;; +1F750;ALCHEMICAL SYMBOL FOR CADUCEUS;So;0;ON;;;;;N;;;;; +1F751;ALCHEMICAL SYMBOL FOR TRIDENT;So;0;ON;;;;;N;;;;; +1F752;ALCHEMICAL SYMBOL FOR STARRED TRIDENT;So;0;ON;;;;;N;;;;; +1F753;ALCHEMICAL SYMBOL FOR LODESTONE;So;0;ON;;;;;N;;;;; +1F754;ALCHEMICAL SYMBOL FOR SOAP;So;0;ON;;;;;N;;;;; +1F755;ALCHEMICAL SYMBOL FOR URINE;So;0;ON;;;;;N;;;;; +1F756;ALCHEMICAL SYMBOL FOR HORSE DUNG;So;0;ON;;;;;N;;;;; +1F757;ALCHEMICAL SYMBOL FOR ASHES;So;0;ON;;;;;N;;;;; +1F758;ALCHEMICAL SYMBOL FOR POT ASHES;So;0;ON;;;;;N;;;;; +1F759;ALCHEMICAL SYMBOL FOR BRICK;So;0;ON;;;;;N;;;;; +1F75A;ALCHEMICAL SYMBOL FOR POWDERED BRICK;So;0;ON;;;;;N;;;;; +1F75B;ALCHEMICAL SYMBOL FOR AMALGAM;So;0;ON;;;;;N;;;;; +1F75C;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM;So;0;ON;;;;;N;;;;; +1F75D;ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2;So;0;ON;;;;;N;;;;; +1F75E;ALCHEMICAL SYMBOL FOR SUBLIMATION;So;0;ON;;;;;N;;;;; +1F75F;ALCHEMICAL SYMBOL FOR PRECIPITATE;So;0;ON;;;;;N;;;;; +1F760;ALCHEMICAL SYMBOL FOR DISTILL;So;0;ON;;;;;N;;;;; +1F761;ALCHEMICAL SYMBOL FOR DISSOLVE;So;0;ON;;;;;N;;;;; +1F762;ALCHEMICAL SYMBOL FOR DISSOLVE-2;So;0;ON;;;;;N;;;;; +1F763;ALCHEMICAL SYMBOL FOR PURIFY;So;0;ON;;;;;N;;;;; +1F764;ALCHEMICAL SYMBOL FOR PUTREFACTION;So;0;ON;;;;;N;;;;; +1F765;ALCHEMICAL SYMBOL FOR CRUCIBLE;So;0;ON;;;;;N;;;;; +1F766;ALCHEMICAL SYMBOL FOR CRUCIBLE-2;So;0;ON;;;;;N;;;;; +1F767;ALCHEMICAL SYMBOL FOR CRUCIBLE-3;So;0;ON;;;;;N;;;;; +1F768;ALCHEMICAL SYMBOL FOR CRUCIBLE-4;So;0;ON;;;;;N;;;;; +1F769;ALCHEMICAL SYMBOL FOR CRUCIBLE-5;So;0;ON;;;;;N;;;;; +1F76A;ALCHEMICAL SYMBOL FOR ALEMBIC;So;0;ON;;;;;N;;;;; +1F76B;ALCHEMICAL SYMBOL FOR BATH OF MARY;So;0;ON;;;;;N;;;;; +1F76C;ALCHEMICAL SYMBOL FOR BATH OF VAPOURS;So;0;ON;;;;;N;;;;; +1F76D;ALCHEMICAL SYMBOL FOR RETORT;So;0;ON;;;;;N;;;;; +1F76E;ALCHEMICAL SYMBOL FOR HOUR;So;0;ON;;;;;N;;;;; +1F76F;ALCHEMICAL SYMBOL FOR NIGHT;So;0;ON;;;;;N;;;;; +1F770;ALCHEMICAL SYMBOL FOR DAY-NIGHT;So;0;ON;;;;;N;;;;; +1F771;ALCHEMICAL SYMBOL FOR MONTH;So;0;ON;;;;;N;;;;; +1F772;ALCHEMICAL SYMBOL FOR HALF DRAM;So;0;ON;;;;;N;;;;; +1F773;ALCHEMICAL SYMBOL FOR HALF OUNCE;So;0;ON;;;;;N;;;;; 20000;;Lo;0;L;;;;;N;;;;; 2A6D6;;Lo;0;L;;;;;N;;;;; 2A700;;Lo;0;L;;;;;N;;;;; 2B734;;Lo;0;L;;;;;N;;;;; +2B740;;Lo;0;L;;;;;N;;;;; +2B81D;;Lo;0;L;;;;;N;;;;; 2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; 2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; 2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in index 65cbb80ee..64d49fe0b 100644 --- a/util/bash-completion.d/grub-completion.bash.in +++ b/util/bash-completion.d/grub-completion.bash.in @@ -402,7 +402,7 @@ unset __grub_mkimage_program # # grub-mkpasswd-pbkdf2 # -_grub_mkpasswd-pbkdf2 () { +_grub_mkpasswd_pbkdf2 () { local cur COMPREPLY=() @@ -417,7 +417,7 @@ _grub_mkpasswd-pbkdf2 () { } __grub_mkpasswd_pbkdf2_program=$( echo grub-mkpasswd-pbkdf2 | sed "@program_transform_name@" ) have ${__grub_mkpasswd_pbkdf2_program} && \ - complete -F _grub_mkpasswd-pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program} + complete -F _grub_mkpasswd_pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program} unset __grub_mkpasswd_pbkdf2_program @@ -462,7 +462,7 @@ unset __grub_probe_program # # grub-script-check # -_grub_script-check () { +_grub_script_check () { local cur COMPREPLY=() @@ -477,7 +477,7 @@ _grub_script-check () { } __grub_script_check_program=$( echo grub-script-check | sed "@program_transform_name@" ) have ${__grub_script_check_program} && \ - complete -F _grub_script-check -o filenames ${__grub_script_check_program} + complete -F _grub_script_check -o filenames ${__grub_script_check_program} # Local variables: diff --git a/util/bin2h.c b/util/bin2h.c index e81ede8c6..ee1c7fd32 100644 --- a/util/bin2h.c +++ b/util/bin2h.c @@ -96,7 +96,7 @@ main (int argc, char *argv[]) if (b == EOF) goto abort; - printf ("/* THIS CHUNK OF BYTES IS AUTOMATICALY GENERATED */\n" + printf ("/* THIS CHUNK OF BYTES IS AUTOMATICALLY GENERATED */\n" "unsigned char %s[] =\n{\n", sym); while (1) diff --git a/util/deviceiter.c b/util/deviceiter.c index 1cf511934..87cbc9ebc 100644 --- a/util/deviceiter.c +++ b/util/deviceiter.c @@ -1,7 +1,7 @@ /* deviceiter.c - iterate over system devices */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2011 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 @@ -286,6 +286,26 @@ get_scsi_disk_name (char *name, int unit) #endif } +#ifdef __FreeBSD_kernel__ +static void +get_ada_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/ada%d", unit); +} + +static void +get_ataraid_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/ar%d", unit); +} + +static void +get_mfi_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/mfid%d", unit); +} +#endif + #ifdef __linux__ static void get_virtio_disk_name (char *name, int unit) @@ -349,6 +369,7 @@ get_xvd_disk_name (char *name, int unit) static struct seen_device { struct seen_device *next; + struct seen_device **prev; const char *name; } *seen; @@ -485,12 +506,15 @@ compare_devices (const void *a, const void *b) { const struct device *left = (const struct device *) a; const struct device *right = (const struct device *) b; - int ret; - ret = strcmp (left->kernel, right->kernel); - if (ret) - return ret; - else - return strcmp (left->stable, right->stable); + + if (left->kernel && right->kernel) + { + int ret = strcmp (left->kernel, right->kernel); + if (ret) + return ret; + } + + return strcmp (left->stable, right->stable); } #endif /* __linux__ */ @@ -533,6 +557,10 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), necessary. */ for (entry = readdir (dir); entry; entry = readdir (dir)) { + /* Skip current and parent directory entries. */ + if (strcmp (entry->d_name, ".") == 0 || + strcmp (entry->d_name, "..") == 0) + continue; /* Skip partition entries. */ if (strstr (entry->d_name, "-part")) continue; @@ -601,7 +629,7 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), #endif /* __linux__ */ /* IDE disks. */ - for (i = 0; i < 26; i++) + for (i = 0; i < 96; i++) { char name[16]; @@ -613,6 +641,48 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), } } +#ifdef __FreeBSD_kernel__ + /* IDE disks using ATA Direct Access driver. */ + if (get_kfreebsd_version () >= 800000) + for (i = 0; i < 96; i++) + { + char name[16]; + + get_ada_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + + /* ATARAID disks. */ + for (i = 0; i < 8; i++) + { + char name[20]; + + get_ataraid_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + + /* LSI MegaRAID SAS. */ + for (i = 0; i < 32; i++) + { + char name[20]; + + get_mfi_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } +#endif + #ifdef __linux__ /* Virtio disks. */ for (i = 0; i < 26; i++) @@ -655,7 +725,7 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), #endif /* __linux__ */ /* The rest is SCSI disks. */ - for (i = 0; i < 26; i++) + for (i = 0; i < 48; i++) { char name[16]; diff --git a/util/getroot.c b/util/getroot.c new file mode 100644 index 000000000..cae7611ab --- /dev/null +++ b/util/getroot.c @@ -0,0 +1,2492 @@ +/* getroot.c - Get root device */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 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 +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include +#include + +#ifdef HAVE_DEVICE_MAPPER +# include +#endif + +#ifdef __GNU__ +#include +#include +#include +#include +#endif + +#ifdef __linux__ +# include +# include +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# include +#endif + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +# include +# include +#endif + +#ifdef __sun__ +# include +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef __linux__ +# include /* ioctl */ +# include +# ifndef MAJOR +# ifndef MINORBITS +# define MINORBITS 8 +# endif /* ! MINORBITS */ +# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS)) +# endif /* ! MAJOR */ +# ifndef FLOPPY_MAJOR +# define FLOPPY_MAJOR 2 +# endif /* ! FLOPPY_MAJOR */ +#endif + +#ifdef __CYGWIN__ +# include +# include /* BLKGETSIZE64 */ +# include /* HDIO_GETGEO */ +# define MAJOR(dev) ((unsigned) ((dev) >> 16)) +# define FLOPPY_MAJOR 2 +#endif + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# include /* DIOCGMEDIASIZE */ +# include +# include +# include +#include +# define MAJOR(dev) major(dev) +# define FLOPPY_MAJOR 2 +#endif + +#if defined (__sun__) +# include +#endif + +#if defined(__APPLE__) +# include +#endif + +#ifdef HAVE_DEVICE_MAPPER +# include +#endif + +#if defined(__NetBSD__) +# define HAVE_DIOCGDINFO +# include +# include /* struct disklabel */ +#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */ +# undef HAVE_DIOCGDINFO +#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ + +#if defined(__NetBSD__) +# ifdef HAVE_GETRAWPARTITION +# include /* getrawpartition */ +# endif /* HAVE_GETRAWPARTITION */ +# include +# ifndef FLOPPY_MAJOR +# define FLOPPY_MAJOR 2 +# endif /* ! FLOPPY_MAJOR */ +# ifndef RAW_FLOPPY_MAJOR +# define RAW_FLOPPY_MAJOR 9 +# endif /* ! RAW_FLOPPY_MAJOR */ +#endif /* defined(__NetBSD__) */ + +static void +strip_extra_slashes (char *dir) +{ + char *p = dir; + + while ((p = strchr (p, '/')) != 0) + { + if (p[1] == '/') + { + memmove (p, p + 1, strlen (p)); + continue; + } + else if (p[1] == '\0') + { + if (p > dir) + p[0] = '\0'; + break; + } + + p++; + } +} + +static char * +xgetcwd (void) +{ + size_t size = 10; + char *path; + + path = xmalloc (size); + while (! getcwd (path, size)) + { + size <<= 1; + path = xrealloc (path, size); + } + + return path; +} + +#ifdef __linux__ + +#define ESCAPED_PATH_MAX (4 * PATH_MAX) +struct mountinfo_entry +{ + int id; + int major, minor; + char enc_root[ESCAPED_PATH_MAX + 1], enc_path[ESCAPED_PATH_MAX + 1]; + char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1]; +}; + +/* Statting something on a btrfs filesystem always returns a virtual device + major/minor pair rather than the real underlying device, because btrfs + can span multiple underlying devices (and even if it's currently only + using a single device it can be dynamically extended onto another). We + can't deal with the multiple-device case yet, but in the meantime, we can + at least cope with the single-device case by scanning + /proc/self/mountinfo. */ +static void +unescape (char *str) +{ + char *optr; + const char *iptr; + for (iptr = optr = str; *iptr; optr++) + { + if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8' + && iptr[2] >= '0' && iptr[2] < '8' + && iptr[3] >= '0' && iptr[3] < '8') + { + *optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3) + | (iptr[3] - '0')); + iptr += 4; + } + else + *optr = *iptr++; + } + *optr = 0; +} + +char * +grub_find_root_device_from_mountinfo (const char *dir, char **relroot) +{ + FILE *fp; + char *buf = NULL; + size_t len = 0; + char *ret = NULL; + int entry_len = 0, entry_max = 4; + struct mountinfo_entry *entries; + struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" }; + int i; + + if (! *dir) + dir = "/"; + if (relroot) + *relroot = NULL; + + fp = fopen ("/proc/self/mountinfo", "r"); + if (! fp) + return NULL; /* fall through to other methods */ + + entries = xmalloc (entry_max * sizeof (*entries)); + + /* First, build a list of relevant visible mounts. */ + while (getline (&buf, &len, fp) > 0) + { + struct mountinfo_entry entry; + int count; + size_t enc_path_len; + const char *sep; + + if (sscanf (buf, "%d %d %u:%u %s %s%n", + &entry.id, &parent_entry.id, &entry.major, &entry.minor, + entry.enc_root, entry.enc_path, &count) < 6) + continue; + + unescape (entry.enc_root); + unescape (entry.enc_path); + + enc_path_len = strlen (entry.enc_path); + /* Check that enc_path is a prefix of dir. The prefix must either be + the entire string, or end with a slash, or be immediately followed + by a slash. */ + if (strncmp (dir, entry.enc_path, enc_path_len) != 0 || + (enc_path_len && dir[enc_path_len - 1] != '/' && + dir[enc_path_len] && dir[enc_path_len] != '/')) + continue; + + sep = strstr (buf + count, " - "); + if (!sep) + continue; + + sep += sizeof (" - ") - 1; + if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2) + continue; + + /* Using the mount IDs, find out where this fits in the list of + visible mount entries we've seen so far. There are three + interesting cases. Firstly, it may be inserted at the end: this is + the usual case of /foo/bar being mounted after /foo. Secondly, it + may be inserted at the start: for example, this can happen for + filesystems that are mounted before / and later moved under it. + Thirdly, it may occlude part or all of the existing filesystem + tree, in which case the end of the list needs to be pruned and this + new entry will be inserted at the end. */ + if (entry_len >= entry_max) + { + entry_max <<= 1; + entries = xrealloc (entries, entry_max * sizeof (*entries)); + } + + if (!entry_len) + { + /* Initialise list. */ + entry_len = 2; + entries[0] = parent_entry; + entries[1] = entry; + } + else + { + for (i = entry_len - 1; i >= 0; i--) + { + if (entries[i].id == parent_entry.id) + { + /* Insert at end, pruning anything previously above this. */ + entry_len = i + 2; + entries[i + 1] = entry; + break; + } + else if (i == 0 && entries[i].id == entry.id) + { + /* Insert at start. */ + entry_len++; + memmove (entries + 1, entries, + (entry_len - 1) * sizeof (*entries)); + entries[0] = parent_entry; + entries[1] = entry; + break; + } + } + } + } + + /* Now scan visible mounts for the ones we're interested in. */ + for (i = entry_len - 1; i >= 0; i--) + { + if (!*entries[i].device) + continue; + + ret = strdup (entries[i].device); + if (relroot) + *relroot = strdup (entries[i].enc_root); + break; + } + + free (buf); + free (entries); + fclose (fp); + return ret; +} + +#endif /* __linux__ */ + +static char * +find_root_device_from_libzfs (const char *dir) +{ + char *device = NULL; + char *poolname; + char *poolfs; + + grub_find_zpool_from_dir (dir, &poolname, &poolfs); + if (! poolname) + return NULL; + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + { + zpool_handle_t *zpool; + libzfs_handle_t *libzfs; + nvlist_t *config, *vdev_tree; + nvlist_t **children, **path; + unsigned int nvlist_count; + unsigned int i; + + libzfs = grub_get_libzfs_handle (); + if (! libzfs) + return NULL; + + zpool = zpool_open (libzfs, poolname); + config = zpool_get_config (zpool, NULL); + + if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0) + error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); + + if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0) + error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); + assert (nvlist_count > 0); + + while (nvlist_lookup_nvlist_array (children[0], "children", + &children, &nvlist_count) == 0) + assert (nvlist_count > 0); + + for (i = 0; i < nvlist_count; i++) + { + if (nvlist_lookup_string (children[i], "path", &device) != 0) + error (1, errno, "nvlist_lookup_string (\"path\")"); + + struct stat st; + if (stat (device, &st) == 0) + { +#ifdef __sun__ + if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1) + == 0) + device = xasprintf ("/dev/rdsk/%s", + device + sizeof ("/dev/dsk/") - 1); + else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1) + == 0 + && grub_memcmp (device + strlen (device) - 4, + ",raw", 4) != 0) + device = xasprintf ("%s,raw", device); + else +#endif + device = xstrdup (device); + break; + } + + device = NULL; + } + + zpool_close (zpool); + } +#else + { + char *cmd; + FILE *fp; + int ret; + char *line; + size_t len; + int st; + + char name[PATH_MAX + 1], state[257], readlen[257], writelen[257]; + char cksum[257], notes[257]; + unsigned int dummy; + + cmd = xasprintf ("zpool status %s", poolname); + fp = popen (cmd, "r"); + free (cmd); + + st = 0; + while (st < 3) + { + line = NULL; + ret = getline (&line, &len, fp); + if (ret == -1) + goto fail; + + if (sscanf (line, " %s %256s %256s %256s %256s %256s", + name, state, readlen, writelen, cksum, notes) >= 5) + switch (st) + { + case 0: + if (!strcmp (name, "NAME") + && !strcmp (state, "STATE") + && !strcmp (readlen, "READ") + && !strcmp (writelen, "WRITE") + && !strcmp (cksum, "CKSUM")) + st++; + break; + case 1: + if (!strcmp (name, poolname)) + st++; + break; + case 2: + if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy) + && !sscanf (name, "raidz%u", &dummy) + && !strcmp (state, "ONLINE")) + st++; + break; + } + + free (line); + } + device = xasprintf ("/dev/%s", name); + + fail: + pclose (fp); + } +#endif + + free (poolname); + if (poolfs) + free (poolfs); + + return device; +} + +#ifdef __MINGW32__ + +char * +grub_find_device (const char *dir __attribute__ ((unused)), + dev_t dev __attribute__ ((unused))) +{ + return 0; +} + +#elif ! defined(__CYGWIN__) + +char * +grub_find_device (const char *dir, dev_t dev) +{ + DIR *dp; + char *saved_cwd; + struct dirent *ent; + + if (! dir) + { +#ifdef __CYGWIN__ + return NULL; +#else + dir = "/dev"; +#endif + } + + dp = opendir (dir); + if (! dp) + return 0; + + saved_cwd = xgetcwd (); + + grub_util_info ("changing current directory to %s", dir); + if (chdir (dir) < 0) + { + free (saved_cwd); + closedir (dp); + return 0; + } + + while ((ent = readdir (dp)) != 0) + { + struct stat st; + + /* Avoid: + - dotfiles (like "/dev/.tmp.md0") since they could be duplicates. + - dotdirs (like "/dev/.static") since they could contain duplicates. */ + if (ent->d_name[0] == '.') + continue; + + if (lstat (ent->d_name, &st) < 0) + /* Ignore any error. */ + continue; + + if (S_ISLNK (st.st_mode)) { +#ifdef __linux__ + if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) { + /* Follow symbolic links under /dev/mapper/; the canonical name + may be something like /dev/dm-0, but the names under + /dev/mapper/ are more human-readable and so we prefer them if + we can get them. */ + if (stat (ent->d_name, &st) < 0) + continue; + } else +#endif /* __linux__ */ + /* Don't follow other symbolic links. */ + continue; + } + + if (S_ISDIR (st.st_mode)) + { + /* Find it recursively. */ + char *res; + + res = grub_find_device (ent->d_name, dev); + + if (res) + { + if (chdir (saved_cwd) < 0) + grub_util_error ("cannot restore the original directory"); + + free (saved_cwd); + closedir (dp); + return res; + } + } + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) + if (S_ISCHR (st.st_mode) && st.st_rdev == dev) +#else + if (S_ISBLK (st.st_mode) && st.st_rdev == dev) +#endif + { +#ifdef __linux__ + /* Skip device names like /dev/dm-0, which are short-hand aliases + to more descriptive device names, e.g. those under /dev/mapper */ + if (ent->d_name[0] == 'd' && + ent->d_name[1] == 'm' && + ent->d_name[2] == '-' && + ent->d_name[3] >= '0' && + ent->d_name[3] <= '9') + continue; +#endif + + /* Found! */ + char *res; + char *cwd; +#if defined(__NetBSD__) + /* Convert this block device to its character (raw) device. */ + const char *template = "%s/r%s"; +#else + /* Keep the device name as it is. */ + const char *template = "%s/%s"; +#endif + + cwd = xgetcwd (); + res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3); + sprintf (res, template, cwd, ent->d_name); + strip_extra_slashes (res); + free (cwd); + + /* /dev/root is not a real block device keep looking, takes care + of situation where root filesystem is on the same partition as + grub files */ + + if (strcmp(res, "/dev/root") == 0) + continue; + + if (chdir (saved_cwd) < 0) + grub_util_error (_("cannot restore the original directory")); + + free (saved_cwd); + closedir (dp); + return res; + } + } + + if (chdir (saved_cwd) < 0) + grub_util_error (_("cannot restore the original directory")); + + free (saved_cwd); + closedir (dp); + return 0; +} + +#else /* __CYGWIN__ */ + +/* Read drive/partition serial number from mbr/boot sector, + return 0 on read error, ~0 on unknown serial. */ +static unsigned +get_bootsec_serial (const char *os_dev, int mbr) +{ + /* Read boot sector. */ + int fd = open (os_dev, O_RDONLY); + if (fd < 0) + return 0; + unsigned char buf[0x200]; + int n = read (fd, buf, sizeof (buf)); + close (fd); + if (n != sizeof(buf)) + return 0; + + /* Check signature. */ + if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa)) + return ~0; + + /* Serial number offset depends on boot sector type. */ + if (mbr) + n = 0x1b8; + else if (memcmp (buf + 0x03, "NTFS", 4) == 0) + n = 0x048; + else if (memcmp (buf + 0x52, "FAT32", 5) == 0) + n = 0x043; + else if (memcmp (buf + 0x36, "FAT", 3) == 0) + n = 0x027; + else + return ~0; + + unsigned serial = *(unsigned *)(buf + n); + if (serial == 0) + return ~0; + return serial; +} + +char * +grub_find_device (const char *path, dev_t dev) +{ + /* No root device for /cygdrive. */ + if (dev == (DEV_CYGDRIVE_MAJOR << 16)) + return 0; + + /* Convert to full POSIX and Win32 path. */ + char fullpath[PATH_MAX], winpath[PATH_MAX]; + cygwin_conv_to_full_posix_path (path, fullpath); + cygwin_conv_to_full_win32_path (fullpath, winpath); + + /* If identical, this is no real filesystem path. */ + if (strcmp (fullpath, winpath) == 0) + return 0; + + /* Check for floppy drive letter. */ + if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0])) + return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1"); + + /* Cygwin returns the partition serial number in stat.st_dev. + This is never identical to the device number of the emulated + /dev/sdXN device, so above grub_find_device () does not work. + Search the partition with the same serial in boot sector instead. */ + char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */ + int d; + for (d = 'a'; d <= 'z'; d++) + { + sprintf (devpath, "/dev/sd%c", d); + if (get_bootsec_serial (devpath, 1) == 0) + continue; + int p; + for (p = 1; p <= 15; p++) + { + sprintf (devpath, "/dev/sd%c%d", d, p); + unsigned ser = get_bootsec_serial (devpath, 0); + if (ser == 0) + break; + if (ser != (unsigned)~0 && dev == (dev_t)ser) + return xstrdup (devpath); + } + } + return 0; +} + +#endif /* __CYGWIN__ */ + +char * +grub_guess_root_device (const char *dir) +{ + char *os_dev = NULL; +#ifdef __GNU__ + file_t file; + mach_port_t *ports; + int *ints; + loff_t *offsets; + char *data; + error_t err; + mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0; + size_t name_len; + + file = file_name_lookup (dir, 0, 0); + if (file == MACH_PORT_NULL) + return 0; + + err = file_get_storage_info (file, + &ports, &num_ports, + &ints, &num_ints, + &offsets, &num_offsets, + &data, &data_len); + + if (num_ints < 1) + grub_util_error (_("Storage info for `%s' does not include type"), dir); + if (ints[0] != STORAGE_DEVICE) + grub_util_error (_("Filesystem of `%s' is not stored on local disk"), dir); + + if (num_ints < 5) + grub_util_error (_("Storage info for `%s' does not include name"), dir); + name_len = ints[4]; + if (name_len < data_len) + grub_util_error (_("Bogus name length for storage info for `%s'"), dir); + if (data[name_len - 1] != '\0') + grub_util_error (_("Storage name for `%s' not NUL-terminated"), dir); + + os_dev = xmalloc (strlen ("/dev/") + data_len); + memcpy (os_dev, "/dev/", strlen ("/dev/")); + memcpy (os_dev + strlen ("/dev/"), data, data_len); + + if (ports && num_ports > 0) + { + mach_msg_type_number_t i; + for (i = 0; i < num_ports; i++) + { + mach_port_t port = ports[i]; + if (port != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self(), port); + } + munmap ((caddr_t) ports, num_ports * sizeof (*ports)); + } + + if (ints && num_ints > 0) + munmap ((caddr_t) ints, num_ints * sizeof (*ints)); + if (offsets && num_offsets > 0) + munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets)); + if (data && data_len > 0) + munmap (data, data_len); + mach_port_deallocate (mach_task_self (), file); +#else /* !__GNU__ */ + struct stat st; + dev_t dev; + +#ifdef __linux__ + if (!os_dev) + os_dev = grub_find_root_device_from_mountinfo (dir, NULL); +#endif /* __linux__ */ + + if (!os_dev) + os_dev = find_root_device_from_libzfs (dir); + + if (os_dev) + { + char *tmp = os_dev; + os_dev = canonicalize_file_name (os_dev); + free (tmp); + } + + if (os_dev) + { + int dm = (strncmp (os_dev, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0); + int root = (strcmp (os_dev, "/dev/root") == 0); + if (!dm && !root) + return os_dev; + if (stat (os_dev, &st) >= 0) + { + free (os_dev); + dev = st.st_rdev; + return grub_find_device (dm ? "/dev/mapper" : "/dev", dev); + } + free (os_dev); + } + + if (stat (dir, &st) < 0) + grub_util_error (_("cannot stat `%s'"), dir); + + dev = st.st_dev; + +#ifdef __CYGWIN__ + /* Cygwin specific function. */ + os_dev = grub_find_device (dir, dev); + +#else + + /* This might be truly slow, but is there any better way? */ + os_dev = grub_find_device ("/dev", dev); +#endif +#endif /* !__GNU__ */ + + return os_dev; +} + +#ifdef HAVE_DEVICE_MAPPER + +static int +grub_util_open_dm (const char *os_dev, struct dm_tree **tree, + struct dm_tree_node **node) +{ + uint32_t maj, min; + struct stat st; + + *node = NULL; + *tree = NULL; + + if ((strncmp ("/dev/mapper/", os_dev, 12) != 0)) + return 0; + + if (stat (os_dev, &st) < 0) + return 0; + + *tree = dm_tree_create (); + if (! *tree) + { + grub_puts_ (N_("Failed to create tree")); + grub_dprintf ("hostdisk", "dm_tree_create failed\n"); + return 0; + } + + maj = major (st.st_rdev); + min = minor (st.st_rdev); + + if (! dm_tree_add_dev (*tree, maj, min)) + { + grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n"); + dm_tree_free (*tree); + *tree = NULL; + return 0; + } + + *node = dm_tree_find_node (*tree, maj, min); + if (! *node) + { + grub_dprintf ("hostdisk", "dm_tree_find_node failed\n"); + dm_tree_free (*tree); + *tree = NULL; + return 0; + } + return 1; +} + +#endif + +static char * +get_dm_uuid (const char *os_dev) +{ + if ((strncmp ("/dev/mapper/", os_dev, 12) != 0)) + return NULL; + +#ifdef HAVE_DEVICE_MAPPER + { + struct dm_tree *tree; + struct dm_tree_node *node; + const char *node_uuid; + char *ret; + + if (!grub_util_open_dm (os_dev, &tree, &node)) + return NULL; + + node_uuid = dm_tree_node_get_uuid (node); + if (! node_uuid) + { + grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev); + dm_tree_free (tree); + return NULL; + } + + ret = grub_strdup (node_uuid); + + dm_tree_free (tree); + + return ret; + } +#endif + + return NULL; +} + +static enum grub_dev_abstraction_types +grub_util_get_dm_abstraction (const char *os_dev) +{ +#ifdef HAVE_DEVICE_MAPPER + char *uuid; + + uuid = get_dm_uuid (os_dev); + + if (uuid == NULL) + return GRUB_DEV_ABSTRACTION_NONE; + + if (strncmp (uuid, "LVM-", 4) == 0) + { + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_LVM; + } + if (strncmp (uuid, "CRYPT-LUKS1-", 4) == 0) + { + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_LUKS; + } + + grub_free (uuid); + return GRUB_DEV_ABSTRACTION_NONE; +#else + if ((strncmp ("/dev/mapper/", os_dev, 12) != 0)) + return GRUB_DEV_ABSTRACTION_NONE; + return GRUB_DEV_ABSTRACTION_LVM; +#endif +} + +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) +#include + +static const char * +grub_util_get_geom_abstraction (const char *dev) +{ + char *whole; + struct gmesh mesh; + struct gclass *class; + const char *name; + int error; + + if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0) + return 0; + name = dev + sizeof ("/dev/") - 1; + grub_util_follow_gpart_up (name, NULL, &whole); + + grub_util_info ("following geom '%s'", name); + + error = geom_gettree (&mesh); + if (error != 0) + grub_util_error (_("couldn't open geom")); + + LIST_FOREACH (class, &mesh.lg_class, lg_class) + { + struct ggeom *geom; + LIST_FOREACH (geom, &class->lg_geom, lg_geom) + { + struct gprovider *provider; + LIST_FOREACH (provider, &geom->lg_provider, lg_provider) + if (strcmp (provider->lg_name, name) == 0) + return class->lg_name; + } + } + return NULL; +} +#endif + +int +grub_util_get_dev_abstraction (const char *os_dev) +{ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + /* User explicitly claims that this drive is visible by BIOS. */ + if (grub_util_biosdisk_is_present (os_dev)) + return GRUB_DEV_ABSTRACTION_NONE; +#endif + +#ifdef __linux__ + enum grub_dev_abstraction_types ret; + + /* Check for LVM and LUKS. */ + ret = grub_util_get_dm_abstraction (os_dev); + + if (ret != GRUB_DEV_ABSTRACTION_NONE) + return ret; + + /* Check for RAID. */ + if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)) + return GRUB_DEV_ABSTRACTION_RAID; +#endif + +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) + const char *abs; + abs = grub_util_get_geom_abstraction (os_dev); + grub_util_info ("abstraction of %s is %s", os_dev, abs); + if (abs && grub_strcasecmp (abs, "eli") == 0) + return GRUB_DEV_ABSTRACTION_GELI; + + /* Check for LVM. */ + if (!strncmp (os_dev, LVM_DEV_MAPPER_STRING, sizeof(LVM_DEV_MAPPER_STRING)-1)) + return GRUB_DEV_ABSTRACTION_LVM; +#endif + + /* No abstraction found. */ + return GRUB_DEV_ABSTRACTION_NONE; +} + +#ifdef __linux__ +static char * +get_mdadm_uuid (const char *os_dev) +{ + int mdadm_pipe[2]; + pid_t mdadm_pid; + char *name = NULL; + + if (pipe (mdadm_pipe) < 0) + { + grub_util_warn (_("Unable to create pipe for mdadm: %s"), + strerror (errno)); + return NULL; + } + + mdadm_pid = fork (); + if (mdadm_pid < 0) + grub_util_warn (_("Unable to fork mdadm: %s"), strerror (errno)); + else if (mdadm_pid == 0) + { + /* Child. */ + char *argv[5]; + + close (mdadm_pipe[0]); + dup2 (mdadm_pipe[1], STDOUT_FILENO); + close (mdadm_pipe[1]); + + /* execvp has inconvenient types, hence the casts. None of these + strings will actually be modified. */ + argv[0] = (char *) "mdadm"; + argv[1] = (char *) "--detail"; + argv[2] = (char *) "--export"; + argv[3] = (char *) os_dev; + argv[4] = NULL; + execvp ("mdadm", argv); + exit (127); + } + else + { + /* Parent. Read mdadm's output. */ + FILE *mdadm; + char *buf = NULL; + size_t len = 0; + + close (mdadm_pipe[1]); + mdadm = fdopen (mdadm_pipe[0], "r"); + if (! mdadm) + { + grub_util_warn (_("Unable to open stream from mdadm: %s"), + strerror (errno)); + goto out; + } + + while (getline (&buf, &len, mdadm) > 0) + { + if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0) + { + char *name_start, *ptri, *ptro; + size_t name_len; + + free (name); + name_start = buf + sizeof ("MD_UUID=") - 1; + ptro = name = xmalloc (strlen (name_start) + 1); + for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r'; + ptri++) + if ((*ptri >= '0' && *ptri <= '9') + || (*ptri >= 'a' && *ptri <= 'f') + || (*ptri >= 'A' && *ptri <= 'F')) + *ptro++ = *ptri; + *ptro = 0; + } + } + +out: + close (mdadm_pipe[0]); + waitpid (mdadm_pid, NULL, 0); + } + + return name; +} +#endif /* __linux__ */ + +void +grub_util_pull_device (const char *os_dev) +{ + int ab; + ab = grub_util_get_dev_abstraction (os_dev); + switch (ab) + { + case GRUB_DEV_ABSTRACTION_GELI: +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) + { + char *whole; + struct gmesh mesh; + struct gclass *class; + const char *name; + int error; + char *lastsubdev = NULL; + + if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0) + return; + name = os_dev + sizeof ("/dev/") - 1; + grub_util_follow_gpart_up (name, NULL, &whole); + + grub_util_info ("following geom '%s'", name); + + error = geom_gettree (&mesh); + if (error != 0) + grub_util_error (_("couldn't open geom")); + + LIST_FOREACH (class, &mesh.lg_class, lg_class) + { + struct ggeom *geom; + LIST_FOREACH (geom, &class->lg_geom, lg_geom) + { + struct gprovider *provider; + LIST_FOREACH (provider, &geom->lg_provider, lg_provider) + if (strcmp (provider->lg_name, name) == 0) + { + struct gconsumer *consumer; + char *fname; + char *uuid; + + LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer) + break; + if (!consumer) + grub_util_error (_("couldn't find geli consumer")); + fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name); + grub_util_info ("consumer %s", consumer->lg_provider->lg_name); + lastsubdev = consumer->lg_provider->lg_name; + grub_util_pull_device (fname); + free (fname); + } + } + } + if (ab == GRUB_DEV_ABSTRACTION_GELI && lastsubdev) + { + char *fname = xasprintf ("/dev/%s", lastsubdev); + char *grdev = grub_util_get_grub_dev (fname); + free (fname); + + if (grdev) + { + grub_err_t err; + err = grub_cryptodisk_cheat_mount (grdev, os_dev); + if (err) + grub_util_error (_("Can't mount crypto: %s"), _(grub_errmsg)); + } + + grub_free (grdev); + } + } +#endif + break; + + case GRUB_DEV_ABSTRACTION_LVM: + case GRUB_DEV_ABSTRACTION_LUKS: +#ifdef HAVE_DEVICE_MAPPER + { + struct dm_tree *tree; + struct dm_tree_node *node; + struct dm_tree_node *child; + void *handle = NULL; + char *lastsubdev = NULL; + + if (!grub_util_open_dm (os_dev, &tree, &node)) + return; + + while ((child = dm_tree_next_child (&handle, node, 0))) + { + const struct dm_info *dm = dm_tree_node_get_info (child); + char *subdev; + if (!dm) + continue; + subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor)); + if (subdev) + { + lastsubdev = subdev; + grub_util_pull_device (subdev); + } + } + if (ab == GRUB_DEV_ABSTRACTION_LUKS && lastsubdev) + { + char *grdev = grub_util_get_grub_dev (lastsubdev); + dm_tree_free (tree); + if (grdev) + { + grub_err_t err; + err = grub_cryptodisk_cheat_mount (grdev, os_dev); + if (err) + grub_util_error (_("Can't mount crypto: %s"), _(grub_errmsg)); + } + grub_free (grdev); + } + else + dm_tree_free (tree); + } +#endif + return; + case GRUB_DEV_ABSTRACTION_RAID: +#ifdef __linux__ + { + char **devicelist = grub_util_raid_getmembers (os_dev, 0); + int i; + for (i = 0; devicelist[i];i++) + grub_util_pull_device (devicelist[i]); + free (devicelist); + } +#endif + return; + + default: /* GRUB_DEV_ABSTRACTION_NONE */ + free (grub_util_biosdisk_get_grub_dev (os_dev)); + return; + } +} + +#ifdef HAVE_DEVICE_MAPPER +static int +grub_util_get_dm_node_linear_info (const char *dev, + int *maj, int *min) +{ + struct dm_task *dmt; + void *next = NULL; + uint64_t length, start; + char *target, *params; + char *ptr; + int major, minor; + + dmt = dm_task_create(DM_DEVICE_TABLE); + if (!dmt) + return 0; + + if (!dm_task_set_name(dmt, dev)) + { + dm_task_destroy (dmt); + return 0; + } + dm_task_no_open_count(dmt); + if (!dm_task_run(dmt)) + { + dm_task_destroy (dmt); + return 0; + } + next = dm_get_next_target(dmt, next, &start, &length, + &target, ¶ms); + if (grub_strcmp (target, "linear") != 0) + { + dm_task_destroy (dmt); + return 0; + } + major = grub_strtoul (params, &ptr, 10); + if (grub_errno) + { + dm_task_destroy (dmt); + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (*ptr != ':') + { + dm_task_destroy (dmt); + return 0; + } + ptr++; + minor = grub_strtoul (ptr, 0, 10); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; + dm_task_destroy (dmt); + return 0; + } + if (maj) + *maj = major; + if (min) + *min = minor; + dm_task_destroy (dmt); + return 1; +} +#endif + +int +grub_util_biosdisk_is_floppy (grub_disk_t disk) +{ + struct stat st; + int fd; + const char *dname; + + dname = grub_util_biosdisk_get_osdev (disk); + + if (!dname) + return 0; + + fd = open (dname, O_RDONLY); + /* Shouldn't happen. */ + if (fd == -1) + return 0; + + /* Shouldn't happen either. */ + if (fstat (fd, &st) < 0) + { + close (fd); + return 0; + } + + close (fd); + +#if defined(__NetBSD__) + if (major(st.st_rdev) == RAW_FLOPPY_MAJOR) + return 1; +#endif + +#if defined(FLOPPY_MAJOR) + if (major(st.st_rdev) == FLOPPY_MAJOR) +#else + /* Some kernels (e.g. kFreeBSD) don't have a static major number + for floppies, but they still use a "fd[0-9]" pathname. */ + if (map[disk->id].device[5] == 'f' + && map[disk->id].device[6] == 'd' + && map[disk->id].device[7] >= '0' + && map[disk->id].device[7] <= '9') +#endif + return 1; + + return 0; +} + +static char * +convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) +{ +#if defined(__linux__) + char *path = xmalloc (PATH_MAX); + if (! realpath (os_dev, path)) + return NULL; + + if (strncmp ("/dev/", path, 5) == 0) + { + char *p = path + 5; + + /* If this is an IDE disk. */ + if (strncmp ("ide/", p, 4) == 0) + { + p = strstr (p, "part"); + if (p) + strcpy (p, "disc"); + + return path; + } + + /* If this is a SCSI disk. */ + if (strncmp ("scsi/", p, 5) == 0) + { + p = strstr (p, "part"); + if (p) + strcpy (p, "disc"); + + return path; + } + + /* If this is a DAC960 disk. */ + if (strncmp ("rd/c", p, 4) == 0) + { + /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is a Mylex AcceleRAID Array. */ + if (strncmp ("rs/c", p, 4) == 0) + { + /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + /* If this is a CCISS disk. */ + if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0) + { + /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is a Compaq Intelligent Drive Array. */ + if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0) + { + /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + /* If this is an I2O disk. */ + if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0) + { + /* /dev/i2o/hd[a-z]([0-9]+)? */ + p[sizeof ("i2o/hda") - 1] = '\0'; + return path; + } + + /* If this is a MultiMediaCard (MMC). */ + if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0) + { + /* /dev/mmcblk[0-9]+(p[0-9]+)? */ + p = strchr (p, 'p'); + if (p) + *p = '\0'; + + return path; + } + + if (strncmp ("md", p, 2) == 0 + && p[2] >= '0' && p[2] <= '9') + { + char *ptr = p + 2; + while (*ptr >= '0' && *ptr <= '9') + ptr++; + *ptr = 0; + return path; + } + + /* If this is an IDE, SCSI or Virtio disk. */ + if (strncmp ("vdisk", p, 5) == 0 + && p[5] >= 'a' && p[5] <= 'z') + { + /* /dev/vdisk[a-z][0-9]* */ + p[6] = '\0'; + return path; + } + if ((strncmp ("hd", p, 2) == 0 + || strncmp ("vd", p, 2) == 0 + || strncmp ("sd", p, 2) == 0) + && p[2] >= 'a' && p[2] <= 'z') + { + char *pp = p + 2; + while (*pp >= 'a' && *pp <= 'z') + pp++; + /* /dev/[hsv]d[a-z]+[0-9]* */ + *pp = '\0'; + return path; + } + + /* If this is a Xen virtual block device. */ + if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z') + { + char *pp = p + 3; + while (*pp >= 'a' && *pp <= 'z') + pp++; + /* /dev/xvd[a-z]+[0-9]* */ + *pp = '\0'; + return path; + } + +#ifdef HAVE_DEVICE_MAPPER + /* If this is a DM-RAID device. + Compare os_dev rather than path here, since nodes under + /dev/mapper/ are often symlinks. */ + if ((strncmp ("/dev/mapper/", os_dev, 12) == 0)) + { + struct dm_tree *tree; + uint32_t maj, min; + struct dm_tree_node *node = NULL, *child; + void *handle; + const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name; + + tree = dm_tree_create (); + if (! tree) + { + grub_dprintf ("hostdisk", "dm_tree_create failed\n"); + goto devmapper_out; + } + + maj = major (st->st_rdev); + min = minor (st->st_rdev); + if (! dm_tree_add_dev (tree, maj, min)) + { + grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n"); + goto devmapper_out; + } + + node = dm_tree_find_node (tree, maj, min); + if (! node) + { + grub_dprintf ("hostdisk", "dm_tree_find_node failed\n"); + goto devmapper_out; + } + node_uuid = dm_tree_node_get_uuid (node); + if (! node_uuid) + { + grub_dprintf ("hostdisk", "%s has no DM uuid\n", path); + node = NULL; + goto devmapper_out; + } + if (strncmp (node_uuid, "LVM-", 4) == 0) + { + grub_dprintf ("hostdisk", "%s is an LVM\n", path); + node = NULL; + goto devmapper_out; + } + if (strncmp (node_uuid, "mpath-", 6) == 0) + { + /* Multipath partitions have partN-mpath-* UUIDs, and are + linear mappings so are handled by + grub_util_get_dm_node_linear_info. Multipath disks are not + linear mappings and must be handled specially. */ + grub_dprintf ("hostdisk", "%s is a multipath disk\n", path); + mapper_name = dm_tree_node_get_name (node); + goto devmapper_out; + } + if (strncmp (node_uuid, "DMRAID-", 7) != 0) + { + int major, minor; + const char *node_name; + grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path); + + if ((node_name = dm_tree_node_get_name (node)) + && grub_util_get_dm_node_linear_info (node_name, + &major, &minor)) + { + if (tree) + dm_tree_free (tree); + free (path); + char *ret = grub_find_device ("/dev", + (major << 8) | minor); + return ret; + } + + node = NULL; + goto devmapper_out; + } + + handle = NULL; + /* Counter-intuitively, device-mapper refers to the disk-like + device containing a DM-RAID partition device as a "child" of + the partition device. */ + child = dm_tree_next_child (&handle, node, 0); + if (! child) + { + grub_dprintf ("hostdisk", "%s has no DM children\n", path); + goto devmapper_out; + } + child_uuid = dm_tree_node_get_uuid (child); + if (! child_uuid) + { + grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path); + goto devmapper_out; + } + else if (strncmp (child_uuid, "DMRAID-", 7) != 0) + { + grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path); + goto devmapper_out; + } + child_name = dm_tree_node_get_name (child); + if (! child_name) + { + grub_dprintf ("hostdisk", "%s child has no DM name\n", path); + goto devmapper_out; + } + mapper_name = child_name; + +devmapper_out: + if (! mapper_name && node) + { + /* This is a DM-RAID disk, not a partition. */ + mapper_name = dm_tree_node_get_name (node); + if (! mapper_name) + grub_dprintf ("hostdisk", "%s has no DM name\n", path); + } + if (tree) + dm_tree_free (tree); + free (path); + if (mapper_name) + return xasprintf ("/dev/mapper/%s", mapper_name); + else + return NULL; + } +#endif /* HAVE_DEVICE_MAPPER */ + } + + return path; + +#elif defined(__GNU__) + char *path = xstrdup (os_dev); + if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0) + { + char *p = strchr (path + 7, 's'); + if (p) + *p = '\0'; + } + return path; + +#elif defined(__CYGWIN__) + char *path = xstrdup (os_dev); + if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z') + path[8] = 0; + return path; + +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + char *out, *out2; + if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0) + return xstrdup (os_dev); + grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out); + + out2 = xasprintf ("/dev/%s", out); + free (out); + + return out2; +#elif defined(__APPLE__) + char *path = xstrdup (os_dev); + if (strncmp ("/dev/", path, 5) == 0) + { + char *p; + for (p = path + 5; *p; ++p) + if (grub_isdigit(*p)) + { + p = strpbrk (p, "sp"); + if (p) + *p = '\0'; + break; + } + } + return path; + +#elif defined(__NetBSD__) + /* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */ + char *path = xstrdup (os_dev); + if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 && + (path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') && + strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */ + { + char *p; + for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++); + if (grub_isdigit(*p)) + { + p++; + if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0')) + { + /* path matches the required regular expression and + p points to its last character. */ + int rawpart = -1; +# ifdef HAVE_GETRAWPARTITION + rawpart = getrawpartition(); +# endif /* HAVE_GETRAWPARTITION */ + if (rawpart >= 0) + *p = 'a' + rawpart; + } + } + } + return path; + +#elif defined (__sun__) + char *colon = grub_strrchr (os_dev, ':'); + if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0 + && colon) + { + char *ret = xmalloc (colon - os_dev + sizeof (":q,raw")); + grub_memcpy (ret, os_dev, colon - os_dev); + grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw")); + return ret; + } + else + return xstrdup (os_dev); +#else +# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly." + return xstrdup (os_dev); +#endif +} + +static const char * +find_system_device (const char *os_dev, struct stat *st, int convert, int add) +{ + unsigned int i; + char *os_disk; + const char *drive; + + if (convert) + os_disk = convert_system_partition_to_system_disk (os_dev, st); + else + os_disk = xstrdup (os_dev); + if (! os_disk) + return NULL; + + drive = grub_hostdisk_os_dev_to_grub_drive (os_disk, add); + free (os_disk); + return drive; +} + +/* + * Note: we do not use the new partition naming scheme as dos_part does not + * necessarily correspond to an msdos partition. + */ +static char * +make_device_name (const char *drive, int dos_part, int bsd_part) +{ + char *ret, *ptr, *end; + const char *iptr; + + ret = xmalloc (strlen (drive) * 2 + + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX" + ",XXXXXXXXXXXXXXXXXXXXXXXXXX")); + end = (ret + strlen (drive) * 2 + + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX" + ",XXXXXXXXXXXXXXXXXXXXXXXXXX")); + ptr = ret; + for (iptr = drive; *iptr; iptr++) + { + if (*iptr == ',') + *ptr++ = '\\'; + *ptr++ = *iptr; + } + *ptr = 0; + if (dos_part >= 0) + snprintf (ptr, end - ptr, ",%d", dos_part + 1); + ptr += strlen (ptr); + if (bsd_part >= 0) + snprintf (ptr, end - ptr, ",%d", bsd_part + 1); + + return ret; +} + +#if defined(__sun__) +static int +device_is_wholedisk (const char *os_dev) +{ + if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0) + return 1; + if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1), + ":q,raw", (sizeof (":q,raw") - 1)) == 0) + return 1; + return 0; +} +#endif + +#if defined(__linux__) || defined(__CYGWIN__) +static int +device_is_wholedisk (const char *os_dev) +{ + int len = strlen (os_dev); + + if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9') + return 1; + return 0; +} +#endif + +#if defined(__NetBSD__) +/* Try to determine whether a given device name corresponds to a whole disk. + This function should give in most cases a definite answer, but it may + actually give an approximate one in the following sense: if the return + value is 0 then the device name does not correspond to a whole disk. */ +static int +device_is_wholedisk (const char *os_dev) +{ + int len = strlen (os_dev); + int rawpart = -1; + +# ifdef HAVE_GETRAWPARTITION + rawpart = getrawpartition(); +# endif /* HAVE_GETRAWPARTITION */ + if (rawpart < 0) + return 1; + return (os_dev[len - 1] == ('a' + rawpart)); +} +#endif /* defined(__NetBSD__) */ + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +static int +device_is_wholedisk (const char *os_dev) +{ + const char *p; + + if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0) + return 0; + + for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p) + if (grub_isdigit (*p)) + { + if (strchr (p, 's')) + return 0; + break; + } + + return 1; +} +#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ + +char * +grub_util_biosdisk_get_grub_dev (const char *os_dev) +{ + struct stat st; + const char *drive; + char *sys_disk; + + grub_util_info ("Looking for %s", os_dev); + + if (stat (os_dev, &st) < 0) + { + grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev); + grub_util_info ("cannot stat `%s'", os_dev); + return 0; + } + + drive = find_system_device (os_dev, &st, 1, 1); + if (!drive) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "no mapping exists for `%s'", os_dev); + grub_util_info ("no mapping exists for `%s'", os_dev); + return 0; + } + + sys_disk = convert_system_partition_to_system_disk (os_dev, &st); + if (grub_strcmp (os_dev, sys_disk) == 0) + { + free (sys_disk); + return make_device_name (drive, -1, -1); + } + free (sys_disk); + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__) + if (! S_ISCHR (st.st_mode)) +#else + if (! S_ISBLK (st.st_mode)) +#endif + return make_device_name (drive, -1, -1); + +#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__) + + /* Linux counts partitions uniformly, whether a BSD partition or a DOS + partition, so mapping them to GRUB devices is not trivial. + Here, get the start sector of a partition by HDIO_GETGEO, and + compare it with each partition GRUB recognizes. + + Cygwin /dev/sdXN emulation uses Windows partition mapping. It + does not count the extended partition and missing primary + partitions. Use same method as on Linux here. + + For NetBSD and FreeBSD, proceed as for Linux, except that the start + sector is obtained from the disk label. */ + { + char *name, *partname; + grub_disk_t disk; + grub_disk_addr_t start; + auto int find_partition (grub_disk_t dsk, + const grub_partition_t partition); + + int find_partition (grub_disk_t dsk __attribute__ ((unused)), + const grub_partition_t partition) + { + grub_disk_addr_t part_start = 0; + grub_util_info ("Partition %d starts from %lu", + partition->number, partition->start); + + part_start = grub_partition_get_start (partition); + + if (start == part_start) + { + partname = grub_partition_get_name (partition); + return 1; + } + + return 0; + } + + name = make_device_name (drive, -1, -1); + +# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__) + if (MAJOR (st.st_rdev) == FLOPPY_MAJOR) + return name; +# else /* defined(HAVE_DIOCGDINFO) */ + /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are + * different, we know that os_dev cannot be a floppy device. */ +# endif /* !defined(HAVE_DIOCGDINFO) */ + + start = grub_hostdisk_find_partition_start (os_dev); + if (grub_errno != GRUB_ERR_NONE) + { + free (name); + return 0; + } + + grub_util_info ("%s starts from %lu", os_dev, start); + + if (start == 0 && device_is_wholedisk (os_dev)) + return name; + + grub_util_info ("opening the device %s", name); + disk = grub_disk_open (name); + free (name); + + if (! disk) + { + /* We already know that the partition exists. Given that we already + checked the device map above, we can only get + GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist. + This can happen on Xen, where disk images in the host can be + assigned to devices that have partition-like names in the guest + but are really more like disks. */ + if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE) + { + grub_util_warn + ("disk does not exist, so falling back to partition device %s", + os_dev); + + drive = find_system_device (os_dev, &st, 0, 1); + if (!drive) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "no mapping exists for `%s'", os_dev); + return 0; + } + + return make_device_name (drive, -1, -1); + } + else + return 0; + } + + name = grub_util_get_ldm (disk, start); + if (name) + return name; + + partname = NULL; + + grub_partition_iterate (disk, find_partition); + if (grub_errno != GRUB_ERR_NONE) + { + grub_disk_close (disk); + return 0; + } + + if (partname == NULL) + { + grub_disk_close (disk); + grub_util_info ("cannot find the partition of `%s'", os_dev); + grub_error (GRUB_ERR_BAD_DEVICE, + "cannot find the partition of `%s'", os_dev); + return 0; + } + + name = grub_xasprintf ("%s,%s", disk->name, partname); + free (partname); + grub_disk_close (disk); + return name; + } + +#elif defined(__GNU__) + /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */ + { + char *p; + int dos_part = -1; + int bsd_part = -1; + + p = strrchr (os_dev, 's'); + if (p) + { + long int n; + char *q; + + p++; + n = strtol (p, &q, 10); + if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX) + { + dos_part = (int) n - 1; + + if (*q >= 'a' && *q <= 'g') + bsd_part = *q - 'a'; + } + } + + return make_device_name (drive, dos_part, bsd_part); + } + +#else +# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly." + return make_device_name (drive, -1, -1); +#endif +} + +int +grub_util_biosdisk_is_present (const char *os_dev) +{ + struct stat st; + + if (stat (os_dev, &st) < 0) + return 0; + + return find_system_device (os_dev, &st, 1, 0) != NULL; +} + +char * +grub_util_get_grub_dev (const char *os_dev) +{ + char *grub_dev = NULL; + + grub_util_pull_device (os_dev); + + switch (grub_util_get_dev_abstraction (os_dev)) + { +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + case GRUB_DEV_ABSTRACTION_LVM: + + { + unsigned short i, len; + grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1; + + len = strlen (os_dev) - offset + 1; + grub_dev = xmalloc (len + sizeof ("lvm/")); + + grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1); + grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len); + } + + break; +#endif + +#ifdef __linux__ + case GRUB_DEV_ABSTRACTION_LUKS: + { + char *uuid, *dash; + uuid = get_dm_uuid (os_dev); + if (!uuid) + break; + dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-'); + if (dash) + *dash = 0; + grub_dev = grub_xasprintf ("cryptouuid/%s", + uuid + sizeof ("CRYPT-LUKS1-") - 1); + grub_free (uuid); + } + break; +#endif + +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) + case GRUB_DEV_ABSTRACTION_GELI: + { + char *whole; + struct gmesh mesh; + struct gclass *class; + const char *name; + int error; + + if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0) + return 0; + name = os_dev + sizeof ("/dev/") - 1; + grub_util_follow_gpart_up (name, NULL, &whole); + + grub_util_info ("following geom '%s'", name); + + error = geom_gettree (&mesh); + if (error != 0) + grub_util_error (_("couldn't open geom")); + + LIST_FOREACH (class, &mesh.lg_class, lg_class) + { + struct ggeom *geom; + LIST_FOREACH (geom, &class->lg_geom, lg_geom) + { + struct gprovider *provider; + LIST_FOREACH (provider, &geom->lg_provider, lg_provider) + if (strcmp (provider->lg_name, name) == 0) + { + struct gconsumer *consumer; + char *fname; + char *uuid; + + LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer) + break; + if (!consumer) + grub_util_error (_("couldn't find geli consumer")); + fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name); + uuid = grub_util_get_geli_uuid (fname); + if (!uuid) + grub_util_error (_("couldn't retrieve geli UUID")); + grub_dev = xasprintf ("cryptouuid/%s", uuid); + free (fname); + free (uuid); + } + } + } + } + break; +#endif + +#ifdef __linux__ + case GRUB_DEV_ABSTRACTION_RAID: + + if (os_dev[7] == '_' && os_dev[8] == 'd') + { + /* This a partitionable RAID device of the form /dev/md_dNNpMM. */ + + char *p, *q; + + p = strdup (os_dev + sizeof ("/dev/md_d") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] == '/' && os_dev[8] == 'd') + { + /* This a partitionable RAID device of the form /dev/md/dNNpMM. */ + + char *p, *q; + + p = strdup (os_dev + sizeof ("/dev/md/d") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] >= '0' && os_dev[7] <= '9') + { + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9') + { + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md/") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md%s", p); + free (p); + } + else if (os_dev[7] == '/') + { + /* mdraid 1.x with a free name. */ + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md/") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md/%s", p); + free (p); + } + else + grub_util_error (_("unknown kind of RAID device `%s'"), os_dev); + + { + char *mdadm_name = get_mdadm_uuid (os_dev); + struct stat st; + + if (mdadm_name) + { + const char *q; + + for (q = os_dev + strlen (os_dev) - 1; q >= os_dev + && grub_isdigit (*q); q--); + + if (q >= os_dev && *q == 'p') + { + free (grub_dev); + grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1); + goto done; + } + free (grub_dev); + grub_dev = xasprintf ("mduuid/%s", mdadm_name); + + done: + free (mdadm_name); + } + } + break; +#endif /* __linux__ */ + + default: /* GRUB_DEV_ABSTRACTION_NONE */ + grub_dev = grub_util_biosdisk_get_grub_dev (os_dev); + } + + return grub_dev; +} + +const char * +grub_util_check_block_device (const char *blk_dev) +{ + struct stat st; + + if (stat (blk_dev, &st) < 0) + grub_util_error (_("cannot stat `%s'"), blk_dev); + + if (S_ISBLK (st.st_mode)) + return (blk_dev); + else + return 0; +} + +const char * +grub_util_check_char_device (const char *blk_dev) +{ + struct stat st; + + if (stat (blk_dev, &st) < 0) + grub_util_error (_("cannot stat `%s'"), blk_dev); + + if (S_ISCHR (st.st_mode)) + return (blk_dev); + else + return 0; +} + +#ifdef __CYGWIN__ +/* Convert POSIX path to Win32 path, + remove drive letter, replace backslashes. */ +static char * +get_win32_path (const char *path) +{ + char winpath[PATH_MAX]; + if (cygwin_conv_path (CCP_POSIX_TO_WIN_A, path, winpath, sizeof(winpath))) + grub_util_error (_("cygwin_conv_path() failed")); + + int len = strlen (winpath); + int offs = (len > 2 && winpath[1] == ':' ? 2 : 0); + + int i; + for (i = offs; i < len; i++) + if (winpath[i] == '\\') + winpath[i] = '/'; + return xstrdup (winpath + offs); +} +#endif + +#ifdef HAVE_LIBZFS +static libzfs_handle_t *__libzfs_handle; + +static void +fini_libzfs (void) +{ + libzfs_fini (__libzfs_handle); +} + +libzfs_handle_t * +grub_get_libzfs_handle (void) +{ + if (! __libzfs_handle) + { + __libzfs_handle = libzfs_init (); + + if (__libzfs_handle) + atexit (fini_libzfs); + } + + return __libzfs_handle; +} +#endif /* HAVE_LIBZFS */ + +/* ZFS has similar problems to those of btrfs (see above). */ +void +grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs) +{ + char *slash; + + *poolname = *poolfs = NULL; + +#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME) + /* FreeBSD and GNU/kFreeBSD. */ + { + struct statfs mnt; + + if (statfs (dir, &mnt) != 0) + return; + + if (strcmp (mnt.f_fstypename, "zfs") != 0) + return; + + *poolname = xstrdup (mnt.f_mntfromname); + } +#elif defined(HAVE_GETEXTMNTENT) + /* Solaris. */ + { + struct stat st; + struct extmnttab mnt; + + if (stat (dir, &st) != 0) + return; + + FILE *mnttab = fopen ("/etc/mnttab", "r"); + if (! mnttab) + return; + + while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0) + { + if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev + && !strcmp (mnt.mnt_fstype, "zfs")) + { + *poolname = xstrdup (mnt.mnt_special); + break; + } + } + + fclose (mnttab); + } +#endif + + if (! *poolname) + return; + + slash = strchr (*poolname, '/'); + if (slash) + { + *slash = '\0'; + *poolfs = xstrdup (slash + 1); + } + else + *poolfs = xstrdup (""); +} + +/* This function never prints trailing slashes (so that its output + can be appended a slash unconditionally). */ +char * +grub_make_system_path_relative_to_its_root (const char *path) +{ + struct stat st; + char *p, *buf, *buf2, *buf3, *ret; + uintptr_t offset = 0; + dev_t num; + size_t len; + char *poolfs = NULL; + + /* canonicalize. */ + p = canonicalize_file_name (path); + if (p == NULL) + grub_util_error (_("failed to get canonical path of %s"), path); + + /* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */ + { + char *dummy; + grub_find_zpool_from_dir (p, &dummy, &poolfs); + } + + len = strlen (p) + 1; + buf = xstrdup (p); + free (p); + + if (stat (buf, &st) < 0) + grub_util_error (_("cannot stat %s: %s"), buf, strerror (errno)); + + buf2 = xstrdup (buf); + num = st.st_dev; + + /* This loop sets offset to the number of chars of the root + directory we're inspecting. */ + while (1) + { + p = strrchr (buf, '/'); + if (p == NULL) + /* This should never happen. */ + grub_util_error (_("FIXME: no / in buf. (make_system_path_relative_to_its_root)")); + if (p != buf) + *p = 0; + else + *++p = 0; + + if (stat (buf, &st) < 0) + grub_util_error (_("cannot stat %s: %s"), buf, strerror (errno)); + + /* buf is another filesystem; we found it. */ + if (st.st_dev != num) + { + /* offset == 0 means path given is the mount point. + This works around special-casing of "/" in Un*x. This function never + prints trailing slashes (so that its output can be appended a slash + unconditionally). Each slash in is considered a preceding slash, and + therefore the root directory is an empty string. */ + if (offset == 0) + { + free (buf); +#ifdef __linux__ + { + char *bind; + grub_free (grub_find_root_device_from_mountinfo (buf2, &bind)); + if (bind && bind[0] && bind[1]) + { + buf3 = bind; + goto parsedir; + } + grub_free (bind); + } +#endif + free (buf2); + if (poolfs) + return xasprintf ("/%s/@", poolfs); + return xstrdup (""); + } + else + break; + } + + offset = p - buf; + /* offset == 1 means root directory. */ + if (offset == 1) + { + /* Include leading slash. */ + offset = 0; + break; + } + } + free (buf); + buf3 = xstrdup (buf2 + offset); + buf2[offset] = 0; +#ifdef __linux__ + { + char *bind; + grub_free (grub_find_root_device_from_mountinfo (buf2, &bind)); + if (bind && bind[0] && bind[1]) + { + char *temp = buf3; + buf3 = grub_xasprintf ("%s%s%s", bind, buf3[0] == '/' ?"":"/", buf3); + grub_free (temp); + } + grub_free (bind); + } +#endif + + free (buf2); + +#ifdef __CYGWIN__ + if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16)) + { + /* Reached some mount point not below /cygdrive. + GRUB does not know Cygwin's emulated mounts, + convert to Win32 path. */ + grub_util_info ("Cygwin path = %s\n", buf3); + char * temp = get_win32_path (buf3); + free (buf3); + buf3 = temp; + } +#endif + + parsedir: + /* Remove trailing slashes, return empty string if root directory. */ + len = strlen (buf3); + while (len > 0 && buf3[len - 1] == '/') + { + buf3[len - 1] = '\0'; + len--; + } + + if (poolfs) + { + ret = xasprintf ("/%s/@%s", poolfs, buf3); + free (buf3); + } + else + ret = buf3; + + return ret; +} diff --git a/util/grub-editenv.c b/util/grub-editenv.c index 519945411..2bff80612 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c @@ -115,26 +115,26 @@ create_envblk_file (const char *name) buf = malloc (DEFAULT_ENVBLK_SIZE); if (! buf) - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); namenew = xasprintf ("%s.new", name); fp = fopen (namenew, "wb"); if (! fp) - grub_util_error ("cannot open the file %s", namenew); + grub_util_error (_("cannot open the file %s"), namenew); memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); if (fwrite (buf, 1, DEFAULT_ENVBLK_SIZE, fp) != DEFAULT_ENVBLK_SIZE) - grub_util_error ("cannot write to the file %s", namenew); + grub_util_error (_("cannot write to the file %s"), namenew); fsync (fileno (fp)); free (buf); fclose (fp); if (rename (namenew, name) < 0) - grub_util_error ("cannot rename the file %s to %s", namenew, name); + grub_util_error (_("cannot rename the file %s to %s"), namenew, name); free (namenew); } @@ -153,29 +153,29 @@ open_envblk_file (const char *name) create_envblk_file (name); fp = fopen (name, "rb"); if (! fp) - grub_util_error ("cannot open the file %s", name); + grub_util_error (_("cannot open the file %s"), name); } if (fseek (fp, 0, SEEK_END) < 0) - grub_util_error ("cannot seek the file %s", name); + grub_util_error (_("cannot seek the file %s"), name); size = (size_t) ftell (fp); if (fseek (fp, 0, SEEK_SET) < 0) - grub_util_error ("cannot seek the file %s", name); + grub_util_error (_("cannot seek the file %s"), name); buf = malloc (size); if (! buf) - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); if (fread (buf, 1, size, fp) != size) - grub_util_error ("cannot read the file %s", name); + grub_util_error (_("cannot read the file %s"), name); fclose (fp); envblk = grub_envblk_open (buf, size); if (! envblk) - grub_util_error ("invalid environment block"); + grub_util_error (_("invalid environment block")); return envblk; } @@ -204,11 +204,11 @@ write_envblk (const char *name, grub_envblk_t envblk) fp = fopen (name, "wb"); if (! fp) - grub_util_error ("cannot open the file %s", name); + grub_util_error (_("cannot open the file %s"), name); if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp) != grub_envblk_size (envblk)) - grub_util_error ("cannot write to the file %s", name); + grub_util_error (_("cannot write to the file %s"), name); fsync (fileno (fp)); fclose (fp); @@ -226,12 +226,12 @@ set_variables (const char *name, int argc, char *argv[]) p = strchr (argv[0], '='); if (! p) - grub_util_error ("invalid parameter %s", argv[0]); + grub_util_error (_("invalid parameter %s"), argv[0]); *(p++) = 0; if (! grub_envblk_set (envblk, argv[0], p)) - grub_util_error ("environment block too small"); + grub_util_error (_("environment block too small")); argc--; argv++; diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 2fcde4ab0..c81314e77 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -54,16 +55,22 @@ execute_command (char *name, int n, char **args) return (cmd->func) (cmd, n, args); } -#define CMD_LS 1 -#define CMD_CP 2 -#define CMD_CMP 3 -#define CMD_HEX 4 -#define CMD_CRC 6 -#define CMD_BLOCKLIST 7 - +enum { + CMD_LS = 1, + CMD_CP, + CMD_CAT, + CMD_CMP, + CMD_HEX, + CMD_CRC, + CMD_BLOCKLIST, + CMD_TESTLOAD, + CMD_ZFSINFO, + CMD_XNU_UUID +}; #define BUF_SIZE 32256 static grub_disk_addr_t skip, leng; +static int uncompress = 0; static void read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) @@ -107,11 +114,13 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) return; } - grub_file_filter_disable_compression (); + if (uncompress == 0) + grub_file_filter_disable_compression (); file = grub_file_open (pathname); if (!file) { - grub_util_error (_("cannot open file %s"), pathname); + grub_util_error (_("cannot open file %s:%s"), pathname, + grub_errmsg); return; } @@ -174,13 +183,34 @@ cmd_cp (char *src, char *dest) ff = fopen (dest, "wb"); if (ff == NULL) { - grub_util_error (_("open error")); + grub_util_error (_("OS file %s open error: %s"), dest, + strerror (errno)); return; } read_file (src, cp_hook); fclose (ff); } +static void +cmd_cat (char *src) +{ + auto int cat_hook (grub_off_t ofs, char *buf, int len); + int cat_hook (grub_off_t ofs, char *buf, int len) + { + (void) ofs; + + if ((int) fwrite (buf, 1, len, stdout) != len) + { + grub_util_error (_("write error")); + return 1; + } + + return 0; + } + + read_file (src, cat_hook); +} + static void cmd_cmp (char *src, char *dest) { @@ -213,7 +243,8 @@ cmd_cmp (char *src, char *dest) ff = fopen (dest, "rb"); if (ff == NULL) { - grub_util_error (_("open error")); + grub_util_error (_("OS file %s open error: %s"), dest, + strerror (errno)); return; } @@ -221,6 +252,14 @@ cmd_cmp (char *src, char *dest) grub_util_error (_("seek error")); read_file (src, cmp_hook); + + { + grub_uint64_t pre; + pre = ftell (ff); + fseek (ff, 0, SEEK_END); + if (pre != ftell (ff)) + grub_util_error (_("unexpected end of file")); + } fclose (ff); } @@ -266,6 +305,7 @@ static char **images = NULL; static int cmd = 0; static char *debug_str = NULL; static char **args = NULL; +static int mount_crypt = 0; static void fstest (int n, char **args) @@ -295,23 +335,40 @@ fstest (int n, char **args) grub_free (host_file); } + { + char *argv[2] = { "-a", NULL}; + if (mount_crypt) + { + if (execute_command ("cryptomount", 1, argv)) + grub_util_error (_("cryptomount command fails: %s"), grub_errmsg); + } + } + + grub_ldm_fini (); grub_lvm_fini (); grub_mdraid09_fini (); grub_mdraid1x_fini (); - grub_raid_fini (); - grub_raid_init (); + grub_diskfilter_fini (); + grub_diskfilter_init (); grub_mdraid09_init (); grub_mdraid1x_init (); grub_lvm_init (); + grub_ldm_init (); switch (cmd) { case CMD_LS: execute_command ("ls", n, args); break; + case CMD_ZFSINFO: + execute_command ("zfsinfo", n, args); + break; case CMD_CP: cmd_cp (args[0], args[1]); break; + case CMD_CAT: + cmd_cat (args[0]); + break; case CMD_CMP: cmd_cmp (args[0], args[1]); break; @@ -324,6 +381,32 @@ fstest (int n, char **args) case CMD_BLOCKLIST: execute_command ("blocklist", n, args); grub_printf ("\n"); + case CMD_TESTLOAD: + execute_command ("testload", n, args); + grub_printf ("\n"); + case CMD_XNU_UUID: + { + grub_device_t dev; + grub_fs_t fs; + char *uuid = 0; + char *argv[3] = { "-l", NULL, NULL}; + dev = grub_device_open (n ? args[0] : 0); + if (!dev) + grub_util_error (grub_errmsg); + fs = grub_fs_probe (dev); + if (!fs) + grub_util_error (grub_errmsg); + if (!fs->uuid) + grub_util_error (_("couldn't retrieve UUID")); + if (fs->uuid (dev, &uuid)) + grub_util_error (grub_errmsg); + if (!uuid) + grub_util_error (_("couldn't retrieve UUID")); + argv[1] = uuid; + execute_command ("xnu_uuid", 2, argv); + grub_free (uuid); + grub_device_close (dev); + } } for (i = 0; i < num_disks; i++) @@ -347,17 +430,22 @@ static struct argp_option options[] = { {0, 0, 0 , OPTION_DOC, N_("Commands:"), 1}, {N_("ls PATH"), 0, 0 , OPTION_DOC, N_("List files in PATH."), 1}, {N_("cp FILE LOCAL"), 0, 0, OPTION_DOC, N_("Copy FILE to local file LOCAL."), 1}, + {N_("cat FILE"), 0, 0 , OPTION_DOC, N_("Copy FILE to standard output."), 1}, {N_("cmp FILE LOCAL"), 0, 0, OPTION_DOC, N_("Compare FILE with local file LOCAL."), 1}, {N_("hex FILE"), 0, 0 , OPTION_DOC, N_("Hex dump FILE."), 1}, {N_("crc FILE"), 0, 0 , OPTION_DOC, N_("Get crc32 checksum of FILE."), 1}, {N_("blocklist FILE"), 0, 0, OPTION_DOC, N_("Display blocklist of FILE."), 1}, + {N_("xnu_uuid"), 0, 0, OPTION_DOC, N_("Compute XNU UUID of the device."), 1}, {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2}, {"skip", 's', "N", 0, N_("Skip N bytes from output file."), 2}, {"length", 'n', "N", 0, N_("Handle N bytes in output file."), 2}, {"diskcount", 'c', "N", 0, N_("N input files."), 2}, {"debug", 'd', "S", 0, N_("Set debug environment variable."), 2}, + {"crypto", 'C', NULL, OPTION_ARG_OPTIONAL, N_("Mount crypto devices."), 2}, + {"zfs-key", 'K', N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2}, {"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, N_("Print verbose messages."), 2}, + {"uncompress", 'u', NULL, OPTION_ARG_OPTIONAL, N_("Uncompress data."), 2}, {0, 0, 0, 0, 0, 0} }; @@ -380,6 +468,42 @@ argp_parser (int key, char *arg, struct argp_state *state) root = arg; return 0; + case 'K': + if (strcmp (arg, "prompt") == 0) + { + char buf[1024]; + grub_puts_ (N_("Enter ZFS password: ")); + if (grub_password_get (buf, 1023)) + { + grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1); + } + } + else + { + FILE *f; + ssize_t real_size; + grub_uint8_t buf[1024]; + f = fopen (arg, "rb"); + if (!f) + { + printf (_("Error loading file %s: %s\n"), arg, strerror (errno)); + return 0; + } + real_size = fread (buf, 1, 1024, f); + if (real_size < 0) + { + printf (_("Error loading file %s: %s\n"), arg, strerror (errno)); + fclose (f); + return 0; + } + grub_zfs_add_key (buf, real_size, 0); + } + return 0; + + case 'C': + mount_crypt = 1; + return 0; + case 's': skip = grub_strtoul (arg, &p, 0); if (*p == 's') @@ -414,6 +538,10 @@ argp_parser (int key, char *arg, struct argp_state *state) verbosity++; return 0; + case 'u': + uncompress = 1; + return 0; + case ARGP_KEY_END: if (args_count < num_disks) { @@ -436,14 +564,9 @@ argp_parser (int key, char *arg, struct argp_state *state) if (args_count < num_disks) { - if (arg[0] != '/') - { - fprintf (stderr, "%s", _("Must use absolute path.\n")); - argp_usage (state); - } if (args_count == 0) images = xmalloc (num_disks * sizeof (images[0])); - images[args_count] = xstrdup (arg); + images[args_count] = canonicalize_file_name (arg); args_count++; return 0; } @@ -454,11 +577,20 @@ argp_parser (int key, char *arg, struct argp_state *state) { cmd = CMD_LS; } + else if (!grub_strcmp (arg, "zfsinfo")) + { + cmd = CMD_ZFSINFO; + } else if (!grub_strcmp (arg, "cp")) { cmd = CMD_CP; nparm = 2; } + else if (!grub_strcmp (arg, "cat")) + { + cmd = CMD_CAT; + nparm = 1; + } else if (!grub_strcmp (arg, "cmp")) { cmd = CMD_CMP; @@ -479,6 +611,16 @@ argp_parser (int key, char *arg, struct argp_state *state) cmd = CMD_BLOCKLIST; nparm = 1; } + else if (!grub_strcmp (arg, "testload")) + { + cmd = CMD_TESTLOAD; + nparm = 1; + } + else if (grub_strcmp (arg, "xnu_uuid") == 0) + { + cmd = CMD_XNU_UUID; + nparm = 0; + } else { fprintf (stderr, _("Invalid command %s.\n"), arg); @@ -514,6 +656,7 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_gcry_init_all (); if (debug_str) grub_env_set ("debug", debug_str); @@ -542,6 +685,7 @@ main (int argc, char *argv[]) fstest (args_count - 1 - num_disks, args); /* Free resources. */ + grub_gcry_fini_all (); grub_fini_all (); return 0; diff --git a/util/grub-install.in b/util/grub-install.in index cace82593..7e4bf1512 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -19,32 +19,34 @@ # Initialize some variables. transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -sbindir=@sbindir@ -bindir=@bindir@ -libdir=@libdir@ -sysconfdir=@sysconfdir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +sbindir="@sbindir@" +bindir="@bindir@" +libdir="@libdir@" +sysconfdir="@sysconfdir@" PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ platform=@platform@ host_os=@host_os@ -pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` -localedir=@datadir@/locale +pkglibdir="${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}`" +datadir="@datadir@" +localedir="@datadir@/locale" -self=`basename $0` +self="`basename $0`" -grub_setup=${sbindir}/`echo grub-setup | sed ${transform}` -grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` -grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` -grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` -grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` -grub_mkrelpath=${bindir}/`echo grub-mkrelpath | sed ${transform}` +grub_setup="${sbindir}/`echo grub-setup | sed ${transform}`" +grub_mkimage="${bindir}/`echo grub-mkimage | sed ${transform}`" +grub_mkdevicemap="${sbindir}/`echo grub-mkdevicemap | sed ${transform}`" +grub_probe="${sbindir}/`echo grub-probe | sed ${transform}`" +grub_editenv="${bindir}/`echo grub-editenv | sed ${transform}`" +grub_mkrelpath="${bindir}/`echo grub-mkrelpath | sed ${transform}`" rootdir= bootdir= -grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` +grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`" modules= install_device= @@ -56,18 +58,15 @@ debug_image= update_nvram=yes -ofpathname=`which ofpathname` -nvsetenv=`which nvsetenv` -efibootmgr=`which efibootmgr 2>/dev/null || true` removable=no efi_quiet= # Get GRUB_DISTRIBUTOR. -if test -f ${sysconfdir}/default/grub ; then - . ${sysconfdir}/default/grub +if test -f "${sysconfdir}/default/grub" ; then + . "${sysconfdir}/default/grub" fi -bootloader_id="$(echo "$GRUB_DISTRIBUTOR" | tr '[A-Z]' '[a-z]' | cut -d' ' -f1)" +bootloader_id="$(echo "$GRUB_DISTRIBUTOR" | tr 'A-Z' 'a-z' | cut -d' ' -f1)" if test -z "$bootloader_id"; then bootloader_id=grub fi @@ -77,7 +76,7 @@ if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then elif [ "${platform}" = "ieee1275" ] || [ "${platform}" = "efi" ] ; then disk_module= else - disk_module=ata + disk_module=native fi # Usage: usage @@ -107,12 +106,14 @@ Install GRUB on your drive. --grub-mkdevicemap=FILE use FILE as grub-mkdevicemap --grub-probe=FILE use FILE as grub-probe --no-floppy do not probe any floppy drive - --recheck probe a device map even if it already exists + --allow-floppy Make the drive also bootable as floppy + (default for fdX devices). May break on some BIOSes. + --recheck delete device map if it already exists --force install even if problems are detected EOF if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then cat <&2 exit 1 fi - echo $1 + echo "$1" } +allow_floppy="" + # Check the arguments. while test $# -gt 0 do @@ -175,44 +178,44 @@ do # Accept for compatibility --root-directory) - rootdir=`argument $option "$@"`; shift;; + rootdir="`argument $option "$@"`"; shift;; --root-directory=*) - rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + rootdir="`echo "$option" | sed 's/--root-directory=//'`" ;; --boot-directory) - bootdir=`argument $option "$@"`; shift;; + bootdir="`argument $option "$@"`"; shift;; --boot-directory=*) - bootdir=`echo "$option" | sed 's/--boot-directory=//'` ;; + bootdir="`echo "$option" | sed 's/--boot-directory=//'`" ;; --grub-setup) - grub_setup=`argument $option "$@"`; shift;; + grub_setup="`argument "$option" "$@"`"; shift;; --grub-setup=*) - grub_setup=`echo "$option" | sed 's/--grub-setup=//'` ;; + grub_setup="`echo "$option" | sed 's/--grub-setup=//'`" ;; --bootloader-id) - bootloader_id=`argument $option "$@"`; shift;; + bootloader_id="`argument $option "$@"`"; shift;; --bootloader-id=*) - bootloader_id=`echo "$option" | sed 's/--bootloader-id=//'` ;; + bootloader_id="`echo "$option" | sed 's/--bootloader-id=//'`" ;; --grub-mkimage) - grub_mkimage=`argument $option "$@"`; shift;; + grub_mkimage="`argument $option "$@"`"; shift;; --grub-mkimage=*) - grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + grub_mkimage="`echo "$option" | sed 's/--grub-mkimage=//'`" ;; --grub-mkrelpath) - grub_mkrelpath=`argument $option "$@"`; shift;; - --grub-mkimage=*) - grub_mkrelpath=`echo "$option" | sed 's/--grub-mkrelpath=//'` ;; + grub_mkrelpath="`argument "$option" "$@"`"; shift;; + --grub-mkrelpath=*) + grub_mkrelpath="`echo "$option" | sed 's/--grub-mkrelpath=//'`" ;; --grub-mkdevicemap) - grub_mkdevicemap=`argument $option "$@"`; shift;; + grub_mkdevicemap="`argument "$option" "$@"`"; shift;; --grub-mkdevicemap=*) - grub_mkdevicemap=`echo "$option" | sed 's/--grub-mkdevicemap=//'` ;; + grub_mkdevicemap="`echo "$option" | sed 's/--grub-mkdevicemap=//'`" ;; --grub-probe) - grub_probe=`argument $option "$@"`; shift;; + grub_probe="`argument "$option" "$@"`"; shift;; --grub-probe=*) - grub_probe=`echo "$option" | sed 's/--grub-probe=//'` ;; + grub_probe="`echo "$option" | sed 's/--grub-probe=//'`" ;; --no-floppy) no_floppy="--no-floppy" ;; @@ -221,13 +224,16 @@ do --removable) removable=yes ;; + --allow-floppy) + allow_floppy="--allow-floppy" ;; + --disk-module) if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then - disk_module=`argument $option "$@"`; shift; + disk_module="`argument "$option" "$@"`"; shift; fi ;; --disk-module=*) if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then - disk_module=`echo "$option" | sed 's/--disk-module=//'` + disk_module="`echo "$option" | sed 's/--disk-module=//'`" fi ;; --no-nvram) @@ -237,9 +243,9 @@ do --debug) debug=yes ;; --debug-image) - debug_image=`argument $option "$@"`; shift;; + debug_image="`argument "$option" "$@"`"; shift;; --debug-image=*) - debug_image=`echo "$option" | sed 's/--debug-image=//'` ;; + debug_image="`echo "$option" | sed 's/--debug-image=//'`" ;; -f | --force) setup_force="--force" ;; @@ -259,8 +265,7 @@ do esac done -# for make_system_path_relative_to_its_root() -. ${libdir}/grub/grub-mkconfig_lib +. "${datadir}/@PACKAGE@/grub-mkconfig_lib" if test "x$install_device" = x && ([ "${target_cpu}-${platform}" = "i386-pc" ] \ || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ]); then @@ -269,9 +274,16 @@ if test "x$install_device" = x && ([ "${target_cpu}-${platform}" = "i386-pc" ] \ exit 1 fi +if ! ([ "${target_cpu}-${platform}" = "i386-pc" ] \ + || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] \ + || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ] \ + || [ "${target_cpu}-${platform}" = "mips-arc" ]); then + install_device= +fi + # If the debugging feature is enabled, print commands. setup_verbose= -if test $debug = yes; then +if test x"$debug" = xyes; then set -x setup_verbose="--verbose" efi_quiet=-q @@ -279,17 +291,17 @@ fi if [ -z "$bootdir" ]; then # Default bootdir if bootdir not initialized. - bootdir=/@bootdirname@ + bootdir="/@bootdirname@" if [ -n "$rootdir" ] ; then # Initialize bootdir if rootdir was initialized. - bootdir=${rootdir}/@bootdirname@ + bootdir="${rootdir}/@bootdirname@" fi fi -grubdir=`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'` -device_map=${grubdir}/device.map -grub_probe="${grub_probe} --device-map=${device_map}" +grubdir="`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'`" +device_map="${grubdir}/device.map" + # Check if GRUB is installed. if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then @@ -302,7 +314,7 @@ if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" fi fi -set $grub_mkimage dummy +set "$grub_mkimage" dummy if test -f "$1"; then : else @@ -310,7 +322,7 @@ else exit 1 fi -set $grub_mkdevicemap dummy +set "$grub_mkdevicemap" dummy if test -f "$1"; then : else @@ -321,24 +333,30 @@ fi if [ x"$platform" = xefi ]; then # Find the EFI System Partition. efidir= - if test -d ${bootdir}/efi; then - install_device=`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${bootdir}/efi` + if test -d "${bootdir}/efi"; then + install_device="`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${bootdir}/efi"`" # Is it a mount point? - if test "x$install_device" != "x`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${bootdir}`"; then - efidir=${bootdir}/efi + if test "x$install_device" != "x`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${bootdir}"`"; then + efidir="${bootdir}/efi" + fi + elif test -d "${bootdir}/EFI"; then + install_device="`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${bootdir}/EFI"`" + # Is it a mount point? + if test "x$install_device" != "x`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${bootdir}"`"; then + efidir="${bootdir}/EFI" fi elif test -n "$rootdir" && test "x$rootdir" != "x/"; then # The EFI System Partition may have been given directly using # --root-directory. - install_device=`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${rootdir}` + install_device="`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${rootdir}"`" # Is it a mount point? - if test "x$install_device" != "x`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${rootdir}/..`"; then - efidir=${rootdir} + if test "x$install_device" != "x`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${rootdir}/.."`"; then + efidir="${rootdir}" fi fi if test -n "$efidir"; then - efi_fs=`$grub_probe --target=fs --device-map=${device_map} ${efidir}` + efi_fs=`"$grub_probe" --target=fs "--device-map=${device_map}" "${efidir}"` if test "x$efi_fs" = xfat; then :; else echo "${efidir} doesn't look like an EFI partition." 1>&2 efidir= @@ -361,7 +379,7 @@ if [ x"$platform" = xefi ]; then case "$target_cpu" in i386) efi_file=BOOTIA32.EFI ;; - x86-64) + x86_64) efi_file=BOOTX64.EFI ;; # GRUB does not yet support these architectures, but they're defined # by the specification so we include them here to ease future @@ -375,7 +393,7 @@ if [ x"$platform" = xefi ]; then case "$target_cpu" in i386) efi_file=grubia32.efi ;; - x86-64) + x86_64) efi_file=grubx64.efi ;; # GRUB does not yet support these architectures, but they're defined # by the specification so we include them here to ease future @@ -404,64 +422,62 @@ mkdir -p "$grubdir" || exit 1 # If --recheck is specified, remove the device map, if present. if test $recheck = yes; then - rm -f $device_map + rm -f "$device_map" fi # Create the device map file if it is not present. if test -f "$device_map"; then - : + # Make sure that there is no duplicated entry. + tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' "$device_map" \ + | sort | uniq -d | sed -n 1p` + if test -n "$tmp"; then + echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2 + exit 1 + fi else - # Create a safe temporary file. - test -n "$mklog" && log_file=`$mklog` - - $grub_mkdevicemap --device-map=$device_map $no_floppy || exit 1 -fi - -# Make sure that there is no duplicated entry. -tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \ - | sort | uniq -d | sed -n 1p` -if test -n "$tmp"; then - echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2 - exit 1 + device_map= fi # Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img ${grubdir}/efiemu??.o; do - if test -f $file && [ "`basename $file`" != menu.lst ]; then - rm -f $file || exit 1 +for file in "${grubdir}"/*.mod "${grubdir}"/*.lst "${grubdir}"/*.img "${grubdir}"/efiemu??.o; do + if test -f "$file" && [ "`basename $file`" != menu.lst ]; then + rm -f "$file" || exit 1 fi done -for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst; do - cp -f $file ${grubdir} || exit 1 +for file in "${pkglibdir}"/*.mod "${pkglibdir}"/*.lst; do + cp -f "$file" "${grubdir}" || exit 1 done if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then - for file in ${pkglibdir}/*.img ${pkglibdir}/efiemu??.o; do - if test -f $file; then - cp -f $file ${grubdir} || exit 1 + for file in "${pkglibdir}"/*.img "${pkglibdir}"/efiemu??.o; do + if test -f "$file"; then + cp -f "$file" "${grubdir}" || exit 1 fi done fi # Copy gettext files -mkdir -p ${grubdir}/locale/ -for dir in ${localedir}/*; do +mkdir -p "${grubdir}"/locale/ +for dir in "${localedir}"/*; do if test -f "$dir/LC_MESSAGES/grub.mo"; then cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo" fi done -# Write device to a variable so we don't have to traverse /dev every time. -grub_device=`$grub_probe --target=device ${grubdir}` || exit 1 +is_path_readable_by_grub "${grubdir}" || (echo "${grubdir}" not readable 1>&2 ; exit 1) -if ! test -f ${grubdir}/grubenv; then - $grub_editenv ${grubdir}/grubenv create +# Write device to a variable so we don't have to traverse /dev every time. +grub_device="`"$grub_probe" --device-map="${device_map}" --target=device "${grubdir}"`" || exit 1 + +if ! test -f "${grubdir}"/grubenv; then + "$grub_editenv" "${grubdir}"/grubenv create fi # Create the core image. First, auto-detect the filesystem module. -fs_module=`$grub_probe --target=fs --device ${grub_device}` -if test "x$fs_module" = x -a "x$modules" = x; then - echo "Auto-detection of a filesystem module failed." 1>&2 - echo "Please specify the module with the option \`--modules' explicitly." 1>&2 +fs_module="`"$grub_probe" --device-map="${device_map}" --target=fs --device "${grub_device}"`" +if test "x$fs_module" = x ; then + echo "Auto-detection of a filesystem of ${grub_device} failed." 1>&2 + echo "Try with --recheck." 1>&2 + echo "If the problem persists please report this together with the output of \"$grub_probe --device-map=\"${device_map}\" --target=fs -v ${grubdir}\" to " 1>&2 exit 1 fi @@ -469,23 +485,36 @@ fi # this command is allowed to fail (--target=fs already grants us that the # filesystem will be accessible). partmap_module= -for x in `$grub_probe --target=partmap --device ${grub_device} 2> /dev/null`; do +for x in `"$grub_probe" --device-map="${device_map}" --target=partmap --device "${grub_device}" 2> /dev/null`; do case "$x" in netbsd | openbsd) partmap_module="$partmap_module part_bsd";; + "") ;; *) partmap_module="$partmap_module part_$x";; esac done # Device abstraction module, if any (lvm, raid). -devabstraction_module=`$grub_probe --target=abstraction --device ${grub_device}` +devabstraction_module="`"$grub_probe" --device-map="${device_map}" --target=abstraction --device "${grub_device}"`" + +if [ "x$disk_module" = xata ]; then + disk_module=pata +fi + +if [ "x$disk_module" = xnative ]; then + disk_module="pata ahci ohci" + if [ "x$target_cpu" = "xi386" ] || [ "x$target_cpu" = "xx86_64" ]; then + disk_module="$disk_module uhci" + fi + disk_module="$disk_module usbms" +fi # The order in this list is critical. Be careful when modifying it. modules="$modules $disk_module" modules="$modules $fs_module $partmap_module $devabstraction_module" -relative_grubdir=`make_system_path_relative_to_its_root ${grubdir}` || exit 1 +relative_grubdir="`"$grub_mkrelpath" "${grubdir}"`" || exit 1 if [ "x${relative_grubdir}" = "x" ] ; then relative_grubdir=/ fi @@ -493,10 +522,10 @@ fi prefix_drive= config_opt= -rm -f ${grubdir}/load.cfg +rm -f "${grubdir}/load.cfg" if [ "x${debug_image}" != x ]; then - echo "set debug='${debug_image}'" >> ${grubdir}/load.cfg + echo "set debug='${debug_image}'" >> "${grubdir}/load.cfg" config_opt="-c ${grubdir}/load.cfg " fi @@ -505,85 +534,111 @@ if [ "x${devabstraction_module}" = "x" ] ; then if echo "${install_device}" | grep -qx "(.*)" ; then install_drive="${install_device}" else - install_drive="`$grub_probe --target=drive --device ${install_device}`" || exit 1 + install_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${install_device}"`" || exit 1 fi - install_drive="`echo ${install_drive} | sed -e s/,[a-z0-9,]*//g`" + install_drive="`echo "${install_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`" fi - grub_drive="`$grub_probe --target=drive --device ${grub_device}`" || exit 1 + grub_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${grub_device}"`" || exit 1 # Strip partition number - grub_partition="`echo ${grub_drive} | sed -e 's/^[^,]*,//; s/)$//'`" - grub_drive="`echo ${grub_drive} | sed -e s/,[a-z0-9,]*//g`" - if [ "$disk_module" = ata ] ; then + grub_partition="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\3/'`" + grub_drive="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`" + if ([ "x$disk_module" != x ] && [ "x$disk_module" != xbiosdisk ]) || [ "x${grub_drive}" != "x${install_drive}" ] || ([ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${platform}" != x"ieee1275" ]); then # generic method (used on coreboot and ata mod) - uuid="`$grub_probe --target=fs_uuid --device ${grub_device}`" + uuid="`"$grub_probe" --device-map="${device_map}" --target=fs_uuid --device "${grub_device}"`" if [ "x${uuid}" = "x" ] ; then - echo "UUID needed with ata mod, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + if [ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${platform}" != x"ieee1275" ]; then + echo "UUID needed with $platform, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + elif [ "$disk_module" = ata ]; then + echo "UUID needed with ata mod, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + else + echo "UUID needed with cross-disk installs, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + fi + exit 1 fi - echo "search.fs_uuid ${uuid} root " >> ${grubdir}/load.cfg - echo 'set prefix=($root)'"${relative_grubdir}" >> ${grubdir}/load.cfg - config_opt="-c ${grubdir}/load.cfg " - modules="$modules search_fs_uuid" - elif [ "x${grub_drive}" != "x${install_drive}" ] ; then - uuid="`$grub_probe --target=fs_uuid --device ${grub_device}`" - if [ "x${uuid}" = "x" ] ; then - echo "You attempted a cross-disk install, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 - exit 1 + + if [ x"$disk_module" != x ] && [ x"$disk_module" != xbiosdisk ]; then + hints="`"$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device "${grub_device}"`" + elif [ x"$platform" = xpc ]; then + hints="`"$grub_probe" --device-map="${device_map}" --target=bios_hints --device "${grub_device}"`" + elif [ x"$platform" = xefi ]; then + hints="`"$grub_probe" --device-map="${device_map}" --target=efi_hints --device "${grub_device}"`" + elif [ x"$platform" = xieee1275 ]; then + hints="`"$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device "${grub_device}"`" + elif [ x"$platform" = xloongson ] || [ x"$platform" = xqemu ] || [ x"$platform" = xcoreboot ] || [ x"$platform" = xmultiboot ] || [ x"$platform" = xqemu-mips ]; then + hints="`"$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device "${grub_device}"`" + else + echo "No hints available for your platform. Expect reduced performance" + hints= fi - echo "search.fs_uuid ${uuid} root " >> ${grubdir}/load.cfg - echo 'set prefix=($root)'"${relative_grubdir}" >> ${grubdir}/load.cfg + echo "search.fs_uuid ${uuid} root $hints " >> "${grubdir}/load.cfg" + echo 'set prefix=($root)'"${relative_grubdir}" >> "${grubdir}/load.cfg" config_opt="-c ${grubdir}/load.cfg " modules="$modules search_fs_uuid" - elif [ "x$platform" = xefi ] || [ "x$platform" = xpc ]; then + else # we need to hardcode the partition number in the core image's prefix. - prefix_drive="(,$grub_partition)" + if [ x"$grub_partition" = x ]; then + prefix_drive="()" + else + # Comma is already there + prefix_drive="($grub_partition)" + fi fi else - prefix_drive=`$grub_probe --target=drive --device ${grub_device}` || exit 1 + if [ x$GRUB_CRYPTODISK_ENABLE = xy ]; then + for uuid in "`"${grub_probe}" --device "${grub_device}" --target=cryptodisk_uuid`"; do + echo "cryptomount -u $uuid" >> "${grubdir}/load.cfg" + done + config_opt="-c ${grubdir}/load.cfg " + fi + + prefix_drive=`"$grub_probe" --device-map="${device_map}" --target=drive --device "${grub_device}"` || exit 1 fi case "${target_cpu}-${platform}" in sparc64-ieee1275) mkimage_target=sparc64-ieee1275-raw ;; - mips-yeeloong) mkimage_target=mipsel-yeeloong-elf ;; + mipsel-loongson) mkimage_target=mipsel-loongson-elf ;; *) mkimage_target="${target_cpu}-${platform}" ;; esac case "${target_cpu}-${platform}" in i386-efi | x86_64-efi) imgext=efi ;; - mips-yeeloong | i386-coreboot | i386-multiboot | i386-ieee1275 \ + mipsel-loongson | i386-coreboot | i386-multiboot | i386-ieee1275 \ | powerpc-ieee1275) imgext=elf ;; *) imgext=img ;; esac -$grub_mkimage ${config_opt} -d ${pkglibdir} -O ${mkimage_target} --output=${grubdir}/core.${imgext} --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 +"$grub_mkimage" ${config_opt} -d "${pkglibdir}" -O ${mkimage_target} --output="${grubdir}/core.${imgext}" --prefix="${prefix_drive}${relative_grubdir}" $modules || exit 1 # Backward-compatibility kludges -if [ "${target_cpu}-${platform}" = "mips-yeeloong" ]; then - cp ${grubdir}/core.${imgext} ${bootdir}/grub.elf +if [ "${target_cpu}-${platform}" = "mipsel-loongson" ]; then + cp "${grubdir}/core.${imgext}" "${bootdir}"/grub.elf elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ]; then - cp ${grubdir}/core.${imgext} ${grubdir}/grub + cp "${grubdir}/core.${imgext}" "${grubdir}/grub" elif [ "${target_cpu}-${platform}" = "i386-efi" ] || [ "${target_cpu}-${platform}" = "x86_64-efi" ]; then - $grub_mkimage ${config_opt} -d ${pkglibdir} -O ${mkimage_target} --output=${grubdir}/grub.efi --prefix="" $modules || exit 1 + "$grub_mkimage" ${config_opt} -d "${pkglibdir}" -O ${mkimage_target} --output="${grubdir}/grub.efi" --prefix="" $modules || exit 1 fi # Perform the platform-dependent install if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then # Now perform the installation. - $grub_setup ${setup_verbose} ${setup_force} --directory=${grubdir} \ - --device-map=${device_map} ${install_device} || exit 1 + "$grub_setup" ${allow_floppy} ${setup_verbose} ${setup_force} --directory="${grubdir}" \ + --device-map="${device_map}" "${install_device}" || exit 1 elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ]; then if [ x"$update_nvram" = xyes ]; then - set $ofpathname dummy + ofpathname="`which ofpathname`" + nvsetenv="`which nvsetenv`" + set "$ofpathname" dummy if test -f "$1"; then : else echo "$1: Not found." 1>&2 exit 1 fi - set $nvsetenv dummy + set "$nvsetenv" dummy if test -f "$1"; then : else @@ -591,16 +646,39 @@ elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${pla exit 1 fi # Get the Open Firmware device tree path translation. - dev=`echo $grub_device | sed -e 's/\/dev\///' -e 's/[0-9]\+//'` - partno=`echo $grub_device | sed -e 's/.*[^0-9]\([0-9]\+\)$/\1/'` - ofpath=`$ofpathname $dev` || { + dev="`echo $grub_device | sed -e 's/\/dev\///' -e 's/[0-9]\+//'`" + partno="`echo $grub_device | sed -e 's/.*[^0-9]\([0-9]\+\)$/\1/'`" + ofpath="`$ofpathname $dev`" || { echo "Couldn't find Open Firmware device tree path for $dev." echo "You will have to set boot-device manually." exit 1 } # Point boot-device at the new grub install - boot_device="$ofpath:$partno,"`grub-mkrelpath ${grubdir}/core.${imgext} | sed 's,/,\\\\,g'` + boot_device="$ofpath:$partno,"`"$grub_mkrelpath" "${grubdir}/core.${imgext}" | sed 's,/,\\\\,g'` + + # If a install device is defined, copy the core.elf to PReP partition. + if [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ] \ + && [ -n "${install_device}" ]; then + if [ "$("${grub_probe}" -m "${device_map}" -d "${install_device}" -t msdos_parttype)" != "41" ]; then + echo "The chosen partition is not a PReP partition." + exit 1 + fi + + if [ "$(file -s "${install_device}" -b | awk '{ print $1 }')" = ELF ] || [ $(cmp /dev/zero "${install_device}" &>/dev/null) ]; then + # Change boot device to the harddisk root + boot_device="$ofpath" + dd if="${grubdir}/core.${imgext}" of="${install_device}" status=noxfer || { + echo "Failed to copy Grub to the PReP partition." + exit 1 + } + else + echo "The PReP partition is not empty. If you are sure you want to use it, run dd to clear it:" + echo " dd if=/dev/zero of=${install_device}" + exit 1 + fi + fi + "$nvsetenv" boot-device "$boot_device" || { echo "$nvsetenv failed." echo "You will have to set boot-device manually. At the Open Firmware prompt, type:" @@ -608,10 +686,18 @@ elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${pla exit 1 } fi +elif [ x"${target_cpu}-${platform}" = xmips-arc ]; then + dvhtool -d "${install_device}" --unix-to-vh "{grubdir}/core.${imgext}" grub + echo "You will have to set SystemPartition and OSLoader manually." elif [ x"$platform" = xefi ]; then - cp ${grubdir}/core.${imgext} ${efidir}/${efi_file} + cp "${grubdir}/core.${imgext}" "${efidir}/${efi_file}" + # For old macs. Suggested by Peter Jones. + if [ x$target_cpu = xi386 ]; then + cp "${grubdir}/core.${imgext}" "${efidir}/boot.efi" + fi # Try to make this image bootable using the EFI Boot Manager, if available. + efibootmgr="`which efibootmgr`" if test "$removable" = no && test -n "$efi_distributor" && \ test -n "$efibootmgr"; then # On Linux, we need the efivars kernel modules. @@ -632,16 +718,18 @@ elif [ x"$platform" = xefi ]; then # Use fresh device map text to avoid any problems with stale data, since # all we need here is a one-to-one mapping. clean_devmap="$($grub_mkdevicemap --device-map=/dev/stdout)" - efidir_drive="$(echo "$clean_devmap" | $grub_probe --target=drive --device-map=/dev/stdin "$efidir")" + efidir_drive="$(echo "$clean_devmap" | "$grub_probe" --device-map="${device_map}" --target=drive --device-map=/dev/stdin "$efidir")" if test -z "$efidir_drive"; then echo "Can't find GRUB drive for $efidir; unable to create EFI Boot Manager entry." >&2 else efidir_disk="$(echo "$clean_devmap" | grep "^$(echo "$efidir_drive" | sed 's/,[^)]*//')" | cut -f2)" efidir_part="$(echo "$efidir_drive" | sed 's/^([^,]*,[^0-9]*//; s/[^0-9].*//')" efibootmgr $efi_quiet -c -d "$efidir_disk" -p "$efidir_part" -w \ - -L "$GRUB_DISTRIBUTOR" -l "\\EFI\\$efi_distributor\\$efi_file" + -L "$bootloader_id" -l "\\EFI\\$efi_distributor\\$efi_file" fi fi +else + echo "WARNING: no platform-specific install was performed" fi echo "Installation finished. No error reported." diff --git a/util/grub-kbdcomp.in b/util/grub-kbdcomp.in index 87b24bcdf..05e516d23 100644 --- a/util/grub-kbdcomp.in +++ b/util/grub-kbdcomp.in @@ -1,5 +1,11 @@ #!/bin/sh +transform="@program_transform_name@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +bindir="@bindir@" + grub_mklayout=${bindir}/`echo grub-mklayout | sed ${transform}` ckbcomp "$@" | $grub_mklayout -o "$1".gkb diff --git a/util/grub-macho2img.c b/util/grub-macho2img.c index bce0a06d1..6dfb5fcbe 100644 --- a/util/grub-macho2img.c +++ b/util/grub-macho2img.c @@ -25,6 +25,8 @@ #include #include +/* Please don't internationalise this file. It's pointless. */ + /* XXX: this file assumes particular Mach-O layout and does no checks. */ /* However as build system ensures correct usage of this tool this shouldn't be a problem. */ diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c index e29c6b17c..aeabad976 100644 --- a/util/grub-menulst2cfg.c +++ b/util/grub-menulst2cfg.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include int main (int argc, char **argv) @@ -36,7 +38,7 @@ main (int argc, char **argv) if (argc >= 2 && argv[1][0] == '-') { - fprintf (stdout, "Usage: %s [INFILE [OUTFILE]]\n", argv[0]); + fprintf (stdout, _("Usage: %s [INFILE [OUTFILE]]\n"), argv[0]); return 0; } @@ -45,7 +47,7 @@ main (int argc, char **argv) in = fopen (argv[1], "r"); if (!in) { - fprintf (stderr, "Couldn't open %s for reading: %s\n", + fprintf (stderr, _("Couldn't open %s for reading: %s\n"), argv[1], strerror (errno)); return 1; } @@ -60,7 +62,7 @@ main (int argc, char **argv) { if (in != stdin) fclose (in); - fprintf (stderr, "Couldn't open %s for writing: %s\n", + fprintf (stderr, _("Couldn't open %s for writing: %s\n"), argv[2], strerror (errno)); return 1; } @@ -78,9 +80,12 @@ main (int argc, char **argv) { char *oldname = NULL; char *newsuffix; + char *ptr; + + for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); oldname = entryname; - parsed = grub_legacy_parse (buf, &entryname, &newsuffix); + parsed = grub_legacy_parse (ptr, &entryname, &newsuffix); if (newsuffix) { suffixlen += strlen (newsuffix); diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index 4a06e19bc..c7175586d 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -18,25 +18,27 @@ set -e # along with GRUB. If not, see . transform="@program_transform_name@" +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -sbindir=@sbindir@ -libdir=@libdir@ -sysconfdir=@sysconfdir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +sbindir="@sbindir@" +bindir="@bindir@" +sysconfdir="@sysconfdir@" PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ host_os=@host_os@ -datarootdir=@datarootdir@ -datadir=@datadir@ -pkgdatadir=${datadir}/`echo @PACKAGE_TARNAME@ | sed "${transform}"` +datadir="@datadir@" +pkgdatadir="${datadir}/`echo @PACKAGE_TARNAME@ | sed "${transform}"`" grub_cfg="" -grub_mkconfig_dir=${sysconfdir}/grub.d +grub_mkconfig_dir="${sysconfdir}"/grub.d self=`basename $0` -grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` -grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` +grub_probe="${sbindir}/`echo grub-probe | sed "${transform}"`" +grub_script_check="${bindir}/`echo grub-script-check | sed "${transform}"`" GRUB_PREFIX=`echo '/@bootdirname@/@grubdirname@' | sed "s,//*,/,g"` @@ -93,7 +95,7 @@ do esac done -. ${libdir}/grub/grub-mkconfig_lib +. "${datadir}/@PACKAGE@/grub-mkconfig_lib" if [ "x$EUID" = "x" ] ; then EUID=`id -u` @@ -116,14 +118,6 @@ if [ "$EUID" != 0 ] ; then fi fi -set $grub_mkdevicemap dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - set $grub_probe dummy if test -f "$1"; then : @@ -134,10 +128,6 @@ fi mkdir -p ${GRUB_PREFIX} -if test -e ${GRUB_PREFIX}/device.map ; then : ; else - ${grub_mkdevicemap} -fi - # Device containing our userland. Typically used for root= parameter. GRUB_DEVICE="`${grub_probe} --target=device /`" GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true @@ -168,20 +158,6 @@ fi for x in ${GRUB_TERMINAL_OUTPUT}; do if [ "x${x}" = "xgfxterm" ]; then - # If this platform supports gfxterm, try to use it. - if ! test -e ${GRUB_PREFIX}/gfxterm.mod ; then - if [ "x$termoutdefault" != "x1" ]; then - echo "gfxterm isn't available on your platform" >&2 ; exit 1 - fi - GRUB_TERMINAL_OUTPUT= - break; - fi - if [ ! -s "${GRUB_PREFIX}/video.lst" ] ; then - if [ "x$termoutdefault" != "x1" ]; then - echo "No suitable backend could be found for gfxterm." >&2 ; exit 1 - fi - GRUB_TERMINAL_OUTPUT= - fi if [ -n "$GRUB_FONT" ] ; then if is_path_readable_by_grub ${GRUB_FONT} > /dev/null ; then GRUB_FONT_PATH=${GRUB_FONT} @@ -251,14 +227,15 @@ export GRUB_DEFAULT \ GRUB_CMDLINE_LINUX_DEFAULT \ GRUB_CMDLINE_XEN \ GRUB_CMDLINE_XEN_DEFAULT \ + GRUB_CMDLINE_LINUX_XEN_REPLACE \ + GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT \ GRUB_CMDLINE_NETBSD \ GRUB_CMDLINE_NETBSD_DEFAULT \ GRUB_TERMINAL_INPUT \ GRUB_TERMINAL_OUTPUT \ GRUB_SERIAL_COMMAND \ GRUB_DISABLE_LINUX_UUID \ - GRUB_DISABLE_LINUX_RECOVERY \ - GRUB_DISABLE_NETBSD_RECOVERY \ + GRUB_DISABLE_RECOVERY \ GRUB_VIDEO_BACKEND \ GRUB_GFXMODE \ GRUB_BACKGROUND \ @@ -267,6 +244,7 @@ export GRUB_DEFAULT \ GRUB_DISABLE_OS_PROBER \ GRUB_INIT_TUNE \ GRUB_SAVEDEFAULT \ + GRUB_ENABLE_CRYPTODISK \ GRUB_BADRAM if test "x${grub_cfg}" != "x"; then @@ -293,6 +271,8 @@ for i in ${grub_mkconfig_dir}/* ; do case "$i" in # emacsen backup files. FIXME: support other editors *~) ;; + # emacsen autosave files. FIXME: support other editors + \#*\#) ;; *) if grub_file_is_not_garbage "$i" && test -x "$i" ; then echo @@ -305,7 +285,7 @@ for i in ${grub_mkconfig_dir}/* ; do done if test "x${grub_cfg}" != "x" ; then - if ! grub-script-check ${grub_cfg}.new; then + if ! ${grub_script_check} ${grub_cfg}.new; then echo "Syntax errors are detected in generated GRUB config file." >&2 echo "Ensure that there are no errors in /etc/default/grub" >&2 echo "and /etc/grub.d/* files or please file a bug report with" >&2 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 41359975e..0b77dc38c 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -16,19 +16,19 @@ transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -datarootdir=@datarootdir@ -datadir=@datadir@ -bindir=@bindir@ -sbindir=@sbindir@ -pkgdatadir=${datadir}/`echo @PACKAGE_TARNAME@ | sed "${transform}"` +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +datadir="@datadir@" +bindir="@bindir@" +sbindir="@sbindir@" +pkgdatadir="${datadir}/`echo "@PACKAGE_TARNAME@" | sed "${transform}"`" if test "x$grub_probe" = x; then - grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` + grub_probe="${sbindir}/`echo grub-probe | sed "${transform}"`" fi if test "x$grub_mkrelpath" = x; then - grub_mkrelpath=${bindir}/`echo grub-mkrelpath | sed ${transform}` + grub_mkrelpath="${bindir}/`echo grub-mkrelpath | sed "${transform}"`" fi if $(which gettext >/dev/null 2>/dev/null) ; then @@ -44,46 +44,64 @@ grub_warn () make_system_path_relative_to_its_root () { - ${grub_mkrelpath} $1 + "${grub_mkrelpath}" "$1" } is_path_readable_by_grub () { - path=$1 + path="$1" # abort if path doesn't exist - if test -e $path ; then : ;else + if test -e "$path" ; then : ;else return 1 fi # abort if file is in a filesystem we can't read - if ${grub_probe} -t fs $path > /dev/null 2>&1 ; then : ; else + if "${grub_probe}" -t fs "$path" > /dev/null 2>&1 ; then : ; else return 1 fi + # ... or if we can't figure out the abstraction module, for example if + # memberlist fails on an LVM volume group. + if abstractions="`"${grub_probe}" -t abstraction "$path"`" 2>&1 ; then + : + else + return 1 + fi + + if [ x$GRUB_CRYPTODISK_ENABLE = xy ]; then + return 0 + fi + + for abstraction in $abstractions; do + if [ "x$abstraction" = xcryptodisk ]; then + return 1 + fi + done + return 0 } convert_system_path_to_grub_path () { - path=$1 + path="$1" grub_warn "convert_system_path_to_grub_path() is deprecated. Use prepare_grub_to_access_device() instead." # abort if GRUB can't access the path - if is_path_readable_by_grub ${path} ; then : ; else + if is_path_readable_by_grub "${path}" ; then : ; else return 1 fi - if drive=`${grub_probe} -t drive $path` ; then : ; else + if drive="`"${grub_probe}" -t drive "$path"`" ; then : ; else return 1 fi - if relative_path=`make_system_path_relative_to_its_root $path` ; then : ; else + if relative_path="`make_system_path_relative_to_its_root "$path"`" ; then : ; else return 1 fi - echo ${drive}${relative_path} + echo "${drive}${relative_path}" } save_default_entry () @@ -97,29 +115,48 @@ EOF prepare_grub_to_access_device () { - device=$1 + device="$1" + + partmap="`"${grub_probe}" --device "${device}" --target=partmap`" + for module in ${partmap} ; do + case "${module}" in + netbsd | openbsd) + echo "insmod part_bsd";; + *) + echo "insmod part_${module}";; + esac + done # Abstraction modules aren't auto-loaded. - abstraction="`${grub_probe} --device ${device} --target=abstraction`" + abstraction="`"${grub_probe}" --device "${device}" --target=abstraction`" for module in ${abstraction} ; do echo "insmod ${module}" done - partmap="`${grub_probe} --device ${device} --target=partmap`" - for module in ${partmap} ; do - echo "insmod part_${module}" - done - - fs="`${grub_probe} --device ${device} --target=fs`" + fs="`"${grub_probe}" --device "${device}" --target=fs`" for module in ${fs} ; do echo "insmod ${module}" done + if [ x$GRUB_CRYPTODISK_ENABLE = xy ]; then + for uuid in "`"${grub_probe}" --device "${device}" --target=cryptodisk_uuid`"; do + echo "cryptomount -u $uuid" + done + fi + # If there's a filesystem UUID that GRUB is capable of identifying, use it; # otherwise set root as per value in device.map. - echo "set root='`${grub_probe} --device ${device} --target=drive`'" - if fs_uuid="`${grub_probe} --device ${device} --target=fs_uuid 2> /dev/null`" ; then - echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" + fs_hint="`"${grub_probe}" --device "${device}" --target=compatibility_hint`" + if [ "x$fs_hint" != x ]; then + echo "set root='$fs_hint'" + fi + if fs_uuid="`"${grub_probe}" --device "${device}" --target=fs_uuid 2> /dev/null`" ; then + hints="`"${grub_probe}" --device "${device}" --target=hints_string 2> /dev/null`" + echo "if [ x\$feature_platform_search_hint = xy ]; then" + echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" + echo "else" + echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" + echo "fi" fi } @@ -128,7 +165,7 @@ grub_file_is_not_garbage () if test -f "$1" ; then case "$1" in *.dpkg-*) return 1 ;; # debian dpkg - README*) return 1 ;; # documentation + README*|*/README*) return 1 ;; # documentation esac else return 1 @@ -138,21 +175,21 @@ grub_file_is_not_garbage () version_test_numeric () { - local a=$1 - local cmp=$2 - local b=$3 - if [ "$a" = "$b" ] ; then - case $cmp in + version_test_numeric_a="$1" + version_test_numeric_cmp="$2" + version_test_numeric_b="$3" + if [ "$version_test_numeric_a" = "$version_test_numeric_b" ] ; then + case "$version_test_numeric_cmp" in ge|eq|le) return 0 ;; gt|lt) return 1 ;; esac fi - if [ "$cmp" = "lt" ] ; then - c=$a - a=$b - b=$c + if [ "$version_test_numeric_cmp" = "lt" ] ; then + version_test_numeric_c="$version_test_numeric_a" + version_test_numeric_a="$version_test_numeric_b" + version_test_numeric_b="$version_test_numeric_c" fi - if (echo $a ; echo $b) | sort -n | head -n 1 | grep -qx $b ; then + if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | sort -n | head -n 1 | grep -qx "$version_test_numeric_b" ; then return 0 else return 1 @@ -161,40 +198,52 @@ version_test_numeric () version_test_gt () { - local a=`echo $1 | sed -e "s/[^-]*-//"` - local b=`echo $2 | sed -e "s/[^-]*-//"` - local cmp=gt - if [ "x$b" = "x" ] ; then + version_test_gt_a="`echo "$1" | sed -e "s/[^-]*-//"`" + version_test_gt_b="`echo "$2" | sed -e "s/[^-]*-//"`" + version_test_gt_cmp=gt + if [ "x$version_test_gt_b" = "x" ] ; then return 0 fi - case $a:$b in + case "$version_test_gt_a:$version_test_gt_b" in *.old:*.old) ;; - *.old:*) a=`echo -n $a | sed -e s/\.old$//` ; cmp=gt ;; - *:*.old) b=`echo -n $b | sed -e s/\.old$//` ; cmp=ge ;; + *.old:*) version_test_gt_a="`echo -n "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo -n "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; esac - version_test_numeric $a $cmp $b - return $? + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" } version_find_latest () { - local a="" - for i in $@ ; do - if version_test_gt "$i" "$a" ; then - a="$i" + version_find_latest_a="" + for i in "$@" ; do + if version_test_gt "$i" "$version_find_latest_a" ; then + version_find_latest_a="$i" fi done - echo "$a" + echo "$version_find_latest_a" } +# One layer of quotation is eaten by "", the second by sed, and the third by +# printf; so this turns ' into \'. Note that you must use the output of +# this function in a printf format string. gettext_quoted () { - $gettext "$@" | sed "s/'/'\\\\''/g" + "$gettext" "$@" | sed "s/'/'\\\\\\\\''/g" +} + +# Run the first argument through gettext_quoted, and then pass that and all +# remaining arguments to printf. This is a useful abbreviation and tends to +# be easier to type. +gettext_printf () { + gettext_printf_format="$1" + shift + printf "$(gettext_quoted "$gettext_printf_format")" "$@" } uses_abstraction () { - device=$1 + device="$1" - abstraction="`${grub_probe} --device ${device} --target=abstraction`" + abstraction="`"${grub_probe}" --device "${device}" --target=abstraction`" for module in ${abstraction}; do if test "x${module}" = "x$2"; then return 0 diff --git a/util/grub-mkdevicemap.c b/util/grub-mkdevicemap.c index bdecae4a3..bdf8ef1c6 100644 --- a/util/grub-mkdevicemap.c +++ b/util/grub-mkdevicemap.c @@ -62,7 +62,7 @@ make_device_map (const char *device_map, int floppy_disks) fp = fopen (device_map, "w"); if (! fp) - grub_util_error ("cannot open %s", device_map); + grub_util_error (_("cannot open %s"), device_map); grub_util_iterate_devices (process_device, floppy_disks); @@ -86,9 +86,9 @@ usage (int status) { if (status) fprintf (stderr, - "Try `%s --help' for more information.\n", program_name); + _("Try `%s --help' for more information.\n"), program_name); else - printf ("\ + printf (_("\ Usage: %s [OPTION]...\n\ \n\ Generate a device map file automatically.\n\ @@ -101,7 +101,7 @@ Generate a device map file automatically.\n\ -v, --verbose print verbose messages\n\ \n\ Report bugs to <%s>.\n\ -", program_name, +"), program_name, DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); exit (status); diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c index 3e24380d1..1fad15660 100644 --- a/util/grub-mkfont.c +++ b/util/grub-mkfont.c @@ -121,9 +121,10 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); else - printf ("\ + printf (_("\ Usage: %s [OPTIONS] FONT_FILES\n\ \nOptions:\n\ -o, --output=FILE_NAME set output file name\n\ @@ -143,7 +144,7 @@ Usage: %s [OPTIONS] FONT_FILES\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ \n\ -Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); +Report bugs to <%s>.\n"), program_name, PACKAGE_BUGREPORT); exit (status); } @@ -188,12 +189,12 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, err = FT_Load_Glyph (face, glyph_idx, flag); if (err) { - printf ("Freetype Error %d loading glyph 0x%x for U+0x%x%s", + printf (_("Freetype Error %d loading glyph 0x%x for U+0x%x%s"), err, glyph_idx, char_code & GRUB_FONT_CODE_CHAR_MASK, char_code & GRUB_FONT_CODE_RIGHT_JOINED - ? ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? " (medial)": - " (leftmost)") - : ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? " (rightmost)": + ? ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? _(" (medial)"): + _(" (leftmost)")) + : ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? _(" (rightmost)"): "")); if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) @@ -519,7 +520,7 @@ process_cursive (struct gsub_feature *feature, if (substtype == GSUB_SUBSTITUTION_DELTA) add_subst (glyph, glyph + grub_be_to_cpu16 (sub->delta), target); else if (i >= grub_be_to_cpu16 (sub->count)) - printf ("Out of range substitution (%d, %d)\n", i, + printf (_("Out of range substitution (%d, %d)\n"), i, grub_be_to_cpu16 (sub->count)); else add_subst (glyph, grub_be_to_cpu16 (sub->repl[i++]), target); @@ -531,7 +532,7 @@ process_cursive (struct gsub_feature *feature, struct gsub_lookup *lookup; if (lookup_index >= grub_be_to_cpu16 (lookups->count)) { - printf ("Out of range lookup: %d\n", lookup_index); + printf (_("Out of range lookup: %d\n"), lookup_index); continue; } lookup = (struct gsub_lookup *) @@ -539,13 +540,13 @@ process_cursive (struct gsub_feature *feature, + grub_be_to_cpu16 (lookups->offsets[lookup_index])); if (grub_be_to_cpu16 (lookup->type) != GSUB_SINGLE_SUBSTITUTION) { - printf ("Unsupported substitution type: %d\n", + printf (_("Unsupported substitution type: %d\n"), grub_be_to_cpu16 (lookup->type)); continue; } if (grub_be_to_cpu16 (lookup->flag) & ~GSUB_RTL_CHAR) { - printf ("Unsupported substitution flag: 0x%x\n", + printf (_("Unsupported substitution flag: 0x%x\n"), grub_be_to_cpu16 (lookup->flag)); } switch (feattag) @@ -575,7 +576,7 @@ process_cursive (struct gsub_feature *feature, if (substtype != GSUB_SUBSTITUTION_MAP && substtype != GSUB_SUBSTITUTION_DELTA) { - printf ("Unsupported substitution specification: %d\n", + printf (_("Unsupported substitution specification: %d\n"), substtype); continue; } @@ -601,7 +602,7 @@ process_cursive (struct gsub_feature *feature, subst (m); } else - printf ("Unsupported coverage specification: %d\n", covertype); + printf (_("Unsupported coverage specification: %d\n"), covertype); } } } @@ -640,7 +641,7 @@ add_font (struct grub_font_info *font_info, FT_Face face, int nocut) grub_uint32_t feattag = grub_be_to_cpu32 (features->features[i].feature_tag); if (feature->params) - printf ("WARNING: unsupported feature parameters: %x\n", + printf (_("WARNING: unsupported feature parameters: %x\n"), grub_be_to_cpu16 (feature->params)); switch (feattag) { @@ -670,7 +671,7 @@ add_font (struct grub_font_info *font_info, FT_Face face, int nocut) for (j = 0; j < 4; j++) if (!grub_isgraph (str[j])) str[j] = '?'; - printf ("Unknown gsub feature 0x%x (%s)\n", feattag, str); + printf (_("Unknown gsub feature 0x%x (%s)\n"), feattag, str); } } } @@ -739,8 +740,8 @@ print_glyphs (struct grub_font_info *font_info) int x, y, xmax, xmin, ymax, ymin; grub_uint8_t *bitmap, mask; - printf ("\nGlyph #%d, U+%04x\n", num, glyph->char_code); - printf ("Width %d, Height %d, X offset %d, Y offset %d, Device width %d\n", + printf (_("\nGlyph #%d, U+%04x\n"), num, glyph->char_code); + printf (_("Width %d, Height %d, X offset %d, Y offset %d, Device width %d\n"), glyph->width, glyph->height, glyph->x_ofs, glyph->y_ofs, glyph->device_width); @@ -807,7 +808,7 @@ write_font_ascii_bitmap (struct grub_font_info *font_info, char *output_file) file = fopen (output_file, "wb"); if (! file) - grub_util_error ("Can\'t write to file %s.", output_file); + grub_util_error (_("Can\'t write to file %s."), output_file); int correct_size; for (glyph = font_info->glyphs_sorted, num = 0; num < font_info->num_glyphs; @@ -843,7 +844,7 @@ write_font_width_spec (struct grub_font_info *font_info, char *output_file) file = fopen (output_file, "wb"); if (! file) - grub_util_error ("Can\'t write to file %s.", output_file); + grub_util_error (_("Can\'t write to file %s."), output_file); for (glyph = font_info->glyphs_sorted; glyph < font_info->glyphs_sorted + font_info->num_glyphs; glyph++) @@ -859,14 +860,14 @@ void write_font_pf2 (struct grub_font_info *font_info, char *output_file) { FILE *file; - grub_uint32_t leng, data; + grub_uint32_t leng; char style_name[20], *font_name; int offset; struct grub_glyph_info *cur; file = fopen (output_file, "wb"); if (! file) - grub_util_error ("can\'t write to file %s.", output_file); + grub_util_error (_("Can\'t write to file %s."), output_file); offset = 0; @@ -959,12 +960,14 @@ write_font_pf2 (struct grub_font_info *font_info, char *output_file) for (cur = font_info->glyphs_sorted; cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++) { - data = grub_cpu_to_be32 (cur->char_code); - grub_util_write_image ((char *) &data, 4, file); - data = 0; - grub_util_write_image ((char *) &data, 1, file); - data = grub_cpu_to_be32 (offset); - grub_util_write_image ((char *) &data, 4, file); + grub_uint32_t data32; + grub_uint8_t data8; + data32 = grub_cpu_to_be32 (cur->char_code); + grub_util_write_image ((char *) &data32, 4, file); + data8 = 0; + grub_util_write_image ((char *) &data8, 1, file); + data32 = grub_cpu_to_be32 (offset); + grub_util_write_image ((char *) &data32, 4, file); offset += 10 + cur->bitmap_size; } @@ -976,6 +979,7 @@ write_font_pf2 (struct grub_font_info *font_info, char *output_file) for (cur = font_info->glyphs_sorted; cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++) { + grub_uint16_t data; data = grub_cpu_to_be16 (cur->width); grub_util_write_image ((char *) &data, 2, file); data = grub_cpu_to_be16 (cur->height); @@ -1060,7 +1064,7 @@ main (int argc, char *argv[]) a = strtoul (p, &p, 0); if (*p != '-') - grub_util_error ("invalid font range"); + grub_util_error (_("invalid font range")); b = strtoul (p + 1, &p, 0); if ((font_info.num_range & (GRUB_FONT_RANGE_BLOCK - 1)) == 0) font_info.ranges = xrealloc (font_info.ranges, @@ -1075,7 +1079,7 @@ main (int argc, char *argv[]) if (*p) { if (*p != ',') - grub_util_error ("invalid font range"); + grub_util_error (_("invalid font range")); else p++; } @@ -1121,7 +1125,7 @@ main (int argc, char *argv[]) if (file_format == ASCII_BITMAPS && font_info.num_range > 0) { - grub_util_error ("Option --ascii-bitmaps doesn't accept ranges (use ASCII)."); + grub_util_error (_("Option --ascii-bitmaps doesn't accept ranges (use ASCII).")); return 1; } @@ -1137,20 +1141,27 @@ main (int argc, char *argv[]) } if (! output_file) - grub_util_error ("no output file is specified"); + grub_util_error (_("no output file is specified")); if (FT_Init_FreeType (&ft_lib)) - grub_util_error ("FT_Init_FreeType fails"); + grub_util_error (_("FT_Init_FreeType fails")); for (; optind < argc; optind++) { FT_Face ft_face; int size; + FT_Error err; - if (FT_New_Face (ft_lib, argv[optind], font_index, &ft_face)) + err = FT_New_Face (ft_lib, argv[optind], font_index, &ft_face); + if (err) { - grub_util_info ("can't open file %s, index %d", argv[optind], - font_index); + grub_printf (_("can't open file %s, index %d: error %d"), + argv[optind], font_index, err); + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + printf (": %s\n", ft_errmsgs[err]); + else + printf ("\n"); + continue; } @@ -1170,7 +1181,8 @@ main (int argc, char *argv[]) font_info.style = ft_face->style_flags; font_info.size = size; - FT_Set_Pixel_Sizes (ft_face, size, size); + if (FT_Set_Pixel_Sizes (ft_face, size, size)) + grub_util_error (_("can't set %dx%d font size"), size, size); add_font (&font_info, ft_face, file_format != PF2); FT_Done_Face (ft_face); } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 53e867602..ca8047df6 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -29,7 +29,10 @@ #include #include #include +#include +#include #include +#include #include #include @@ -52,60 +55,64 @@ #define TARGET_NO_FIELD 0xffffffff typedef enum { - COMPRESSION_AUTO, COMPRESSION_NONE, COMPRESSION_XZ + COMPRESSION_AUTO, COMPRESSION_NONE, COMPRESSION_XZ, COMPRESSION_LZMA } grub_compression_t; struct image_target_desc { - const char *name; + const char *dirname; + const char *names[6]; grub_size_t voidp_sizeof; int bigendian; enum { IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_I386_IEEE1275, - IMAGE_YEELOONG_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, - IMAGE_I386_PC_PXE + IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, + IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC, + IMAGE_QEMU_MIPS_FLASH } id; enum { PLATFORM_FLAGS_NONE = 0, - PLATFORM_FLAGS_LZMA = 1, - PLATFORM_FLAGS_DECOMPRESSORS = 2 + PLATFORM_FLAGS_DECOMPRESSORS = 2, + PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4, } flags; - unsigned prefix; - unsigned prefix_end; - unsigned raw_size; unsigned total_module_size; - unsigned kernel_image_size; - unsigned compressed_size; + unsigned decompressor_compressed_size; + unsigned decompressor_uncompressed_size; + unsigned decompressor_uncompressed_addr; unsigned link_align; grub_uint16_t elf_target; unsigned section_align; signed vaddr_offset; - unsigned install_dos_part, install_bsd_part; grub_uint64_t link_addr; unsigned mod_gap, mod_align; grub_compression_t default_compression; + grub_uint16_t pe_target; }; +#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE \ + + GRUB_PE32_SIGNATURE_SIZE \ + + sizeof (struct grub_pe32_coff_header) \ + + sizeof (struct grub_pe64_optional_header) \ + + 4 * sizeof (struct grub_pe32_section_table), \ + GRUB_PE32_SECTION_ALIGNMENT) + struct image_target_desc image_targets[] = { { - .name = "i386-coreboot", + .dirname = "i386-coreboot", + .names = { "i386-coreboot", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_COREBOOT, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_I386_COREBOOT_PREFIX, - .prefix_end = GRUB_KERNEL_I386_COREBOOT_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, .elf_target = EM_386, .link_align = 4, @@ -113,21 +120,18 @@ struct image_target_desc image_targets[] = .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN }, { - .name = "i386-multiboot", + .dirname = "i386-multiboot", + .names = { "i386-multiboot", NULL}, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_COREBOOT, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_I386_MULTIBOOT_PREFIX, - .prefix_end = GRUB_KERNEL_I386_MULTIBOOT_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, .elf_target = EM_386, .link_align = 4, @@ -135,53 +139,46 @@ struct image_target_desc image_targets[] = .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN }, { - .name = "i386-pc", + .dirname = "i386-pc", + .names = { "i386-pc", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_I386_PC, - .flags = PLATFORM_FLAGS_LZMA, - .prefix = GRUB_KERNEL_I386_PC_PREFIX, - .prefix_end = GRUB_KERNEL_I386_PC_PREFIX_END, - .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, - .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, - .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, - .compressed_size = GRUB_KERNEL_I386_PC_COMPRESSED_SIZE, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = GRUB_KERNEL_I386_PC_INSTALL_DOS_PART, - .install_bsd_part = GRUB_KERNEL_I386_PC_INSTALL_BSD_PART, .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR }, { - .name = "i386-pc-pxe", + .dirname = "i386-pc", + .names = { "i386-pc-pxe", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_I386_PC_PXE, - .flags = PLATFORM_FLAGS_LZMA, - .prefix = GRUB_KERNEL_I386_PC_PREFIX, - .prefix_end = GRUB_KERNEL_I386_PC_PREFIX_END, - .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, - .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, - .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, - .compressed_size = GRUB_KERNEL_I386_PC_COMPRESSED_SIZE, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = GRUB_KERNEL_I386_PC_INSTALL_DOS_PART, - .install_bsd_part = GRUB_KERNEL_I386_PC_INSTALL_BSD_PART, .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR }, { - .name = "i386-efi", + .dirname = "i386-efi", + .names = { "i386-efi", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_EFI, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_I386_EFI_PREFIX, - .prefix_end = GRUB_KERNEL_I386_EFI_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = GRUB_PE32_SECTION_ALIGNMENT, .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE @@ -189,25 +186,22 @@ struct image_target_desc image_targets[] = + sizeof (struct grub_pe32_optional_header) + 4 * sizeof (struct grub_pe32_section_table), GRUB_PE32_SECTION_ALIGNMENT), - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, + .pe_target = GRUB_PE32_MACHINE_I386, + .elf_target = EM_386, }, { - .name = "i386-ieee1275", + .dirname = "i386-ieee1275", + .names = { "i386-ieee1275", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_I386_IEEE1275, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_I386_IEEE1275_PREFIX, - .prefix_end = GRUB_KERNEL_I386_IEEE1275_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR, .elf_target = EM_386, .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP, @@ -215,103 +209,105 @@ struct image_target_desc image_targets[] = .link_align = 4, }, { - .name = "i386-qemu", + .dirname = "i386-qemu", + .names = { "i386-qemu", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_QEMU, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_I386_QEMU_PREFIX, - .prefix_end = GRUB_KERNEL_I386_QEMU_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = GRUB_KERNEL_I386_QEMU_KERNEL_IMAGE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR }, { - .name = "x86_64-efi", + .dirname = "x86_64-efi", + .names = { "x86_64-efi", NULL }, .voidp_sizeof = 8, .bigendian = 0, .id = IMAGE_EFI, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_X86_64_EFI_PREFIX, - .prefix_end = GRUB_KERNEL_X86_64_EFI_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = GRUB_PE32_SECTION_ALIGNMENT, - .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE - + GRUB_PE32_SIGNATURE_SIZE - + sizeof (struct grub_pe32_coff_header) - + sizeof (struct grub_pe64_optional_header) - + 4 * sizeof (struct grub_pe32_section_table), - GRUB_PE32_SECTION_ALIGNMENT), - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_X86_64, + .elf_target = EM_X86_64, }, { - .name = "mipsel-yeeloong-flash", + .dirname = "mipsel-loongson", + .names = { "mipsel-yeeloong-flash", NULL }, .voidp_sizeof = 4, .bigendian = 0, .id = IMAGE_YEELOONG_FLASH, .flags = PLATFORM_FLAGS_DECOMPRESSORS, - .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, - .raw_size = 0, - .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, - .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, .elf_target = EM_MIPS, - .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, .default_compression = COMPRESSION_NONE }, { - .name = "mipsel-yeeloong-elf", + .dirname = "mipsel-loongson", + .names = { "mipsel-fuloong2f-flash", NULL }, .voidp_sizeof = 4, .bigendian = 0, - .id = IMAGE_YEELOONG_ELF, + .id = IMAGE_FULOONG2F_FLASH, .flags = PLATFORM_FLAGS_DECOMPRESSORS, - .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, - .raw_size = 0, - .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, - .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, .elf_target = EM_MIPS, - .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, .default_compression = COMPRESSION_NONE }, { - .name = "powerpc-ieee1275", + .dirname = "mipsel-loongson", + .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf", + "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf", + "mipsel-fuloong-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .dirname = "powerpc-ieee1275", + .names = { "powerpc-ieee1275", NULL }, .voidp_sizeof = 4, .bigendian = 1, .id = IMAGE_PPC, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX, - .prefix_end = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END, - .raw_size = 0, .total_module_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, - .compressed_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR, .elf_target = EM_PPC, .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP, @@ -319,41 +315,142 @@ struct image_target_desc image_targets[] = .link_align = 4 }, { - .name = "sparc64-ieee1275-raw", + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-raw", NULL }, .voidp_sizeof = 8, .bigendian = 1, .id = IMAGE_SPARC64_RAW, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, - .prefix_end = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END, - .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, - .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, - .compressed_size = GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR }, { - .name = "sparc64-ieee1275-aout", + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-aout", NULL }, .voidp_sizeof = 8, .bigendian = 1, .id = IMAGE_SPARC64_AOUT, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, - .prefix_end = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END, - .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, - .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, - .compressed_size = GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, .section_align = 1, .vaddr_offset = 0, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR }, + { + .dirname = "ia64-efi", + .names = {"ia64-efi", NULL}, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_IA64, + .elf_target = EM_IA_64, + }, + { + .dirname = "mips-arc", + .names = {"mips-arc", NULL}, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_MIPS_ARC, + .flags = (PLATFORM_FLAGS_DECOMPRESSORS + | PLATFORM_FLAGS_MODULES_BEFORE_KERNEL), + .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .dirname = "mipsel-qemu_mips", + .names = { "mipsel-qemu_mips-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .dirname = "mips-qemu_mips", + .names = { "mips-qemu_mips-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_QEMU_MIPS_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .dirname = "mipsel-qemu_mips", + .names = { "mipsel-qemu_mips-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU_MIPS_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .dirname = "mips-qemu_mips", + .names = { "mips-qemu_mips-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, }; #define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x))) @@ -476,7 +573,7 @@ static ISzAlloc g_Alloc = { SzAlloc, SzFree }; static void compress_kernel_lzma (char *kernel_img, size_t kernel_size, - char **core_img, size_t *core_size, size_t raw_size) + char **core_img, size_t *core_size) { CLzmaEncProps props; unsigned char out_props[5]; @@ -489,27 +586,21 @@ compress_kernel_lzma (char *kernel_img, size_t kernel_size, props.pb = 2; props.numThreads = 1; - if (kernel_size < raw_size) - grub_util_error (_("the core image is too small")); - *core_img = xmalloc (kernel_size); - memcpy (*core_img, kernel_img, raw_size); - *core_size = kernel_size - raw_size; - if (LzmaEncode ((unsigned char *) *core_img + raw_size, core_size, - (unsigned char *) kernel_img + raw_size, - kernel_size - raw_size, + *core_size = kernel_size; + if (LzmaEncode ((unsigned char *) *core_img, core_size, + (unsigned char *) kernel_img, + kernel_size, &props, out_props, &out_props_size, 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK) grub_util_error (_("cannot compress the kernel image")); - - *core_size += raw_size; } #ifdef HAVE_LIBLZMA static void compress_kernel_xz (char *kernel_img, size_t kernel_size, - char **core_img, size_t *core_size, size_t raw_size) + char **core_img, size_t *core_size) { lzma_stream strm = LZMA_STREAM_INIT; lzma_ret xzret; @@ -530,20 +621,16 @@ compress_kernel_xz (char *kernel_img, size_t kernel_size, { .id = LZMA_VLI_UNKNOWN, .options = NULL} }; - if (kernel_size < raw_size) - grub_util_error (_("the core image is too small")); - xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE); if (xzret != LZMA_OK) grub_util_error (_("cannot compress the kernel image")); *core_img = xmalloc (kernel_size); - memcpy (*core_img, kernel_img, raw_size); - *core_size = kernel_size - raw_size; - strm.next_in = (unsigned char *) kernel_img + raw_size; - strm.avail_in = kernel_size - raw_size; - strm.next_out = (unsigned char *) *core_img + raw_size; + *core_size = kernel_size; + strm.next_in = (unsigned char *) kernel_img; + strm.avail_in = kernel_size; + strm.next_out = (unsigned char *) *core_img; strm.avail_out = *core_size; while (1) @@ -557,8 +644,6 @@ compress_kernel_xz (char *kernel_img, size_t kernel_size, } *core_size -= strm.avail_out; - - *core_size += raw_size; } #endif @@ -567,26 +652,27 @@ compress_kernel (struct image_target_desc *image_target, char *kernel_img, size_t kernel_size, char **core_img, size_t *core_size, grub_compression_t comp) { - if (image_target->flags & PLATFORM_FLAGS_LZMA) - { - compress_kernel_lzma (kernel_img, kernel_size, core_img, - core_size, image_target->raw_size); - return; - } + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp == COMPRESSION_LZMA)) + { + compress_kernel_lzma (kernel_img, kernel_size, core_img, + core_size); + return; + } #ifdef HAVE_LIBLZMA if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS && (comp == COMPRESSION_XZ)) { compress_kernel_xz (kernel_img, kernel_size, core_img, - core_size, image_target->raw_size); + core_size); return; } #endif if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS && (comp != COMPRESSION_NONE)) - grub_util_error ("unknown compression %d\n", comp); + grub_util_error (_("unknown compression %d\n"), comp); *core_img = xmalloc (kernel_size); memcpy (*core_img, kernel_img, kernel_size); @@ -617,6 +703,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], char *kernel_img, *core_img; size_t kernel_size, total_module_size, core_size, exec_size; size_t memdisk_size = 0, config_size = 0, config_size_pure = 0; + size_t prefix_size = 0; char *kernel_path; size_t offset; struct grub_util_path_list *path_list, *p, *next; @@ -624,10 +711,15 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], grub_uint64_t start_address; void *rel_section; grub_size_t reloc_size, align; + size_t decompress_size; if (comp == COMPRESSION_AUTO) comp = image_target->default_compression; + if (image_target->id == IMAGE_I386_PC + || image_target->id == IMAGE_I386_PC_PXE) + comp = COMPRESSION_LZMA; + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); kernel_path = grub_util_get_path (dir, "kernel.img"); @@ -652,6 +744,12 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], total_module_size += config_size + sizeof (struct grub_module_header); } + if (prefix) + { + prefix_size = ALIGN_ADDR (strlen (prefix) + 1); + total_module_size += prefix_size + sizeof (struct grub_module_header); + } + for (p = path_list; p; p = p->next) total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name)) + sizeof (struct grub_module_header)); @@ -667,31 +765,47 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], total_module_size, &start_address, &rel_section, &reloc_size, &align, image_target); - if (image_target->prefix + strlen (prefix) + 1 > image_target->prefix_end) - grub_util_error (_("prefix is too long")); - strcpy (kernel_img + image_target->prefix, prefix); + if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + && (image_target->total_module_size != TARGET_NO_FIELD)) + *((grub_uint32_t *) (kernel_img + image_target->total_module_size)) + = grub_host_to_target32 (total_module_size); + + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + memmove (kernel_img + total_module_size, kernel_img, kernel_size); if (image_target->voidp_sizeof == 8) { /* Fill in the grub_module_info structure. */ struct grub_module_info64 *modinfo; - modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + modinfo = (struct grub_module_info64 *) kernel_img; + else + modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size); memset (modinfo, 0, sizeof (struct grub_module_info64)); modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64)); modinfo->size = grub_host_to_target_addr (total_module_size); - offset = kernel_size + sizeof (struct grub_module_info64); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + offset = sizeof (struct grub_module_info64); + else + offset = kernel_size + sizeof (struct grub_module_info64); } else { /* Fill in the grub_module_info structure. */ struct grub_module_info32 *modinfo; - modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + modinfo = (struct grub_module_info32 *) kernel_img; + else + modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size); memset (modinfo, 0, sizeof (struct grub_module_info32)); modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32)); modinfo->size = grub_host_to_target_addr (total_module_size); - offset = kernel_size + sizeof (struct grub_module_info32); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + offset = sizeof (struct grub_module_info32); + else + offset = kernel_size + sizeof (struct grub_module_info32); } for (p = path_list; p; p = p->next) @@ -742,14 +856,25 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], offset += config_size; } - if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) - && (image_target->total_module_size != TARGET_NO_FIELD)) - *((grub_uint32_t *) (kernel_img + image_target->total_module_size)) - = grub_host_to_target32 (total_module_size); + if (prefix) + { + 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_PREFIX); + header->size = grub_host_to_target32 (prefix_size + sizeof (*header)); + offset += sizeof (*header); + + grub_memset (kernel_img + offset, 0, prefix_size); + grub_strcpy (kernel_img + offset, prefix); + offset += prefix_size; + } grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size); compress_kernel (image_target, kernel_img, kernel_size + total_module_size, &core_img, &core_size, comp); + free (kernel_img); grub_util_info ("the core size is 0x%x", core_size); @@ -757,30 +882,12 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], && image_target->total_module_size != TARGET_NO_FIELD) *((grub_uint32_t *) (core_img + image_target->total_module_size)) = grub_host_to_target32 (total_module_size); - if (image_target->kernel_image_size != TARGET_NO_FIELD) - *((grub_uint32_t *) (core_img + image_target->kernel_image_size)) - = grub_host_to_target32 (kernel_size); - if (image_target->compressed_size != TARGET_NO_FIELD) - *((grub_uint32_t *) (core_img + image_target->compressed_size)) - = grub_host_to_target32 (core_size - image_target->raw_size); - - /* If we included a drive in our prefix, let GRUB know it doesn't have to - prepend the drive told by BIOS. */ - if (image_target->install_dos_part != TARGET_NO_FIELD - && image_target->install_bsd_part != TARGET_NO_FIELD && prefix[0] == '(') - { - *((grub_int32_t *) (core_img + image_target->install_dos_part)) - = grub_host_to_target32 (-2); - *((grub_int32_t *) (core_img + image_target->install_bsd_part)) - = grub_host_to_target32 (-2); - } if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) { char *full_img; size_t full_size; char *decompress_path, *decompress_img; - size_t decompress_size; const char *name; switch (comp) @@ -788,23 +895,44 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], case COMPRESSION_XZ: name = "xz_decompress.img"; break; + case COMPRESSION_LZMA: + name = "lzma_decompress.img"; + break; case COMPRESSION_NONE: name = "none_decompress.img"; break; default: - grub_util_error ("unknown compression %d\n", comp); + grub_util_error (_("unknown compression %d\n"), comp); } decompress_path = grub_util_get_path (dir, name); decompress_size = grub_util_get_image_size (decompress_path); decompress_img = grub_util_read_image (decompress_path); - *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE)) - = grub_host_to_target32 (core_size); + if ((image_target->id == IMAGE_I386_PC + || image_target->id == IMAGE_I386_PC_PXE) + && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200) + grub_util_error (_("Decompressor is too big")); - *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_YEELOONG_UNCOMPRESSED_SIZE)) - = grub_host_to_target32 (kernel_size + total_module_size); + if (image_target->decompressor_compressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (decompress_img + + image_target->decompressor_compressed_size)) + = grub_host_to_target32 (core_size); + if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (decompress_img + + image_target->decompressor_uncompressed_size)) + = grub_host_to_target32 (kernel_size + total_module_size); + + if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD) + { + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr)) + = grub_host_to_target_addr (image_target->link_addr - total_module_size); + else + *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr)) + = grub_host_to_target_addr (image_target->link_addr); + } full_size = core_size + decompress_size; full_img = xmalloc (full_size); @@ -831,10 +959,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], char *boot_path, *boot_img; size_t boot_size; - if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > GRUB_MEMORY_I386_PC_UPPER) - grub_util_error (_("core image is too big (%p > %p)"), + if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000) + grub_util_error (_("core image is too big (0x%x > 0x%x)"), GRUB_KERNEL_I386_PC_LINK_ADDR + core_size, - GRUB_MEMORY_I386_PC_UPPER); + 0x78000); num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); if (num > 0xffff) @@ -844,6 +972,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], { char *pxeboot_path, *pxeboot_img; size_t pxeboot_size; + grub_uint32_t *ptr; pxeboot_path = grub_util_get_path (dir, "pxeboot.img"); pxeboot_size = grub_util_get_image_size (pxeboot_path); @@ -852,6 +981,18 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], grub_util_write_image (pxeboot_img, pxeboot_size, out); free (pxeboot_img); free (pxeboot_path); + + /* Remove Multiboot header to avoid confusing ipxe. */ + for (ptr = (grub_uint32_t *) core_img; + ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++) + if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC) + && grub_target_to_host32 (ptr[0]) + + grub_target_to_host32 (ptr[1]) + + grub_target_to_host32 (ptr[2]) == 0) + { + *ptr = 0; + break; + } } boot_path = grub_util_get_path (dir, "diskboot.img"); @@ -901,12 +1042,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], + 4 * sizeof (struct grub_pe32_section_table), GRUB_PE32_SECTION_ALIGNMENT); else - header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE - + GRUB_PE32_SIGNATURE_SIZE - + sizeof (struct grub_pe32_coff_header) - + sizeof (struct grub_pe64_optional_header) - + 4 * sizeof (struct grub_pe32_section_table), - GRUB_PE32_SECTION_ALIGNMENT); + header_size = EFI64_HEADER_SIZE; reloc_addr = ALIGN_UP (header_size + core_size, image_target->section_align); @@ -927,10 +1063,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], /* The COFF file header. */ c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE); - if (image_target->voidp_sizeof == 4) - c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_I386); - else - c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_X86_64); + c->machine = grub_host_to_target16 (image_target->pe_target); c->num_sections = grub_host_to_target16 (4); c->time = grub_host_to_target32 (time (0)); @@ -1124,6 +1257,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], aout_size = core_size + sizeof (*aout_head); aout_img = xmalloc (aout_size); aout_head = aout_img; + grub_memset (aout_head, 0, sizeof (*aout_head)); aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16) | AOUT32_OMAGIC); aout_head->a_text = grub_host_to_target32 (core_size); @@ -1148,7 +1282,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], 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) - grub_util_error ("diskboot.img is not one sector size"); + grub_util_error (_("diskboot.img is not one sector size")); boot_img = grub_util_read_image (boot_path); @@ -1162,17 +1296,63 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], } break; case IMAGE_YEELOONG_FLASH: + case IMAGE_FULOONG2F_FLASH: { char *rom_img; size_t rom_size; char *boot_path, *boot_img; size_t boot_size; - - boot_path = grub_util_get_path (dir, "fwstart.img"); + grub_uint8_t context[GRUB_MD_SHA512->contextsize]; + /* fwstart.img is the only part which can't be tested by using *-elf + target. Check it against the checksum. */ + const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + /* None yet. */ + const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + const grub_uint8_t *fwstart_good_hash; + + if (image_target->id == IMAGE_FULOONG2F_FLASH) + { + fwstart_good_hash = fuloong2f_fwstart_good_hash; + boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img"); + } + else + { + fwstart_good_hash = yeeloong_fwstart_good_hash; + boot_path = grub_util_get_path (dir, "fwstart.img"); + } + boot_size = grub_util_get_image_size (boot_path); boot_img = grub_util_read_image (boot_path); - rom_size = ALIGN_UP (core_size + boot_size, 512 * 1024); + grub_memset (context, 0, sizeof (context)); + GRUB_MD_SHA512->init (context); + GRUB_MD_SHA512->write (context, boot_img, boot_size); + GRUB_MD_SHA512->final (context); + if (grub_memcmp (GRUB_MD_SHA512->read (context), fwstart_good_hash, + GRUB_MD_SHA512->mdlen) != 0) + grub_util_warn (_("fwstart.img doesn't match the known good version. " + "proceed at your own risk")); + + if (core_size + boot_size > 512 * 1024) + grub_util_error (_("firmware image is too big")); + rom_size = 512 * 1024; rom_img = xmalloc (rom_size); memset (rom_img, 0, rom_size); @@ -1189,7 +1369,104 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], core_size = rom_size; } break; - case IMAGE_YEELOONG_ELF: + case IMAGE_QEMU_MIPS_FLASH: + { + char *rom_img; + size_t rom_size; + + if (core_size > 512 * 1024) + grub_util_error (_("firmware image is too big")); + rom_size = 512 * 1024; + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + memcpy (rom_img, core_img, core_size); + + memset (rom_img + core_size, 0, + rom_size - core_size); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + } + break; + case IMAGE_MIPS_ARC: + { + char *ecoff_img; + struct ecoff_header { + grub_uint16_t magic; + grub_uint16_t nsec; + grub_uint32_t time; + grub_uint32_t syms; + grub_uint32_t nsyms; + grub_uint16_t opt; + grub_uint16_t flags; + grub_uint16_t magic2; + grub_uint16_t version; + grub_uint32_t textsize; + grub_uint32_t datasize; + grub_uint32_t bsssize; + grub_uint32_t entry; + grub_uint32_t text_start; + grub_uint32_t data_start; + grub_uint32_t bss_start; + grub_uint32_t gprmask; + grub_uint32_t cprmask[4]; + grub_uint32_t gp_value; + }; + struct ecoff_section + { + char name[8]; + grub_uint32_t paddr; + grub_uint32_t vaddr; + grub_uint32_t size; + grub_uint32_t file_offset; + grub_uint32_t reloc; + grub_uint32_t gp; + grub_uint16_t nreloc; + grub_uint16_t ngp; + grub_uint32_t flags; + }; + struct ecoff_header *head; + struct ecoff_section *section; + grub_uint32_t target_addr; + size_t program_size; + + program_size = ALIGN_ADDR (core_size); + if (comp == COMPRESSION_NONE) + target_addr = (image_target->link_addr + - total_module_size - decompress_size); + else + target_addr = (image_target->link_addr + - ALIGN_UP(total_module_size + core_size, 1048576) + - (1 << 20)); + + ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section)); + grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section)); + head = (void *) ecoff_img; + section = (void *) (head + 1); + head->magic = grub_host_to_target16 (0x160); + head->nsec = grub_host_to_target16 (1); + head->time = grub_host_to_target32 (0); + head->opt = grub_host_to_target16 (0x38); + head->flags = grub_host_to_target16 (0x207); + head->magic2 = grub_host_to_target16 (0x107); + head->textsize = grub_host_to_target32 (program_size); + head->entry = grub_host_to_target32 (target_addr); + head->text_start = grub_host_to_target32 (target_addr); + head->data_start = grub_host_to_target32 (target_addr + program_size); + grub_memcpy (section->name, ".text", sizeof (".text") - 1); + section->vaddr = grub_host_to_target32 (target_addr); + section->size = grub_host_to_target32 (program_size); + section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section)); + memcpy (section + 1, core_img, core_size); + free (core_img); + core_img = ecoff_img; + core_size = program_size + sizeof (*head) + sizeof (*section); + } + break; + case IMAGE_LOONGSON_ELF: case IMAGE_PPC: case IMAGE_COREBOOT: case IMAGE_I386_IEEE1275: @@ -1202,7 +1479,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], int header_size, footer_size = 0; int phnum = 1; - if (image_target->id != IMAGE_YEELOONG_ELF) + if (image_target->id != IMAGE_LOONGSON_ELF) phnum += 2; if (note) @@ -1237,7 +1514,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], /* No section headers. */ ehdr->e_shoff = grub_host_to_target32 (0); - if (image_target->id == IMAGE_YEELOONG_ELF) + if (image_target->id == IMAGE_LOONGSON_ELF) ehdr->e_shentsize = grub_host_to_target16 (0); else ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr)); @@ -1250,21 +1527,26 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], phdr->p_offset = grub_host_to_target32 (header_size); phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); - if (image_target->id == IMAGE_YEELOONG_ELF) - target_addr = ALIGN_UP (image_target->link_addr - + kernel_size + total_module_size, 32); + if (image_target->id == IMAGE_LOONGSON_ELF) + { + if (comp == COMPRESSION_NONE) + target_addr = (image_target->link_addr - decompress_size); + else + target_addr = ALIGN_UP (image_target->link_addr + + kernel_size + total_module_size, 32); + } else target_addr = image_target->link_addr; ehdr->e_entry = grub_host_to_target32 (target_addr); phdr->p_vaddr = grub_host_to_target32 (target_addr); phdr->p_paddr = grub_host_to_target32 (target_addr); phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align); - if (image_target->id == IMAGE_YEELOONG_ELF) + if (image_target->id == IMAGE_LOONGSON_ELF) ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER | EF_MIPS_PIC | EF_MIPS_CPIC); else ehdr->e_flags = 0; - if (image_target->id == IMAGE_YEELOONG_ELF) + if (image_target->id == IMAGE_LOONGSON_ELF) { phdr->p_filesz = grub_host_to_target32 (core_size); phdr->p_memsz = grub_host_to_target32 (core_size); @@ -1335,7 +1617,6 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], } grub_util_write_image (core_img, core_size, out); - free (kernel_img); free (core_img); free (kernel_path); @@ -1379,12 +1660,12 @@ usage (int status) char *ptr; unsigned i; for (i = 0; i < ARRAY_SIZE (image_targets); i++) - format_len += strlen (image_targets[i].name) + 2; + format_len += strlen (image_targets[i].names[0]) + 2; ptr = formats = xmalloc (format_len); for (i = 0; i < ARRAY_SIZE (image_targets); i++) { - strcpy (ptr, image_targets[i].name); - ptr += strlen (image_targets[i].name); + strcpy (ptr, image_targets[i].names[0]); + ptr += strlen (image_targets[i].names[0]); *ptr++ = ','; *ptr++ = ' '; } @@ -1454,13 +1735,15 @@ main (int argc, char *argv[]) case 'O': { - unsigned i; + unsigned i, j; for (i = 0; i < ARRAY_SIZE (image_targets); i++) - if (strcmp (optarg, image_targets[i].name) == 0) - image_target = &image_targets[i]; + for (j = 0; image_targets[i].names[j] + && j < ARRAY_SIZE (image_targets[i].names); j++) + if (strcmp (optarg, image_targets[i].names[j]) == 0) + image_target = &image_targets[i]; if (!image_target) { - printf ("unknown target format %s\n", optarg); + printf (_("unknown target format %s\n"), optarg); usage (1); } break; @@ -1501,14 +1784,14 @@ main (int argc, char *argv[]) #ifdef HAVE_LIBLZMA comp = COMPRESSION_XZ; #else - grub_util_error ("grub-mkimage is compiled without XZ support", + grub_util_error (_("grub-mkimage is compiled without XZ support"), optarg); #endif } else if (grub_strcmp (optarg, "none") == 0) comp = COMPRESSION_NONE; else - grub_util_error ("Unknown compression format %s", optarg); + grub_util_error (_("Unknown compression format %s"), optarg); break; case 'h': @@ -1538,7 +1821,7 @@ main (int argc, char *argv[]) if (!image_target) { - printf ("Target format not specified (use the -O option).\n"); + printf (_("Target format not specified (use the -O option).\n")); usage (1); } @@ -1552,25 +1835,19 @@ main (int argc, char *argv[]) if (!dir) { - const char *last; - last = strchr (image_target->name, '-'); - if (last) - last = strchr (last + 1, '-'); - if (!last) - last = image_target->name + strlen (image_target->name); - dir = xmalloc (sizeof (GRUB_PKGLIBROOTDIR) + (last - image_target->name) - + 1); + dir = xmalloc (sizeof (GRUB_PKGLIBROOTDIR) + + grub_strlen (image_target->dirname) + 1); memcpy (dir, GRUB_PKGLIBROOTDIR, sizeof (GRUB_PKGLIBROOTDIR) - 1); *(dir + sizeof (GRUB_PKGLIBROOTDIR) - 1) = '/'; - memcpy (dir + sizeof (GRUB_PKGLIBROOTDIR), image_target->name, - last - image_target->name); - *(dir + sizeof (GRUB_PKGLIBROOTDIR) + (last - image_target->name)) = 0; + strcpy (dir + sizeof (GRUB_PKGLIBROOTDIR), image_target->dirname); } generate_image (dir, prefix ? : DEFAULT_DIRECTORY, fp, argv + optind, memdisk, config, image_target, note, comp); + fflush (fp); + fsync (fileno (fp)); fclose (fp); if (dir) diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index ce51f2fbc..352291070 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -56,6 +56,7 @@ static Elf_Addr SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Shdr *symtab_section, Elf_Addr *section_addresses, Elf_Half section_entsize, Elf_Half num_sections, + void *jumpers, Elf_Addr jumpers_addr, struct image_target_desc *image_target) { Elf_Word symtab_size, sym_size, num_syms; @@ -65,6 +66,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Word i; Elf_Shdr *strtab_section; const char *strtab; + grub_uint64_t *jptr = jumpers; strtab_section = (Elf_Shdr *) ((char *) sections @@ -101,9 +103,19 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, else if (index >= num_sections) grub_util_error ("section %d does not exist", index); - sym->st_value = (grub_target_to_host32 (sym->st_value) + sym->st_value = (grub_target_to_host (sym->st_value) + section_addresses[index]); - grub_util_info ("locating %s at 0x%x", name, sym->st_value); + + if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) + == STT_FUNC) + { + *jptr = sym->st_value; + sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr; + jptr++; + *jptr = 0; + jptr++; + } + grub_util_info ("locating %s at 0x%x", name, sym->st_value, section_addresses[index]); if (! start_address) if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) @@ -134,6 +146,152 @@ SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset, return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset); } +static Elf_Addr +SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section, + struct image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Addr start_address = 0; + Elf_Sym *sym; + Elf_Word i; + int ret = 0; + + symtab_size = grub_target_to_host (symtab_section->sh_size); + sym_size = grub_target_to_host (symtab_section->sh_entsize); + symtab_offset = grub_target_to_host (symtab_section->sh_offset); + num_syms = symtab_size / sym_size; + + for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); + i < num_syms; + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + ret++; + + return ret; +} + +#ifdef MKIMAGE_ELF64 +struct unaligned_uint32 +{ + grub_uint32_t val; +} __attribute__ ((packed)); + +#define MASK20 ((1 << 20) - 1) +#define MASK19 ((1 << 19) - 1) + +static void +add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value) +{ + struct unaligned_uint32 *p; + switch (addr & 3) + { + case 0: + p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2); + p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2) + | (p->val & ~(MASK20 << 2))); + break; + case 1: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7); + p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3) + | (p->val & ~(MASK20 << 3))); + break; + case 2: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12); + p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4) + | (p->val & ~(MASK20 << 4))); + break; + } +} + +#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) ) + +static grub_uint32_t +add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value) +{ + grub_uint32_t high, mid, low, c; + low = (a & 0x00007f); + mid = (a & 0x7fc000) >> 7; + high = (a & 0x003e00) << 7; + c = (low | mid | high) + value; + return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00 +} + +static void +add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value) +{ + struct unaligned_uint32 *p; + switch (addr & 3) + { + case 0: + p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2); + p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2)); + break; + case 1: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7); + p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3)); + break; + case 2: + p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12); + p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4)); + break; + } +} + + +struct ia64_kernel_trampoline +{ + /* nop.m */ + grub_uint8_t nop[5]; + /* movl r15 = addr*/ + grub_uint8_t addr_hi[6]; + grub_uint8_t e0; + grub_uint8_t addr_lo[4]; + grub_uint8_t jump[0x20]; +}; + +static grub_uint8_t nopm[5] = + { + /* [MLX] nop.m 0x0 */ + 0x05, 0x00, 0x00, 0x00, 0x01 + }; + +static grub_uint8_t jump[0x20] = + { + /* [MMI] add r15=r15,r1;; */ + 0x0b, 0x78, 0x3c, 0x02, 0x00, 0x20, + /* ld8 r16=[r15],8 */ + 0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0, + /* mov r14=r1;; */ + 0x01, 0x08, 0x00, 0x84, + /* [MIB] ld8 r1=[r15] */ + 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, + /* mov b6=r16 */ + 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, + /* br.few b6;; */ + 0x60, 0x00, 0x80, 0x00 + }; + +static void +make_trampoline (struct ia64_kernel_trampoline *tr, grub_uint64_t addr) +{ + grub_memcpy (tr->nop, nopm, sizeof (tr->nop)); + tr->addr_hi[0] = ((addr & 0xc00000) >> 16); + tr->addr_hi[1] = (addr >> 24) & 0xff; + tr->addr_hi[2] = (addr >> 32) & 0xff; + tr->addr_hi[3] = (addr >> 40) & 0xff; + tr->addr_hi[4] = (addr >> 48) & 0xff; + tr->addr_hi[5] = (addr >> 56) & 0xff; + tr->e0 = 0xe0; + tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01; + tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11) + | ((addr & 0x200000) >> 17)); + tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19); + tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60; + grub_memcpy (tr->jump, jump, sizeof (tr->jump)); +} +#endif + /* Deal with relocation information. This function relocates addresses within the virtual address space starting from 0. So only relative addresses can be fully resolved. Absolute addresses must be relocated @@ -142,10 +300,15 @@ static void SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Addr *section_addresses, Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab, struct image_target_desc *image_target) + const char *strtab, + char *pe_target, Elf_Addr tramp_off, + Elf_Addr got_off, + struct image_target_desc *image_target) { Elf_Half i; Elf_Shdr *s; + struct ia64_kernel_trampoline *tr = (void *) (pe_target + tramp_off); + grub_uint64_t *gpptr = (void *) (pe_target + got_off); for (i = 0, s = sections; i < num_sections; @@ -200,7 +363,9 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? r->r_addend : 0; - if (image_target->voidp_sizeof == 4) + switch (image_target->elf_target) + { + case EM_386: switch (ELF_R_TYPE (info)) { case R_386_NONE: @@ -224,11 +389,12 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, *target, offset); break; default: - grub_util_error ("unknown relocation type %d", + grub_util_error ("unknown relocation type 0x%x", ELF_R_TYPE (info)); break; } - else + break; + case EM_X86_64: switch (ELF_R_TYPE (info)) { @@ -270,6 +436,85 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, ELF_R_TYPE (info)); break; } + break; +#ifdef MKIMAGE_ELF64 + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL21B: + { + grub_uint64_t noff; + make_trampoline (tr, addend + sym_addr); + noff = ((char *) tr - (char *) pe_target + - target_section_addr - (offset & ~3)) >> 4; + tr++; + if (noff & ~MASK19) + grub_util_error ("trampoline offset too big (%lx)", + noff); + add_value_to_slot_20b ((grub_addr_t) target, noff); + } + break; + + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + { + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host32 (symtab_section->sh_offset) + + ELF_R_SYM (info) * grub_target_to_host32 (symtab_section->sh_entsize)); + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target + + sym->st_value + - image_target->vaddr_offset)); + } + case R_IA64_LTOFF_FPTR22: + *gpptr = grub_host_to_target64 (addend + sym_addr); + add_value_to_slot_21 ((grub_addr_t) target, + (char *) gpptr - (char *) pe_target + + image_target->vaddr_offset); + gpptr++; + break; + + case R_IA64_GPREL22: + add_value_to_slot_21 ((grub_addr_t) target, + addend + sym_addr); + break; + case R_IA64_PCREL64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + break; + + case R_IA64_SEGREL64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr - target_section_addr); + break; + case R_IA64_DIR64LSB: + case R_IA64_FPTR64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr); + grub_util_info ("relocating a direct entry to 0x%" + PRIxGRUB_UINT64_T " at the offset 0x%x", + *target, offset); + break; + + /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */ + case R_IA64_LDXMOV: + break; + + default: + grub_util_error ("unknown relocation type 0x%x", + ELF_R_TYPE (info)); + break; + } + break; +#endif + default: + grub_util_error ("unknown architecture type %d", + image_target->elf_target); + } } } } @@ -312,7 +557,7 @@ SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type, b->block_size += 2; } } - else if (b->block_size & (8 - 1)) + else while (b->block_size & (8 - 1)) { /* If not aligned with a 32-bit boundary, add a padding entry. */ @@ -374,9 +619,11 @@ static Elf_Addr SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, Elf_Addr *section_addresses, Elf_Shdr *sections, Elf_Half section_entsize, Elf_Half num_sections, - const char *strtab, struct image_target_desc *image_target) + const char *strtab, + Elf_Addr jumpers, grub_size_t njumpers, + struct image_target_desc *image_target) { - Elf_Half i; + unsigned i; Elf_Shdr *s; struct fixup_block_list *lst, *lst0; Elf_Addr current_address = 0; @@ -384,8 +631,7 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000); memset (lst, 0, sizeof (*lst) + 2 * 0x1000); - for (i = 0, s = sections; - i < num_sections; + for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) @@ -417,8 +663,9 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, info = grub_le_to_cpu32 (r->r_info); /* Necessary to relocate only absolute addresses. */ - if (image_target->voidp_sizeof == 4) + switch (image_target->elf_target) { + case EM_386: if (ELF_R_TYPE (info) == R_386_32) { Elf_Addr addr; @@ -431,9 +678,8 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, addr, 0, current_address, image_target); } - } - else - { + break; + case EM_X86_64: if ((ELF_R_TYPE (info) == R_X86_64_32) || (ELF_R_TYPE (info) == R_X86_64_32S)) { @@ -452,10 +698,57 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, 0, current_address, image_target); } + break; + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL64LSB: + case R_IA64_LDXMOV: + case R_IA64_PCREL21B: + case R_IA64_LTOFF_FPTR22: + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + case R_IA64_GPREL22: + case R_IA64_SEGREL64LSB: + break; + + case R_IA64_FPTR64LSB: + case R_IA64_DIR64LSB: +#if 1 + { + Elf_Addr addr; + + addr = section_address + offset; + grub_util_info ("adding a relocation entry for 0x%llx", addr); + current_address + = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, current_address, + image_target); + } +#endif + break; + default: + grub_util_error ("unknown relocation type 0x%x", + ELF_R_TYPE (info)); + break; + } + break; + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); } } } + if (image_target->elf_target == EM_IA_64) + for (i = 0; i < njumpers; i++) + current_address = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_DIR64, + jumpers + 8 * i, + 0, current_address, + image_target); + current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target); { @@ -617,7 +910,10 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, Elf_Off section_offset; Elf_Half section_entsize; grub_size_t kernel_size; + grub_size_t ia64jmp_off = 0, ia64_toff = 0, ia64_got_off = 0; + unsigned ia64jmpnum = 0; Elf_Shdr *symtab_section; + grub_size_t got = 0; *start = 0; @@ -696,23 +992,31 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, break; } +#ifdef MKIMAGE_ELF64 + if (image_target->elf_target == EM_IA_64) + { + grub_size_t tramp; + + *kernel_sz = ALIGN_UP (*kernel_sz, 16); + + grub_ia64_dl_get_tramp_got_size (e, &tramp, &got); + tramp *= sizeof (struct ia64_kernel_trampoline); + + ia64_toff = *kernel_sz; + *kernel_sz += ALIGN_UP (tramp, 16); + + ia64jmp_off = *kernel_sz; + ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section, + image_target); + *kernel_sz += 16 * ia64jmpnum; + + ia64_got_off = *kernel_sz; + *kernel_sz += ALIGN_UP (got * sizeof (grub_uint64_t), 16); + } +#endif + if (! symtab_section) grub_util_error ("no symbol table"); - - *start = SUFFIX (relocate_symbols) (e, sections, symtab_section, - section_vaddresses, section_entsize, - num_sections, image_target); - if (*start == 0) - grub_util_error ("start symbol is not defined"); - - /* Resolve addresses in the virtual address space. */ - SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize, - num_sections, strtab, image_target); - - *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, - section_vaddresses, sections, - section_entsize, num_sections, - strtab, image_target); } else { @@ -722,6 +1026,34 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, out_img = xmalloc (*kernel_sz + total_module_size); + if (image_target->id == IMAGE_EFI) + { + *start = SUFFIX (relocate_symbols) (e, sections, symtab_section, + section_vaddresses, section_entsize, + num_sections, + (char *) out_img + ia64jmp_off, + ia64jmp_off + + image_target->vaddr_offset, + image_target); + if (*start == 0) + grub_util_error ("start symbol is not defined"); + + /* Resolve addresses in the virtual address space. */ + SUFFIX (relocate_addresses) (e, sections, section_addresses, + section_entsize, + num_sections, strtab, + out_img, ia64_toff, ia64_got_off, + image_target); + + *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, + section_vaddresses, sections, + section_entsize, num_sections, + strtab, ia64jmp_off + + image_target->vaddr_offset, + 2 * ia64jmpnum + got, + image_target); + } + for (i = 0, s = sections; i < num_sections; i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index e90d955ff..8de07747d 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -60,6 +60,8 @@ static struct console_grub_equivalence console_grub_equivalences_shift[] = { {"KP_8", '8'}, {"KP_9", '9'}, {"KP_Period", '.'}, + + {NULL, '\0'} }; static struct console_grub_equivalence console_grub_equivalences_unshift[] = { @@ -74,6 +76,8 @@ static struct console_grub_equivalence console_grub_equivalences_unshift[] = { {"KP_8", GRUB_TERM_KEY_UP}, {"KP_9", GRUB_TERM_KEY_PPAGE}, {"KP_Period", GRUB_TERM_KEY_DC}, + + {NULL, '\0'} }; static struct console_grub_equivalence console_grub_equivalences_common[] = { @@ -256,16 +260,17 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); else - printf ("\ -Usage: %s [OPTIONS] LAYOUT\n\ - -o, --output set output base name file. Default is LAYOUT.gkb\n\ + printf (_("\ +Usage: %s [OPTIONS]\n\ + -i, --input set input filename. Default is STDIN\n\ + -o, --output set output filename. Default is STDOUT\n\ -h, --help display this message and exit.\n\ -V, --version print version information and exit.\n\ -v, --verbose print verbose messages.\n\ \n\ -Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); +Report bugs to <%s>.\n"), program_name, PACKAGE_BUGREPORT); exit (status); } @@ -295,7 +300,7 @@ lookup (char *code, int shift) if (strcmp (code, console_grub_equivalences_common[i].layout) == 0) return console_grub_equivalences_common[i].grub; - fprintf (stderr, "Unknown key %s\n", code); + fprintf (stderr, _("Unknown key %s\n"), code); return '\0'; } @@ -391,7 +396,7 @@ write_keymaps (FILE *in, FILE *out) if (keycode_usb == 0 || keycode_usb >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) { - fprintf (stderr, "Unknown keycode 0x%02x\n", keycode_linux); + fprintf (stderr, _("Unknown keycode 0x%02x\n"), keycode_linux); continue; } if (keycode_usb < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) @@ -409,7 +414,7 @@ write_keymaps (FILE *in, FILE *out) if (ok == 0) { - fprintf (stderr, "ERROR: no keycodes found. Check output of %s.\n", + fprintf (stderr, _("ERROR: no keycodes found. Check output of %s.\n"), CKBCOMP); exit (1); } @@ -474,7 +479,7 @@ main (int argc, char *argv[]) in = stdin; if (!in) - grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); + grub_util_error (_("Couldn't open input file: %s\n"), strerror (errno)); if (outfile_name) out = fopen (outfile_name, "wb"); @@ -485,7 +490,7 @@ main (int argc, char *argv[]) { if (in != stdin) fclose (in); - grub_util_error ("Couldn't open output file: %s\n", strerror (errno)); + grub_util_error (_("Couldn't open output file: %s\n"), strerror (errno)); } write_keymaps (in, out); diff --git a/util/grub-mknetdir.in b/util/grub-mknetdir.in index b353e98b9..4f4061621 100644 --- a/util/grub-mknetdir.in +++ b/util/grub-mknetdir.in @@ -19,25 +19,20 @@ # Initialize some variables. transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -sbindir=@sbindir@ -bindir=@bindir@ -libdir=@libdir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +bindir="@bindir@" +libdir="@libdir@" PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ -platform=@platform@ host_os=@host_os@ -pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` -localedir=@datadir@/locale -native_platform=@platform@ pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" self=`basename $0` -grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` +grub_mkimage="${bindir}/`echo grub-mkimage | sed ${transform}`" rootdir=/srv/tftp grub_prefix=`echo /boot/grub | sed ${transform}` modules= @@ -48,7 +43,13 @@ recheck=no debug=no debug_image= subdir=`echo /boot/grub | sed ${transform}` -pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc +pc_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc" +ppc_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/powerpc-ieee1275" +sparc_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/sparc64-ieee1275" +i386_ieee1275_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-ieee1275" +efi32_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi" +efi64_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi" +itanium_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/ia64-efi" # Usage: usage # Print the usage. @@ -64,7 +65,7 @@ Install GRUB on your drive. --subdir=DIR relative subdirectory on network server --grub-mkimage=FILE use FILE as grub-mkimage -$self copies GRUB images into net_directory/subdir/${target_cpu}-${platform} +$self copies GRUB images into net_directory/subdir/target_cpu-platform Report bugs to . EOF @@ -170,12 +171,12 @@ process_input_dir () config_opt= mkdir -p "$grubdir" || exit 1 - for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img ${grubdir}/efiemu??.o; do - if test -f $file && [ "`basename $file`" != menu.lst ]; then - rm -f $file || exit 1 + for file in "${grubdir}"/*.mod "${grubdir}"/*.lst "${grubdir}"/*.img "${grubdir}"/efiemu??.o; do + if test -f "$file" && [ "`basename $file`" != menu.lst ]; then + rm -f "$file" || exit 1 fi done - for file in ${input_dir}/*.mod; do + for file in "${input_dir}"/*.mod; do if test -f "$file"; then cp -f "$file" "$grubdir/" fi @@ -200,11 +201,20 @@ process_input_dir () config_opt="-c ${grubdir}/load.cfg " fi + prefix="/${subdir}/${platform}"; case "${platform}" in i386-pc) mkimage_target=i386-pc-pxe; netmodules="pxe"; - prefix="(pxe)/${subdir}/${platform}"; ext=0 ;; + sparc64-ieee1275) mkimage_target=sparc64-ieee1275-aout; + netmodules="ofnet"; + ext=img ;; + *-ieee1275) mkimage_target="${platform}"; + netmodules="ofnet"; + ext=elf ;; + *-efi) mkimage_target="${platform}"; + netmodules="efinet"; + ext=efi ;; *) echo Unsupported platform ${platform}; exit 1;; esac @@ -213,16 +223,35 @@ process_input_dir () source ${subdir}/grub.cfg EOF - $grub_mkimage ${config_opt} -d "${input_dir}" -O ${mkimage_target} --output=${grubdir}/core.$ext --prefix=$prefix $modules $netmodules || exit 1 + "$grub_mkimage" ${config_opt} -d "${input_dir}" -O ${mkimage_target} "--output=${grubdir}/core.$ext" "--prefix=$prefix" $modules $netmodules tftp || exit 1 echo "Netboot directory for ${platform} created. Configure your DHCP server to point to ${subdir}/${platform}/core.$ext" } if [ "${override_dir}" = "" ] ; then if test -e "${pc_dir}" ; then - process_input_dir ${pc_dir} i386-pc + process_input_dir "${pc_dir}" i386-pc + fi + if test -e "${ppc_dir}" ; then + process_input_dir "${ppc_dir}" powerpc-ieee1275 + fi + if test -e "${sparc_dir}" ; then + process_input_dir ${sparc_dir} sparc64-ieee1275 + fi + if test -e "${i386_ieee1275_dir}" ; then + process_input_dir "${i386_ieee1275_dir}" i386-ieee1275 + fi + if test -e "${efi32_dir}" ; then + process_input_dir "${efi32_dir}" i386-efi + fi + if test -e "${efi64_dir}" ; then + process_input_dir "${efi64_dir}" x86_64-efi + fi + if test -e "${itanium_dir}" ; then + process_input_dir "${itanium_dir}" ia64-efi fi else - process_input_dir ${override_dir} ${target_cpu}-${native_platform} + source "${override_dir}"/modinfo.sh + process_input_dir "${override_dir}" ${grub_modinfo_target_cpu}-${grub_modinfo_platform} fi diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c index fe1887f8f..9c676a100 100644 --- a/util/grub-mkpasswd-pbkdf2.c +++ b/util/grub-mkpasswd-pbkdf2.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include "progname.h" @@ -46,16 +46,17 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); else - printf ("\ + printf (_("\ Usage: %s [OPTIONS]\n\ \nOptions:\n\ -c number, --iteration-count=number Number of PBKDF2 iterations\n\ -l number, --buflen=number Length of generated hash\n\ -s number, --salt=number Length of salt\n\ \n\ -Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); +Report bugs to <%s>.\n"), program_name, PACKAGE_BUGREPORT); exit (status); } @@ -85,14 +86,12 @@ int main (int argc, char *argv[]) { unsigned int count = 10000, buflen = 64, saltlen = 64; - char *pass1, *pass2; char *bufhex, *salthex; gcry_err_code_t gcry_err; grub_uint8_t *buf, *salt; ssize_t nr; - FILE *in, *out; - struct termios s, t; - int tty_changed; + char pass1[GRUB_AUTH_MAX_PASSLEN]; + char pass2[GRUB_AUTH_MAX_PASSLEN]; set_program_name (argv[0]); @@ -137,12 +136,12 @@ main (int argc, char *argv[]) bufhex = malloc (buflen * 2 + 1); if (!bufhex) - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); buf = malloc (buflen); if (!buf) { free (bufhex); - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); } salt = malloc (saltlen); @@ -150,7 +149,7 @@ main (int argc, char *argv[]) { free (bufhex); free (buf); - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); } salthex = malloc (saltlen * 2 + 1); if (!salthex) @@ -158,120 +157,68 @@ main (int argc, char *argv[]) free (salt); free (bufhex); free (buf); - grub_util_error ("out of memory"); + grub_util_error (_("out of memory")); } - - /* Disable echoing. Based on glibc. */ - in = fopen ("/dev/tty", "w+c"); - if (in == NULL) - { - in = stdin; - out = stderr; - } - else - out = in; - - if (tcgetattr (fileno (in), &t) == 0) - { - /* Save the old one. */ - s = t; - /* Tricky, tricky. */ - t.c_lflag &= ~(ECHO|ISIG); - tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0); - } - else - tty_changed = 0; - printf ("Enter password: "); - pass1 = NULL; - { - grub_size_t n; - nr = getline (&pass1, &n, stdin); - } - if (nr < 0 || !pass1) + printf ("%s", _("Enter password: ")); + if (!grub_password_get (pass1, GRUB_AUTH_MAX_PASSLEN)) { free (buf); free (bufhex); free (salthex); free (salt); - /* Restore the original setting. */ - if (tty_changed) - (void) tcsetattr (fileno (in), TCSAFLUSH, &s); - grub_util_error ("failure to read password"); + grub_util_error (_("failure to read password")); } - if (nr >= 1 && pass1[nr-1] == '\n') - pass1[nr-1] = 0; - - printf ("\nReenter password: "); - pass2 = NULL; - { - grub_size_t n; - nr = getline (&pass2, &n, stdin); - } - /* Restore the original setting. */ - if (tty_changed) - (void) tcsetattr (fileno (in), TCSAFLUSH, &s); - printf ("\n"); - - if (nr < 0 || !pass2) + printf ("\n%s", _("Reenter password: ")); + if (!grub_password_get (pass2, GRUB_AUTH_MAX_PASSLEN)) { - memset (pass1, 0, strlen (pass1)); - free (pass1); free (buf); free (bufhex); free (salthex); free (salt); - grub_util_error ("failure to read password"); + grub_util_error (_("failure to read password")); } - if (nr >= 1 && pass2[nr-1] == '\n') - pass2[nr-1] = 0; if (strcmp (pass1, pass2) != 0) { - memset (pass1, 0, strlen (pass1)); - memset (pass2, 0, strlen (pass2)); - free (pass1); - free (pass2); + memset (pass1, 0, sizeof (pass1)); + memset (pass2, 0, sizeof (pass2)); free (buf); free (bufhex); free (salthex); free (salt); - grub_util_error ("passwords don't match"); + grub_util_error (_("passwords don't match")); } - memset (pass2, 0, strlen (pass2)); - free (pass2); + memset (pass2, 0, sizeof (pass2)); #if ! defined (__linux__) && ! defined (__FreeBSD__) - printf ("WARNING: your random generator isn't known to be secure\n"); + printf ("%s", _("WARNING: your random generator isn't known to be secure\n")); #endif { FILE *f; size_t rd; - f = fopen ("/dev/random", "rb"); + f = fopen ("/dev/urandom", "rb"); if (!f) { - memset (pass1, 0, strlen (pass1)); - free (pass1); + memset (pass1, 0, sizeof (pass1)); free (buf); free (bufhex); free (salthex); free (salt); fclose (f); - grub_util_error ("couldn't retrieve random data for salt"); + grub_util_error (_("couldn't retrieve random data for salt")); } rd = fread (salt, 1, saltlen, f); if (rd != saltlen) { fclose (f); - memset (pass1, 0, strlen (pass1)); - free (pass1); + memset (pass1, 0, sizeof (pass1)); free (buf); free (bufhex); free (salthex); free (salt); - fclose (f); - grub_util_error ("couldn't retrieve random data for salt"); + grub_util_error (_("couldn't retrieve random data for salt")); } fclose (f); } @@ -280,8 +227,7 @@ main (int argc, char *argv[]) (grub_uint8_t *) pass1, strlen (pass1), salt, saltlen, count, buf, buflen); - memset (pass1, 0, strlen (pass1)); - free (pass1); + memset (pass1, 0, sizeof (pass1)); if (gcry_err) { @@ -293,13 +239,13 @@ main (int argc, char *argv[]) memset (salthex, 0, 2 * saltlen); free (salt); free (salthex); - grub_util_error ("cryptographic error number %d", gcry_err); + grub_util_error (_("cryptographic error number %d"), gcry_err); } hexify (bufhex, buf, buflen); hexify (salthex, salt, saltlen); - printf ("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n", + printf (_("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n"), count, salthex, bufhex); memset (buf, 0, buflen); memset (bufhex, 0, 2 * buflen); diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c index 3fe3fe698..788db38a2 100644 --- a/util/grub-mkrelpath.c +++ b/util/grub-mkrelpath.c @@ -38,9 +38,9 @@ static void usage (int status) { if (status) - fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); else - printf ("\ + printf (_("\ Usage: %s [OPTIONS] PATH\n\ \n\ Make a system path relative to its root.\n\ @@ -49,7 +49,7 @@ Options:\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ \n\ -Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); +Report bugs to <%s>.\n"), program_name, PACKAGE_BUGREPORT); exit (status); } @@ -89,13 +89,13 @@ main (int argc, char *argv[]) if (optind >= argc) { - fprintf (stderr, "No path is specified.\n"); + fprintf (stderr, _("No path is specified.\n")); usage (1); } if (optind + 1 != argc) { - fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind + 1]); usage (1); } diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in index f2714c486..ccad5e0d9 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -18,30 +18,30 @@ set -e # along with GRUB. If not, see . # Initialize some variables. + transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +bindir="@bindir@" +libdir="@libdir@" PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ -native_platform=@platform@ pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" self=`basename $0` -multiboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-multiboot -coreboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-coreboot -qemu_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-qemu -pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc -efi32_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi -efi64_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi +multiboot_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-multiboot" +coreboot_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-coreboot" +qemu_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-qemu" +pc_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc" +efi32_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi" +efi64_dir="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi" rom_directory= override_dir= -grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` +grub_mkimage="${bindir}/`echo grub-mkimage | sed ${transform}`" xorriso=xorriso @@ -131,7 +131,7 @@ do --xorriso) xorriso=`argument $option "$@"`; shift ;; --xorriso=*) - xorriso=`echo "${option}/" | sed 's/--xorriso=//'` ;; + xorriso=`echo "${option}" | sed 's/--xorriso=//'` ;; *) source="${source} ${option} $@"; break ;; @@ -152,15 +152,7 @@ else exit 1 fi -if test "x$TMP" != x; then - MKTEMP_TEMPLATE="$TMP/grub-mkrescue.XXXXXXXXXX" -elif test "x$TEMP" != x; then - MKTEMP_TEMPLATE="$TEMP/grub-mkrescue.XXXXXXXXXX" -else - MKTEMP_TEMPLATE="/tmp/grub-mkrescue.XXXXXXXXXX" -fi - -iso9660_dir=`mktemp -d "$MKTEMP_TEMPLATE"` +iso9660_dir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 mkdir -p ${iso9660_dir}/boot/grub process_input_dir () @@ -168,7 +160,7 @@ process_input_dir () input_dir="$1" platform="$2" mkdir -p ${iso9660_dir}/boot/grub/${platform} - for file in ${input_dir}/*.mod; do + for file in "${input_dir}/"*.mod "${input_dir}/"efiemu32.o "${input_dir}/"efiemu64.o; do if test -f "$file"; then cp -f "$file" ${iso9660_dir}/boot/grub/${platform}/ fi @@ -197,8 +189,8 @@ make_image () echo "Enabling $2 support ..." - memdisk_img=`mktemp "$MKTEMP_TEMPLATE"` - memdisk_dir=`mktemp -d "$MKTEMP_TEMPLATE"` + memdisk_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + memdisk_dir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 mkdir -p ${memdisk_dir}/boot/grub cat << EOF > ${memdisk_dir}/boot/grub/grub.cfg @@ -239,14 +231,15 @@ if [ "${override_dir}" = "" ] ; then process_input_dir ${efi64_dir} x86_64-efi fi else - process_input_dir ${override_dir} ${target_cpu}-${native_platform} + . "${override_dir}"/modinfo.sh + process_input_dir "${override_dir}" ${grub_modinfo_target_cpu}-${grub_modinfo_platform} multiboot_dir= pc_dir= efi32_dir= efi64_dir= coreboot_dir= qemu_dir= - case "${target_cpu}-${native_platform}" in + case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in i386-multiboot) multiboot_dir=${override_dir} ;; i386-coreboot) coreboot_dir=${override_dir} ;; i386-qemu) qemu_dir=${override_dir} ;; @@ -263,12 +256,12 @@ grub_mkisofs_arguments="${grub_mkisofs_arguments} --modification-date=$(echo ${i # build BIOS core.img if test -e "${pc_dir}" ; then echo "Enabling BIOS support ..." - core_img=`mktemp "$MKTEMP_TEMPLATE"` + core_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 $grub_mkimage -O i386-pc -d ${pc_dir}/ -o ${core_img} --prefix=/boot/grub/i386-pc \ iso9660 biosdisk cat ${pc_dir}/cdboot.img ${core_img} > ${iso9660_dir}/boot/grub/i386-pc/eltorito.img - embed_img=`mktemp "$MKTEMP_TEMPLATE"` + embed_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 cat ${pc_dir}/boot.img ${core_img} > ${embed_img} rm -f ${core_img} @@ -284,16 +277,20 @@ if test -e "${pc_dir}" ; then fi # build multiboot core.img -make_image "${multiboot_dir}" i386-multiboot "${iso9660_dir}/boot/multiboot.img" "ata at_keyboard" +make_image "${multiboot_dir}" i386-multiboot "${iso9660_dir}/boot/multiboot.img" "pata ahci at_keyboard" if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then - efi_dir=`mktemp -d "$MKTEMP_TEMPLATE"` + efi_dir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 mkdir -p "${efi_dir}/efi/boot" # build bootx64.efi make_image "${efi64_dir}" x86_64-efi "${efi_dir}"/efi/boot/bootx64.efi "" # build bootia32.efi make_image "${efi32_dir}" i386-efi "${efi_dir}"/efi/boot/bootia32.efi "" + if [ -e "${efi_dir}"/efi/boot/bootia32.efi ]; then + # For old macs. Suggested by Peter Jones. + cp "${efi_dir}"/efi/boot/bootia32.efi "${efi_dir}"/efi/boot/boot.efi + fi mformat -C -f 2880 -L 16 -i "${iso9660_dir}"/efi.img :: mcopy -s -i "${iso9660_dir}"/efi.img ${efi_dir}/efi ::/ @@ -301,11 +298,11 @@ if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then grub_mkisofs_arguments="${grub_mkisofs_arguments} --efi-boot efi.img" fi -make_image "${qemu_dir}" i386-qemu "${iso9660_dir}/boot/qemu.img" "ata at_keyboard" +make_image "${qemu_dir}" i386-qemu "${iso9660_dir}/boot/qemu.img" "pata at_keyboard" if [ -e "${iso9660_dir}/boot/qemu.img" ] && [ -d "${rom_directory}" ]; then cp "${iso9660_dir}/boot/qemu.img" "${rom_directory}/qemu.img" fi -make_image "${coreboot_dir}" i386-coreboot "${iso9660_dir}/boot/coreboot.elf" "ata at_keyboard" +make_image "${coreboot_dir}" i386-coreboot "${iso9660_dir}/boot/coreboot.elf" "pata ahci at_keyboard" if [ -e "${iso9660_dir}/boot/coreboot.elf" ] && [ -d "${rom_directory}" ]; then cp "${iso9660_dir}/boot/coreboot.elf" "${rom_directory}/coreboot.elf" fi diff --git a/util/grub-mkstandalone.in b/util/grub-mkstandalone.in new file mode 100644 index 000000000..13cf9df7b --- /dev/null +++ b/util/grub-mkstandalone.in @@ -0,0 +1,192 @@ +#! /bin/sh +set -e + +# Make GRUB rescue image +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. + +transform="@program_transform_name@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +bindir="@bindir@" +libdir="@libdir@" +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" + +self=`basename $0` + +source_directory= +compression=auto +format= +grub_mkimage="${bindir}/`echo grub-mkimage | sed ${transform}`" +source= + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + + --modules) + modules=`argument $option "$@"`; shift ;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + + -o | --output) + output_image=`argument $option "$@"`; shift ;; + --output=*) + output_image=`echo "$option" | sed 's/--output=//'` ;; + + --directory | -d) + source_directory=`argument $option "$@"`; shift ;; + --directory=*) + source_directory=`echo "$option" | sed 's/--directory=//'` ;; + + --grub-mkimage) + grub_mkimage=`argument $option "$@"`; shift ;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + + --compression | -C) + compression=`argument $option "$@"`; shift ;; + --compression=*) + compression=`echo "${option}" | sed 's/--compression=//'` ;; + + --format | -O) + format=`argument $option "$@"`; shift ;; + --format=*) + format=`echo "${option}" | sed 's/--format=//'` ;; + + *) + source="${source} ${option} $@"; break ;; + esac +done + +if [ "x${output_image}" = x ] ; then + echo "output file must be given" >&2 + usage + exit 1 +fi + +if [ "x${format}" = x ] ; then + echo "format must be given" >&2 + usage + exit 1 +fi + +if [ "x$source_directory" = x ] ; then + cpu="`echo $format | awk -F - '{ print $1; }'`" + platform="`echo $format | awk -F - '{ print $2; }'`" + case "$platform" in + yeeloong | fuloong | fuloong2f | fuloong2e) + platform=loongson ;; + esac + case "$cpu-$platform" in + mips-loongson) + cpu=mipsel ;; + esac + source_directory="${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/$cpu-$platform" +fi + +set $grub_mkimage dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +memdisk_dir="`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 +mkdir -p "${memdisk_dir}"/boot/grub + +for file in "${source_directory}/"*.mod "${source_directory}/"efiemu32.o "${source_directory}/"efiemu64.o; do + if test -f "$file"; then + cp -f "$file" "${memdisk_dir}"/boot/grub/ + fi +done + +for file in ${pkglib_DATA}; do + if test -f "${source_directory}/${file}"; then + cp -f "${source_directory}/${file}" "${memdisk_dir}"/boot/grub/ + fi +done + +mkdir -p "${memdisk_dir}"/boot/grub/locale +for file in "${source_directory}"/po/*.mo; do + if test -f "$file"; then + cp -f "$file" "${memdisk_dir}"/boot/grub/locale/ + fi +done + +for file in $source; do + cp -f "$file" "${memdisk_dir}"/"$file"; +done + +memdisk_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + +(cd "${memdisk_dir}"; tar -cf - * $source) > "${memdisk_img}" +rm -rf "${memdisk_dir}" +"$grub_mkimage" -O "${format}" -C "$compression" -d "${source_directory}" -m "${memdisk_img}" -o "$output_image" --prefix='(memdisk)/boot/grub' memdisk tar $modules +rm -rf "${memdisk_img}" + +exit 0 diff --git a/util/grub-mount.c b/util/grub-mount.c new file mode 100644 index 000000000..e5a3b9f8e --- /dev/null +++ b/util/grub-mount.c @@ -0,0 +1,569 @@ +/* grub-mount.c - FUSE driver for filesystems that GRUB understands */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 FUSE_USE_VERSION 26 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "progname.h" +#include "argp.h" + +static char *root = NULL; +grub_device_t dev = NULL; +grub_fs_t fs = NULL; +static char **images = NULL; +static char *debug_str = NULL; +static char **fuse_args = NULL; +static int fuse_argc = 0; +static int num_disks = 0; +static int mount_crypt = 0; + +static grub_err_t +execute_command (char *name, int n, char **args) +{ + grub_command_t cmd; + + cmd = grub_command_find (name); + if (! cmd) + grub_util_error (_("can\'t find command %s"), name); + + return (cmd->func) (cmd, n, args); +} + +/* Translate GRUB error numbers into OS error numbers. Print any unexpected + errors. */ +static int +translate_error (void) +{ + int ret; + + switch (grub_errno) + { + case GRUB_ERR_NONE: + ret = 0; + break; + + case GRUB_ERR_OUT_OF_MEMORY: + grub_print_error (); + ret = -ENOMEM; + break; + + case GRUB_ERR_BAD_FILE_TYPE: + /* This could also be EISDIR. Take a guess. */ + ret = -ENOTDIR; + break; + + case GRUB_ERR_FILE_NOT_FOUND: + ret = -ENOENT; + break; + + case GRUB_ERR_FILE_READ_ERROR: + case GRUB_ERR_READ_ERROR: + case GRUB_ERR_IO: + grub_print_error (); + ret = -EIO; + break; + + case GRUB_ERR_SYMLINK_LOOP: + ret = -ELOOP; + break; + + default: + grub_print_error (); + ret = -EINVAL; + break; + } + + /* Any previous errors were handled. */ + grub_errno = GRUB_ERR_NONE; + + return ret; +} + +static int +fuse_getattr (const char *path, struct stat *st) +{ + char *filename, *pathname, *path2; + const char *pathname_t; + struct grub_dirhook_info file_info; + int file_exists = 0; + + /* A hook for iterating directories. */ + auto int find_file (const char *cur_filename, + const struct grub_dirhook_info *info); + int find_file (const char *cur_filename, + const struct grub_dirhook_info *info) + { + if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename) + : grub_strcmp (cur_filename, filename)) == 0) + { + file_info = *info; + file_exists = 1; + return 1; + } + return 0; + } + + if (path[0] == '/' && path[1] == 0) + { + st->st_dev = 0; + st->st_ino = 0; + st->st_mode = 0555 | S_IFDIR; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_size = 0; + st->st_blksize = 512; + st->st_blocks = (st->st_blksize + 511) >> 9; + st->st_atime = st->st_mtime = st->st_ctime = 0; + return 0; + } + + file_exists = 0; + + pathname_t = grub_strchr (path, ')'); + if (! pathname_t) + pathname_t = path; + else + pathname_t++; + pathname = xstrdup (pathname_t); + + /* Remove trailing '/'. */ + while (*pathname && pathname[grub_strlen (pathname) - 1] == '/') + pathname[grub_strlen (pathname) - 1] = 0; + + /* Split into path and filename. */ + filename = grub_strrchr (pathname, '/'); + if (! filename) + { + path2 = grub_strdup ("/"); + filename = pathname; + } + else + { + filename++; + path2 = grub_strdup (pathname); + path2[filename - pathname] = 0; + } + + /* It's the whole device. */ + (fs->dir) (dev, path2, find_file); + + grub_free (path2); + if (!file_exists) + { + grub_errno = GRUB_ERR_NONE; + return -ENOENT; + } + st->st_dev = 0; + st->st_ino = 0; + st->st_mode = file_info.dir ? (0555 | S_IFDIR) : (0444 | S_IFREG); + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + if (!file_info.dir) + { + grub_file_t file; + file = grub_file_open (path); + if (! file) + return translate_error (); + st->st_size = file->size; + grub_file_close (file); + } + else + st->st_size = 0; + st->st_blksize = 512; + st->st_blocks = (st->st_size + 511) >> 9; + st->st_atime = st->st_mtime = st->st_ctime = file_info.mtimeset + ? file_info.mtime : 0; + grub_errno = GRUB_ERR_NONE; + return 0; +} + +static int +fuse_opendir (const char *path, struct fuse_file_info *fi) +{ + return 0; +} + +/* FIXME */ +static grub_file_t files[65536]; +static int first_fd = 1; + +static int +fuse_open (const char *path, struct fuse_file_info *fi __attribute__ ((unused))) +{ + grub_file_t file; + file = grub_file_open (path); + if (! file) + return translate_error (); + files[first_fd++] = file; + fi->fh = first_fd; + files[first_fd++] = file; + grub_errno = GRUB_ERR_NONE; + return 0; +} + +static int +fuse_read (const char *path, char *buf, size_t sz, off_t off, + struct fuse_file_info *fi) +{ + grub_file_t file = files[fi->fh]; + grub_ssize_t size; + + if (off > file->size) + return -EINVAL; + + file->offset = off; + + size = grub_file_read (file, buf, sz); + if (size < 0) + return translate_error (); + else + { + grub_errno = GRUB_ERR_NONE; + return size; + } +} + +static int +fuse_release (const char *path, struct fuse_file_info *fi) +{ + grub_file_close (files[fi->fh]); + files[fi->fh] = NULL; + grub_errno = GRUB_ERR_NONE; + return 0; +} + +static int +fuse_readdir (const char *path, void *buf, + fuse_fill_dir_t fill, off_t off, struct fuse_file_info *fi) +{ + char *pathname; + + auto int call_fill (const char *filename, + const struct grub_dirhook_info *info); + int call_fill (const char *filename, const struct grub_dirhook_info *info) + { + struct stat st; + grub_memset (&st, 0, sizeof (st)); + st.st_mode = info->dir ? (0555 | S_IFDIR) : (0444 | S_IFREG); + if (!info->dir) + { + grub_file_t file; + char *tmp; + tmp = xasprintf ("%s/%s", path, filename); + file = grub_file_open (tmp); + free (tmp); + if (! file) + return translate_error (); + st.st_size = file->size; + grub_file_close (file); + } + st.st_blksize = 512; + st.st_blocks = (st.st_size + 511) >> 9; + st.st_atime = st.st_mtime = st.st_ctime + = info->mtimeset ? info->mtime : 0; + fill (buf, filename, &st, 0); + return 0; + } + + pathname = xstrdup (path); + + /* Remove trailing '/'. */ + while (pathname [0] && pathname[1] + && pathname[grub_strlen (pathname) - 1] == '/') + pathname[grub_strlen (pathname) - 1] = 0; + + (fs->dir) (dev, pathname, call_fill); + free (pathname); + grub_errno = GRUB_ERR_NONE; + return 0; +} + +struct fuse_operations grub_opers = { + .getattr = fuse_getattr, + .open = fuse_open, + .release = fuse_release, + .opendir = fuse_opendir, + .readdir = fuse_readdir, + .read = fuse_read +}; + +static grub_err_t +fuse_init (void) +{ + int i; + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + char *host_file; + char *loop_name; + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error (grub_errmsg); + + host_file = grub_xasprintf ("(host)%s", images[i]); + if (!host_file) + grub_util_error (grub_errmsg); + + argv[0] = loop_name; + argv[1] = host_file; + + if (execute_command ("loopback", 2, argv)) + grub_util_error (_("loopback command fails")); + + grub_free (loop_name); + grub_free (host_file); + } + + if (mount_crypt) + { + char *argv[2] = { "-a", NULL}; + if (execute_command ("cryptomount", 1, argv)) + grub_util_error (_("cryptomount command fails: %s"), grub_errmsg); + } + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + dev = grub_device_open (0); + if (! dev) + return grub_errno; + + fs = grub_fs_probe (dev); + if (! fs) + { + grub_device_close (dev); + return grub_errno; + } + + fuse_main (fuse_argc, fuse_args, &grub_opers, NULL); + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + char *loop_name; + + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error (grub_errmsg); + + argv[0] = "-d"; + argv[1] = loop_name; + + execute_command ("loopback", 2, argv); + + grub_free (loop_name); + } + + return GRUB_ERR_NONE; +} + +static struct argp_option options[] = { + {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2}, + {"debug", 'd', "S", 0, N_("Set debug environment variable."), 2}, + {"crypto", 'C', NULL, OPTION_ARG_OPTIONAL, N_("Mount crypto devices."), 2}, + {"zfs-key", 'K', N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2}, + {"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, N_("Print verbose messages."), 2}, + {0, 0, 0, 0, 0, 0} +}; + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); +} +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + char *p; + + switch (key) + { + case 'r': + root = arg; + return 0; + + case 'K': + if (strcmp (arg, "prompt") == 0) + { + char buf[1024]; + grub_printf ("%s", _("Enter ZFS password: ")); + if (grub_password_get (buf, 1023)) + { + grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1); + } + } + else + { + FILE *f; + ssize_t real_size; + grub_uint8_t buf[1024]; + f = fopen (arg, "rb"); + if (!f) + { + printf (_("Error loading file %s: %s\n"), arg, strerror (errno)); + return 0; + } + real_size = fread (buf, 1, 1024, f); + if (real_size < 0) + { + printf (_("Error loading file %s: %s\n"), arg, strerror (errno)); + fclose (f); + return 0; + } + grub_zfs_add_key (buf, real_size, 0); + } + return 0; + + case 'C': + mount_crypt = 1; + return 0; + + case 'd': + debug_str = arg; + return 0; + + case 'v': + verbosity++; + return 0; + + case ARGP_KEY_ARG: + if (arg[0] != '-') + break; + + default: + if (!arg) + return 0; + + fuse_args = xrealloc (fuse_args, (fuse_argc + 1) * sizeof (fuse_args[0])); + fuse_args[fuse_argc] = xstrdup (arg); + fuse_argc++; + return 0; + } + + images = xrealloc (images, (num_disks + 1) * sizeof (images[0])); + images[num_disks] = canonicalize_file_name (arg); + num_disks++; + + return 0; +} + +struct argp argp = { + options, argp_parser, N_("IMAGE1 [IMAGE2 ...] MOUNTPOINT"), + N_("Debug tool for filesystem driver."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + char *default_root, *alloc_root; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + fuse_args = xrealloc (fuse_args, (fuse_argc + 2) * sizeof (fuse_args[0])); + fuse_args[fuse_argc] = xstrdup (argv[0]); + fuse_argc++; + /* Run single-threaded. */ + fuse_args[fuse_argc] = xstrdup ("-s"); + fuse_argc++; + + argp_parse (&argp, argc, argv, 0, 0, 0); + + if (num_disks < 2) + grub_util_error (_("need an image and mountpoint")); + fuse_args = xrealloc (fuse_args, (fuse_argc + 2) * sizeof (fuse_args[0])); + fuse_args[fuse_argc] = images[num_disks - 1]; + fuse_argc++; + num_disks--; + fuse_args[fuse_argc] = NULL; + + /* Initialize all modules. */ + grub_init_all (); + + if (debug_str) + grub_env_set ("debug", debug_str); + + default_root = (num_disks == 1) ? "loop0" : "md0"; + alloc_root = 0; + if (root) + { + if ((*root >= '0') && (*root <= '9')) + { + alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2); + + sprintf (alloc_root, "%s,%s", default_root, root); + root = alloc_root; + } + } + else + root = default_root; + + grub_env_set ("root", root); + + if (alloc_root) + free (alloc_root); + + /* Do it. */ + fuse_init (); + if (grub_errno) + { + grub_print_error (); + return 1; + } + + /* Free resources. */ + grub_fini_all (); + + return 0; +} diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c index f370bbfa8..730b9c12f 100644 --- a/util/grub-pe2elf.c +++ b/util/grub-pe2elf.c @@ -31,6 +31,8 @@ #include "progname.h" +/* Please don't internationalise this file. It's pointless. */ + static struct option options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -79,24 +81,27 @@ Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); #define BSS_SECTION 4 #define MODNAME_SECTION 5 #define MODDEPS_SECTION 6 -#define SYMTAB_SECTION 7 -#define STRTAB_SECTION 8 +#define MODLICENSE_SECTION 7 +#define SYMTAB_SECTION 8 +#define STRTAB_SECTION 9 -#define REL_SECTION 9 -#define MAX_SECTIONS 12 +#define REL_SECTION 10 + +/* 10 normal section + up to 4 relocation (.text, .rdata, .data, .symtab). */ +#define MAX_SECTIONS 16 #define STRTAB_BLOCK 256 static char *strtab; static int strtab_max, strtab_len; -Elf32_Ehdr ehdr; -Elf32_Shdr shdr[MAX_SECTIONS]; -int num_sections; -grub_uint32_t offset; +static Elf32_Ehdr ehdr; +static Elf32_Shdr shdr[MAX_SECTIONS]; +static int num_sections; +static grub_uint32_t offset; static int -insert_string (char *name) +insert_string (const char *name) { int len, result; @@ -124,6 +129,8 @@ write_section_data (FILE* fp, char *image, { int *section_map; int i; + char *pe_strtab = (image + pe_chdr->symtab_offset + + pe_chdr->num_symbols * sizeof (struct grub_pe32_symbol)); section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int)); section_map[0] = 0; @@ -131,31 +138,42 @@ write_section_data (FILE* fp, char *image, for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) { grub_uint32_t idx; + const char *name = pe_shdr->name; - if (! strcmp (pe_shdr->name, ".text")) + if (name[0] == '/' && isdigit (name[1])) + { + char t[sizeof (pe_shdr->name) + 1]; + memcpy (t, name, sizeof (pe_shdr->name)); + t[sizeof (pe_shdr->name)] = 0; + name = pe_strtab + atoi (t + 1); + } + + if (! strcmp (name, ".text")) { idx = TEXT_SECTION; shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; } - else if (! strcmp (pe_shdr->name, ".rdata")) + else if (! strcmp (name, ".rdata")) { idx = RDATA_SECTION; shdr[idx].sh_flags = SHF_ALLOC; } - else if (! strcmp (pe_shdr->name, ".data")) + else if (! strcmp (name, ".data")) { idx = DATA_SECTION; shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; } - else if (! strcmp (pe_shdr->name, ".bss")) + else if (! strcmp (name, ".bss")) { idx = BSS_SECTION; shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; } - else if (! strcmp (pe_shdr->name, ".modname")) + else if (! strcmp (name, ".modname")) idx = MODNAME_SECTION; - else if (! strcmp (pe_shdr->name, ".moddeps")) + else if (! strcmp (name, ".moddeps")) idx = MODDEPS_SECTION; + else if (strcmp (name, ".module_license") == 0) + idx = MODLICENSE_SECTION; else { section_map[i + 1] = -1; @@ -181,14 +199,14 @@ write_section_data (FILE* fp, char *image, if (pe_shdr->relocations_offset) { - char name[5 + strlen (pe_shdr->name)]; + char relname[5 + strlen (name)]; if (num_sections >= MAX_SECTIONS) grub_util_error ("too many sections"); - sprintf (name, ".rel%s", pe_shdr->name); + sprintf (relname, ".rel%s", name); - shdr[num_sections].sh_name = insert_string (name); + shdr[num_sections].sh_name = insert_string (relname); shdr[num_sections].sh_link = i; shdr[num_sections].sh_info = idx; @@ -197,7 +215,7 @@ write_section_data (FILE* fp, char *image, num_sections++; } else - shdr[idx].sh_name = insert_string (pe_shdr->name); + shdr[idx].sh_name = insert_string (name); } return section_map; @@ -337,7 +355,7 @@ write_symbol_table (FILE* fp, char *image, else bind = STB_LOCAL; - if ((type != STT_FUNC) && (pe_symtab->num_aux)) + if ((pe_symtab->type != GRUB_PE32_DT_FUNCTION) && (pe_symtab->num_aux)) { if (! pe_symtab->value) type = STT_SECTION; diff --git a/util/grub-probe.c b/util/grub-probe.c index b92d301f0..17edff6ce 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -32,8 +31,12 @@ #include #include #include -#include +#include #include +#include +#include +#include +#include #include #include @@ -54,24 +57,67 @@ enum { PRINT_DEVICE, PRINT_PARTMAP, PRINT_ABSTRACTION, + PRINT_CRYPTODISK_UUID, + PRINT_HINT_STR, + PRINT_BIOS_HINT, + PRINT_IEEE1275_HINT, + PRINT_BAREMETAL_HINT, + PRINT_EFI_HINT, + PRINT_ARC_HINT, + PRINT_COMPATIBILITY_HINT, + PRINT_MSDOS_PARTTYPE }; -int print = PRINT_FS; +static int print = PRINT_FS; static unsigned int argument_is_device = 0; static void probe_partmap (grub_disk_t disk) { grub_partition_t part; + grub_disk_memberlist_t list = NULL, tmp; if (disk->partition == NULL) { grub_util_info ("no partition map found for %s", disk->name); - return; } for (part = disk->partition; part; part = part->parent) - printf ("%s\n", part->partmap->name); + printf ("%s ", part->partmap->name); + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->memberlist) + { + list = disk->dev->memberlist (disk); + } + while (list) + { + probe_partmap (list->disk); + tmp = list->next; + free (list); + list = tmp; + } +} + +static void +probe_cryptodisk_uuid (grub_disk_t disk) +{ + grub_disk_memberlist_t list = NULL, tmp; + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->memberlist) + { + list = disk->dev->memberlist (disk); + } + while (list) + { + probe_cryptodisk_uuid (list->disk); + tmp = list->next; + free (list); + list = tmp; + } + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + grub_util_cryptodisk_print_uuid (disk); } static int @@ -82,10 +128,188 @@ probe_raid_level (grub_disk_t disk) if (!disk) return -1; - if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID) + if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID) return -1; - return ((struct grub_raid_array *) disk->data)->level; + if (disk->name[0] != 'm' || disk->name[1] != 'd') + return -1; + + if (!((struct grub_diskfilter_lv *) disk->data)->segments) + return -1; + return ((struct grub_diskfilter_lv *) disk->data)->segments->type; +} + +/* Since OF path names can have "," characters in them, and GRUB + internally uses "," to indicate partitions (unlike OF which uses + ":" for this purpose) we escape such commas. */ +static char * +escape_of_path (const char *orig_path) +{ + char *new_path, *d, c; + const char *p; + + if (!strchr (orig_path, ',')) + return (char *) xstrdup (orig_path); + + new_path = xmalloc (strlen (orig_path) * 2 + sizeof ("ieee1275/")); + + p = orig_path; + grub_strcpy (new_path, "ieee1275/"); + d = new_path + sizeof ("ieee1275/") - 1; + while ((c = *p++) != '\0') + { + if (c == ',') + *d++ = '\\'; + *d++ = c; + } + *d = 0; + + free ((char *) orig_path); + + return new_path; +} + +static char * +guess_bios_drive (const char *orig_path) +{ + char *canon; + char *ptr; + canon = canonicalize_file_name (orig_path); + if (!canon) + return NULL; + ptr = strrchr (orig_path, '/'); + if (ptr) + ptr++; + else + ptr = canon; + if ((ptr[0] == 's' || ptr[0] == 'h') && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("hd%d", num); + } + if (ptr[0] == 'f' && ptr[1] == 'd') + { + int num = atoi (ptr + 2); + free (canon); + return xasprintf ("fd%d", num); + } + free (canon); + return NULL; +} + +static char * +guess_efi_drive (const char *orig_path) +{ + char *canon; + char *ptr; + canon = canonicalize_file_name (orig_path); + if (!canon) + return NULL; + ptr = strrchr (orig_path, '/'); + if (ptr) + ptr++; + else + ptr = canon; + if ((ptr[0] == 's' || ptr[0] == 'h') && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("hd%d", num); + } + if (ptr[0] == 'f' && ptr[1] == 'd') + { + int num = atoi (ptr + 2); + free (canon); + return xasprintf ("fd%d", num); + } + free (canon); + return NULL; +} + +static char * +guess_baremetal_drive (const char *orig_path) +{ + char *canon; + char *ptr; + canon = canonicalize_file_name (orig_path); + if (!canon) + return NULL; + ptr = strrchr (orig_path, '/'); + if (ptr) + ptr++; + else + ptr = canon; + if (ptr[0] == 'h' && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("ata%d", num); + } + if (ptr[0] == 's' && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("ahci%d", num); + } + free (canon); + return NULL; +} + +static void +print_full_name (const char *drive, grub_device_t dev) +{ + char *dname = escape_of_path (drive); + if (dev->disk->partition) + { + char *pname = grub_partition_get_name (dev->disk->partition); + printf ("%s,%s", dname, pname); + free (pname); + } + else + printf ("%s", dname); + free (dname); +} + +static void +probe_abstraction (grub_disk_t disk) +{ + grub_disk_memberlist_t list = NULL, tmp; + int raid_level; + + if (disk->dev->memberlist) + list = disk->dev->memberlist (disk); + while (list) + { + probe_abstraction (list->disk); + + tmp = list->next; + free (list); + list = tmp; + } + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0) + printf ("lvm "); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0) + printf ("ldm "); + + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + grub_util_cryptodisk_print_abstraction (disk); + + raid_level = probe_raid_level (disk); + if (raid_level >= 0) + { + printf ("raid "); + if (disk->dev->raidname) + printf ("%s ", disk->dev->raidname (disk)); + } + if (raid_level == 5) + printf ("raid5rec "); + if (raid_level == 6) + printf ("raid6rec "); } static void @@ -99,19 +323,22 @@ probe (const char *path, char *device_name) if (path == NULL) { -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__sun__) if (! grub_util_check_char_device (device_name)) - grub_util_error ("%s is not a character device", device_name); + grub_util_error (_("%s is not a character device"), device_name); #else if (! grub_util_check_block_device (device_name)) - grub_util_error ("%s is not a block device", device_name); + grub_util_error (_("%s is not a block device"), device_name); #endif } else - device_name = grub_guess_root_device (path); + { + grub_path = canonicalize_file_name (path); + device_name = grub_guess_root_device (grub_path); + } if (! device_name) - grub_util_error ("cannot find a device for %s (is /dev mounted?)", path); + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path); if (print == PRINT_DEVICE) { @@ -121,7 +348,8 @@ probe (const char *path, char *device_name) drive_name = grub_util_get_grub_dev (device_name); if (! drive_name) - grub_util_error ("cannot find a GRUB drive for %s. Check your device.map", device_name); + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + device_name); if (print == PRINT_DRIVE) { @@ -132,97 +360,225 @@ probe (const char *path, char *device_name) grub_util_info ("opening %s", drive_name); dev = grub_device_open (drive_name); if (! dev) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); - if (print == PRINT_ABSTRACTION) + if (print == PRINT_HINT_STR) { - grub_disk_memberlist_t list = NULL, tmp; - const int is_lvm = (dev->disk->dev->id == GRUB_DISK_DEVICE_LVM_ID); - int is_raid = 0; - int is_raid5 = 0; - int is_raid6 = 0; - int raid_level; + const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); + const char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0; + char *biosname, *bare, *efi; + const char *map; - raid_level = probe_raid_level (dev->disk); - if (raid_level >= 0) + if (ofpath) { - is_raid = 1; - is_raid5 |= (raid_level == 5); - is_raid6 |= (raid_level == 6); + printf ("--hint-ieee1275='"); + print_full_name (ofpath, dev); + printf ("' "); } - if ((is_lvm) && (dev->disk->dev->memberlist)) - list = dev->disk->dev->memberlist (dev->disk); - while (list) + biosname = guess_bios_drive (device_name); + if (biosname) { - raid_level = probe_raid_level (list->disk); - if (raid_level >= 0) - { - is_raid = 1; - is_raid5 |= (raid_level == 5); - is_raid6 |= (raid_level == 6); - } - - tmp = list->next; - free (list); - list = tmp; + printf ("--hint-bios="); + print_full_name (biosname, dev); + printf (" "); } + free (biosname); - if (is_raid) + efi = guess_efi_drive (device_name); + if (efi) { - printf ("raid "); - if (is_raid5) - printf ("raid5rec "); - if (is_raid6) - printf ("raid6rec "); - printf ("mdraid "); + printf ("--hint-efi="); + print_full_name (efi, dev); + printf (" "); } + free (efi); - if (is_lvm) - printf ("lvm "); + bare = guess_baremetal_drive (device_name); + if (bare) + { + printf ("--hint-baremetal="); + print_full_name (bare, dev); + printf (" "); + } + free (bare); + /* FIXME: Add ARC hint. */ + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf ("--hint='"); + print_full_name (map, dev); + printf ("' "); + } printf ("\n"); goto end; } + if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT + || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT + || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) + && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) + { + print_full_name (dev->disk->name, dev); + printf ("\n"); + goto end; + } + + if (print == PRINT_COMPATIBILITY_HINT) + { + const char *map; + char *biosname; + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + print_full_name (map, dev); + printf ("\n"); + goto end; + } + biosname = guess_bios_drive (device_name); + if (biosname) + print_full_name (biosname, dev); + printf ("\n"); + free (biosname); + goto end; + } + + if (print == PRINT_BIOS_HINT) + { + char *biosname; + biosname = guess_bios_drive (device_name); + if (biosname) + print_full_name (biosname, dev); + printf ("\n"); + free (biosname); + goto end; + } + if (print == PRINT_IEEE1275_HINT) + { + const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); + const char *ofpath = grub_util_devname_to_ofpath (osdev); + const char *map; + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf (" "); + print_full_name (map, dev); + } + + if (ofpath) + { + printf (" "); + print_full_name (ofpath, dev); + } + + printf ("\n"); + goto end; + } + if (print == PRINT_EFI_HINT) + { + char *biosname; + char *name; + const char *map; + biosname = guess_efi_drive (device_name); + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf (" "); + print_full_name (map, dev); + } + if (biosname) + { + printf (" "); + print_full_name (biosname, dev); + } + + printf ("\n"); + free (biosname); + goto end; + } + + if (print == PRINT_BAREMETAL_HINT) + { + char *biosname; + char *name; + const char *map; + + biosname = guess_baremetal_drive (device_name); + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf (" "); + print_full_name (map, dev); + } + if (biosname) + { + printf (" "); + print_full_name (biosname, dev); + } + + printf ("\n"); + free (biosname); + goto end; + } + + if (print == PRINT_ARC_HINT) + { + const char *map; + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf (" "); + print_full_name (map, dev); + } + printf ("\n"); + + /* FIXME */ + + goto end; + } + + if (print == PRINT_ABSTRACTION) + { + probe_abstraction (dev->disk); + printf ("\n"); + goto end; + } + + if (print == PRINT_CRYPTODISK_UUID) + { + probe_cryptodisk_uuid (dev->disk); + printf ("\n"); + goto end; + } + if (print == PRINT_PARTMAP) { - grub_disk_memberlist_t list = NULL, tmp; - /* Check if dev->disk itself is contained in a partmap. */ probe_partmap (dev->disk); + printf ("\n"); + goto end; + } - /* In case of LVM/RAID, check the member devices as well. */ - if (dev->disk->dev->memberlist) - list = dev->disk->dev->memberlist (dev->disk); - while (list) - { - probe_partmap (list->disk); - /* LVM on RAID */ - if (list->disk->dev->memberlist) - { - grub_disk_memberlist_t sub_list; + if (print == PRINT_MSDOS_PARTTYPE) + { + if (dev->disk->partition + && strcmp(dev->disk->partition->partmap->name, "msdos") == 0) + printf ("%02x", dev->disk->partition->msdostype); - sub_list = list->disk->dev->memberlist (list->disk); - while (sub_list) - { - probe_partmap (sub_list->disk); - tmp = sub_list->next; - free (sub_list); - sub_list = tmp; - } - } - tmp = list->next; - free (list); - list = tmp; - } + printf ("\n"); goto end; } fs = grub_fs_probe (dev); if (! fs) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); if (print == PRINT_FS) { @@ -232,7 +588,7 @@ probe (const char *path, char *device_name) { char *uuid; if (! fs->uuid) - grub_util_error ("%s does not support UUIDs", fs->name); + grub_util_error (_("%s does not support UUIDs"), fs->name); if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); @@ -243,10 +599,10 @@ probe (const char *path, char *device_name) { char *label; if (! fs->label) - grub_util_error ("%s does not support labels", fs->name); + grub_util_error (_("%s does not support labels"), fs->name); if (fs->label (dev, &label) != GRUB_ERR_NONE) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); printf ("%s\n", label); } @@ -276,23 +632,23 @@ usage (int status) { if (status) fprintf (stderr, - "Try `%s --help' for more information.\n", program_name); + _("Try `%s --help' for more information.\n"), program_name); else - printf ("\ + printf (_("\ Usage: %s [OPTION]... [PATH|DEVICE]\n\ \n\ Probe device information for a given path (or device, if the -d option is given).\n\ \n\ -d, --device given argument is a system device, not a path\n\ -m, --device-map=FILE use FILE as the device map [default=%s]\n\ - -t, --target=(fs|fs_uuid|fs_label|drive|device|partmap|abstraction)\n\ - print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\ + -t, --target=(fs|fs_uuid|fs_label|drive|device|partmap|abstraction|cryptodisk_uuid|msdos_parttype)\n\ + print filesystem module, GRUB drive, system device, partition map module, abstraction module or CRYPTO UUID [default=fs]\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ -v, --verbose print verbose messages\n\ \n\ Report bugs to <%s>.\n\ -", program_name, +"), program_name, DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); exit (status); @@ -344,6 +700,24 @@ main (int argc, char *argv[]) print = PRINT_PARTMAP; else if (!strcmp (optarg, "abstraction")) print = PRINT_ABSTRACTION; + else if (!strcmp (optarg, "cryptodisk_uuid")) + print = PRINT_CRYPTODISK_UUID; + else if (!strcmp (optarg, "msdos_parttype")) + print = PRINT_MSDOS_PARTTYPE; + else if (!strcmp (optarg, "hints_string")) + print = PRINT_HINT_STR; + else if (!strcmp (optarg, "bios_hints")) + print = PRINT_BIOS_HINT; + else if (!strcmp (optarg, "ieee1275_hints")) + print = PRINT_IEEE1275_HINT; + else if (!strcmp (optarg, "baremetal_hints")) + print = PRINT_BAREMETAL_HINT; + else if (!strcmp (optarg, "efi_hints")) + print = PRINT_EFI_HINT; + else if (!strcmp (optarg, "arc_hints")) + print = PRINT_ARC_HINT; + else if (!strcmp (optarg, "compatibility_hint")) + print = PRINT_COMPATIBILITY_HINT; else usage (1); break; @@ -372,13 +746,13 @@ main (int argc, char *argv[]) /* Obtain ARGUMENT. */ if (optind >= argc) { - fprintf (stderr, "No path or device is specified.\n"); + fprintf (stderr, _("No path or device is specified.\n")); usage (1); } if (optind + 1 != argc) { - fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind + 1]); usage (1); } @@ -389,12 +763,13 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_gcry_init_all (); grub_lvm_fini (); grub_mdraid09_fini (); grub_mdraid1x_fini (); - grub_raid_fini (); - grub_raid_init (); + grub_diskfilter_fini (); + grub_diskfilter_init (); grub_mdraid09_init (); grub_mdraid1x_init (); grub_lvm_init (); @@ -406,6 +781,7 @@ main (int argc, char *argv[]) probe (argument, NULL); /* Free resources. */ + grub_gcry_fini_all (); grub_fini_all (); grub_util_biosdisk_fini (); diff --git a/util/grub-script-check.c b/util/grub-script-check.c index a872a0400..25358a553 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -51,9 +51,9 @@ usage (int status) { if (status) fprintf (stderr, - "Try ``%s --help'' for more information.\n", program_name); + _("Try ``%s --help'' for more information.\n"), program_name); else - printf ("\ + printf (_("\ Usage: %s [PATH]\n\ \n\ Checks GRUB script configuration file for syntax errors.\n\ @@ -63,7 +63,7 @@ Checks GRUB script configuration file for syntax errors.\n\ -v, --verbose print the script as it is being processed\n\ \n\ Report bugs to <%s>.\n\ -", program_name, +"), program_name, PACKAGE_BUGREPORT); exit (status); } @@ -73,6 +73,7 @@ main (int argc, char *argv[]) { char *argument; char *input; + int lineno = 0; FILE *file = 0; int verbose = 0; int found_input = 0; @@ -111,6 +112,7 @@ main (int argc, char *argv[]) cmdline[i] = '\0'; } + lineno++; *line = grub_strdup (cmdline); free (cmdline); @@ -155,7 +157,7 @@ main (int argc, char *argv[]) } else if (optind + 1 != argc) { - fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind + 1]); usage (1); } else @@ -189,5 +191,11 @@ main (int argc, char *argv[]) if (file) fclose (file); - return (found_input && script == 0); + if (found_input && script == 0) + { + fprintf (stderr, _("error: line no: %u\n"), lineno); + return 1; + } + + return 0; } diff --git a/util/grub-setup.c b/util/grub-setup.c index 920d867f2..3db3d1f96 100644 --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -1,7 +1,7 @@ /* grub-setup.c - make GRUB usable */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 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 @@ -32,7 +32,6 @@ #include #include #include -#include #include #ifdef GRUB_MACHINE_IEEE1275 #include @@ -49,6 +48,8 @@ #include #include "progname.h" #include +#include +#include #define _GNU_SOURCE 1 #include @@ -100,56 +101,12 @@ write_rootdev (char *core_img, grub_device_t root_dev, { #ifdef GRUB_MACHINE_PCBIOS { - grub_int32_t *install_dos_part, *install_bsd_part; - grub_int32_t dos_part, bsd_part; grub_uint8_t *boot_drive; grub_disk_addr_t *kernel_sector; boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE); kernel_sector = (grub_disk_addr_t *) (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR); - - install_dos_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE - + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART); - install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE - + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART); - - /* If we hardcoded drive as part of prefix, we don't want to - override the current setting. */ - if (*install_dos_part != -2) - { - /* Embed information about the installed location. */ - if (root_dev->disk->partition) - { - if (root_dev->disk->partition->parent) - { - if (root_dev->disk->partition->parent->parent) - grub_util_error ("Installing on doubly nested partitions is " - "not supported"); - dos_part = root_dev->disk->partition->parent->number; - bsd_part = root_dev->disk->partition->number; - } - else - { - dos_part = root_dev->disk->partition->number; - bsd_part = -1; - } - } - else - dos_part = bsd_part = -1; - } - else - { - dos_part = grub_le_to_cpu32 (*install_dos_part); - bsd_part = grub_le_to_cpu32 (*install_bsd_part); - } - - grub_util_info ("dos partition is %d, bsd partition is %d", - dos_part, bsd_part); - - *install_dos_part = grub_cpu_to_le32 (dos_part); - *install_bsd_part = grub_cpu_to_le32 (bsd_part); - /* FIXME: can this be skipped? */ *boot_drive = 0xFF; @@ -176,8 +133,8 @@ write_rootdev (char *core_img, grub_device_t root_dev, static void setup (const char *dir, const char *boot_file, const char *core_file, - const char *root, const char *dest, int must_embed, int force, - int fs_probe) + const char *root, const char *dest, int force, + int fs_probe, int allow_floppy) { char *boot_path, *core_path, *core_path_dev, *core_path_dev_full; char *boot_img, *core_img; @@ -282,22 +239,22 @@ setup (const char *dir, grub_util_info ("Opening root"); root_dev = grub_device_open (root); if (! root_dev) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); grub_util_info ("Opening dest"); dest_dev = grub_device_open (dest); if (! dest_dev) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); grub_util_info ("setting the root device to `%s'", root); if (grub_env_set ("root", root) != GRUB_ERR_NONE) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); #ifdef GRUB_MACHINE_PCBIOS /* Read the original sector from the disk. */ tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE); if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); #endif #ifdef GRUB_MACHINE_PCBIOS @@ -313,29 +270,18 @@ setup (const char *dir, /* If DEST_DRIVE is a hard disk, enable the workaround, which is for buggy BIOSes which don't pass boot drive correctly. Instead, they pass 0x00 or 0x01 even when booted from 0x80. */ - if (!grub_util_biosdisk_is_floppy (dest_dev->disk)) + if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)) /* Replace the jmp (2 bytes) with double nop's. */ *boot_drive_check = 0x9090; } #endif - /* Clean out the blocklists. */ - block = first_block; - while (block->len) - { - grub_memset (block, 0, sizeof (block)); - - block--; - - if ((char *) block <= core_img) - grub_util_error ("No terminator in the core image"); - } - #ifdef GRUB_MACHINE_PCBIOS { grub_partition_map_t dest_partmap = NULL; grub_partition_t container = dest_dev->disk->partition; int multiple_partmaps = 0; + int is_ldm; grub_err_t err; grub_disk_addr_t *sectors; int i; @@ -351,6 +297,12 @@ setup (const char *dir, { if (p->parent != container) return 0; + /* NetBSD and OpenBSD subpartitions have metadata inside a partition, + so they are safe to ignore. + */ + if (grub_strcmp (p->partmap->name, "netbsd") == 0 + || grub_strcmp (p->partmap->name, "openbsd") == 0) + return 0; if (dest_partmap == NULL) { dest_partmap = p->partmap; @@ -364,10 +316,21 @@ setup (const char *dir, grub_partition_iterate (dest_dev->disk, identify_partmap); + if (container && grub_strcmp (container->partmap->name, "msdos") == 0 + && dest_partmap + && (container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD + || container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD)) + { + grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); + goto unable_to_embed; + } + fs = grub_fs_probe (dest_dev); if (!fs) grub_errno = GRUB_ERR_NONE; + is_ldm = grub_util_is_ldm (dest_dev->disk); + #ifdef GRUB_MACHINE_PCBIOS if (fs_probe) { @@ -392,48 +355,97 @@ setup (const char *dir, "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " "by grub-setup (--skip-fs-probe disables this " "check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name); + if (is_ldm && dest_partmap && strcmp (dest_partmap->name, "msdos") != 0 + && strcmp (dest_partmap->name, "gpt") != 0) + grub_util_error (_("%s appears to contain a %s partition map and " + "LDM which isn't known to be a safe combination." + " Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data" + " is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), + dest_dev->disk->name, dest_partmap->name); + } #endif - if (! dest_partmap) - { - grub_util_warn (_("Attempting to install GRUB to a partitionless disk. This is a BAD idea.")); - goto unable_to_embed; - } - if (multiple_partmaps || fs) - { - grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); - goto unable_to_embed; - } - /* Copy the partition table. */ - if (dest_partmap) + if (dest_partmap || + (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))) memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); free (tmp_img); - if (!dest_partmap->embed) + if (! dest_partmap && ! fs && !is_ldm) { - grub_util_warn ("Partition style '%s' doesn't support embeding", + grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea.")); + goto unable_to_embed; + } + if (multiple_partmaps || (dest_partmap && fs) || (is_ldm && fs)) + { + grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet.")); + goto unable_to_embed; + } + + if (dest_partmap && !dest_partmap->embed) + { + grub_util_warn (_("Partition style '%s' doesn't support embeding"), dest_partmap->name); goto unable_to_embed; } + if (fs && !fs->embed) + { + grub_util_warn (_("File system '%s' doesn't support embeding"), + fs->name); + goto unable_to_embed; + } + nsec = core_sectors; - err = dest_partmap->embed (dest_dev->disk, &nsec, - GRUB_EMBED_PCBIOS, §ors); - if (nsec > 2 * core_sectors) - nsec = 2 * core_sectors; + if (is_ldm) + err = grub_util_ldm_embed (dest_dev->disk, &nsec, + GRUB_EMBED_PCBIOS, §ors); + else if (dest_partmap) + err = dest_partmap->embed (dest_dev->disk, &nsec, + GRUB_EMBED_PCBIOS, §ors); + else + err = fs->embed (dest_dev, &nsec, + GRUB_EMBED_PCBIOS, §ors); + if (!err && nsec < core_sectors) + { + err = grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("Your embedding area is unusually small. " + "core.img won't fit in it.")); + } if (err) { - grub_util_warn ("%s", grub_errmsg); + grub_util_warn ("%s", _(grub_errmsg)); grub_errno = GRUB_ERR_NONE; goto unable_to_embed; } + if (nsec > 2 * core_sectors) + nsec = 2 * core_sectors; + if (nsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) + >> GRUB_DISK_SECTOR_BITS)) + nsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) + >> GRUB_DISK_SECTOR_BITS); + + /* Clean out the blocklists. */ + block = first_block; + while (block->len) + { + grub_memset (block, 0, sizeof (block)); + + block--; + + if ((char *) block <= core_img) + grub_util_error (_("No terminator in the core image")); + } + save_first_sector (sectors[0] + grub_partition_get_start (container), 0, GRUB_DISK_SECTOR_SIZE); @@ -449,14 +461,26 @@ setup (const char *dir, + GRUB_DISK_SECTOR_SIZE - sizeof (*block)); + grub_size_t no_rs_length; *(grub_uint32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY) = grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size); + no_rs_length = grub_target_to_host16 + (*(grub_uint16_t *) (core_img + + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH)); - grub_reed_solomon_add_redundancy (core_img + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + GRUB_DISK_SECTOR_SIZE, - core_size - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART - GRUB_DISK_SECTOR_SIZE, + if (no_rs_length == 0xffff) + grub_util_error ("core.img version mismatch"); + + void *tmp = xmalloc (core_size); + grub_memcpy (tmp, core_img, core_size); + grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE, + core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE, nsec * GRUB_DISK_SECTOR_SIZE - core_size); + assert (grub_memcmp (tmp, core_img, core_size) == 0); + free (tmp); /* Make sure that the second blocklist is a terminator. */ block = first_block - 1; @@ -478,15 +502,23 @@ setup (const char *dir, unable_to_embed: - if (must_embed) - grub_util_error (_("embedding is not possible, but this is required when " - "the root device is on a RAID array or LVM volume")); +#ifdef GRUB_MACHINE_PCBIOS + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) + grub_util_error (_("embedding is not possible, but this is required for " + "cross-disk, RAID and LVM install")); +#else + if (dest_dev->disk->dev->id != root_dev->disk->dev->id) + grub_util_error (_("embedding is not possible, but this is required for " + "RAID and LVM install")); + +#endif grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this " "setup by using blocklists. However, blocklists are UNRELIABLE and " "their use is discouraged.")); if (! force) - grub_util_error (_("if you really want blocklists, use --force")); + grub_util_error (_("will not proceed with blocklists")); /* The core image must be put on a filesystem unfortunately. */ grub_util_info ("will leave the core image on the filesystem"); @@ -497,9 +529,7 @@ unable_to_embed: core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full); free (core_path_dev_full); - /* It is a Good Thing to sync two times. */ - sync (); - sync (); + grub_util_biosdisk_flush (root_dev->disk); #define MAX_TRIES 5 @@ -560,7 +590,7 @@ unable_to_embed: grub_util_info ("error message = %s", grub_errmsg); grub_errno = GRUB_ERR_NONE; - sync (); + grub_util_biosdisk_flush (root_dev->disk); sleep (1); } @@ -587,7 +617,7 @@ unable_to_embed: grub_file_filter_disable_compression (); file = grub_file_open (core_path_dev); if (! file) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); file->read_hook = save_first_sector; if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) @@ -648,11 +678,10 @@ unable_to_embed: /* Write the boot image onto the disk. */ if (grub_disk_write (dest_dev->disk, BOOT_SECTOR, 0, GRUB_DISK_SECTOR_SIZE, boot_img)) - grub_util_error ("%s", grub_errmsg); + grub_util_error ("%s", _(grub_errmsg)); - - /* Sync is a Good Thing. */ - sync (); + grub_util_biosdisk_flush (root_dev->disk); + grub_util_biosdisk_flush (dest_dev->disk); free (core_path); free (core_img); @@ -678,6 +707,9 @@ static struct argp_option options[] = { N_("Do not probe for filesystems in DEVICE"), 0}, {"verbose", 'v', 0, 0, N_("Print verbose messages."), 0}, + {"allow-floppy", 'a', 0, 0, + N_("Make the drive also bootable as floppy (default for fdX devices). May break on some BIOSes."), 0}, + { 0, 0, 0, 0, 0, 0 } }; @@ -712,6 +744,7 @@ struct arguments char *root_dev; int force; int fs_probe; + int allow_floppy; char *device; }; @@ -737,6 +770,10 @@ argp_parser (int key, char *arg, struct argp_state *state) switch (key) { + case 'a': + arguments->allow_floppy = 1; + break; + case 'b': if (arguments->boot_file) free (arguments->boot_file); @@ -814,7 +851,7 @@ Set up images to boot from DEVICE.\n\ \n\ You should not normally run this program directly. Use grub-install instead.") "\v"N_("\ -DEVICE must be an OS device (e.g. /dev/sda1)."), +DEVICE must be an OS device (e.g. /dev/sda)."), NULL, help_filter, NULL }; @@ -835,7 +872,6 @@ main (int argc, char *argv[]) { char *root_dev = NULL; char *dest_dev = NULL; - int must_embed = 0; struct arguments arguments; set_program_name (argv[0]); @@ -865,12 +901,13 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_gcry_init_all (); grub_lvm_fini (); grub_mdraid09_fini (); grub_mdraid1x_fini (); - grub_raid_fini (); - grub_raid_init (); + grub_diskfilter_fini (); + grub_diskfilter_init (); grub_mdraid09_init (); grub_mdraid1x_init (); grub_lvm_init (); @@ -925,41 +962,12 @@ main (int argc, char *argv[]) arguments.dir ? : DEFAULT_DIRECTORY); } -#ifdef __linux__ - if (grub_util_lvm_isvolume (root_dev)) - must_embed = 1; - - if (root_dev[0] == 'm' && root_dev[1] == 'd' - && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/')) - { - /* FIXME: we can avoid this on RAID1. */ - must_embed = 1; - } - - if (dest_dev[0] == 'm' && dest_dev[1] == 'd' - && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/')) - { - char **devicelist; - int i; - - devicelist = grub_util_raid_getmembers (dest_dev); - - for (i = 0; devicelist[i]; i++) - { - setup (arguments.dir ? : DEFAULT_DIRECTORY, - arguments.boot_file ? : DEFAULT_BOOT_FILE, - arguments.core_file ? : DEFAULT_CORE_FILE, - root_dev, grub_util_get_grub_dev (devicelist[i]), 1, - arguments.force, arguments.fs_probe); - } - } - else -#endif - /* Do the real work. */ - setup (arguments.dir ? : DEFAULT_DIRECTORY, - arguments.boot_file ? : DEFAULT_BOOT_FILE, - arguments.core_file ? : DEFAULT_CORE_FILE, - root_dev, dest_dev, must_embed, arguments.force, arguments.fs_probe); + /* Do the real work. */ + setup (arguments.dir ? : DEFAULT_DIRECTORY, + arguments.boot_file ? : DEFAULT_BOOT_FILE, + arguments.core_file ? : DEFAULT_CORE_FILE, + root_dev, dest_dev, arguments.force, + arguments.fs_probe, arguments.allow_floppy); /* Free resources. */ grub_fini_all (); diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 9ed3fc3a1..ece1b90da 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -19,13 +19,13 @@ set -e transform="@program_transform_name@" -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" locale_dir=`echo ${GRUB_PREFIX}/locale | sed ${transform}` -grub_lang=`echo $LANG | cut -d _ -f 1` +grub_lang=`echo $LANG | cut -d . -f 1` -. ${libdir}/grub/grub-mkconfig_lib +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" # Do this as early as possible, since other commands might depend on it. # (e.g. the `loadfont' command might need lvm or raid modules) @@ -36,7 +36,7 @@ done if [ "x${GRUB_DEFAULT}" = "x" ] ; then GRUB_DEFAULT=0 ; fi if [ "x${GRUB_DEFAULT}" = "xsaved" ] ; then GRUB_DEFAULT='${saved_entry}' ; fi if [ "x${GRUB_TIMEOUT}" = "x" ] ; then GRUB_TIMEOUT=5 ; fi -if [ "x${GRUB_GFXMODE}" = "x" ] ; then GRUB_GFXMODE=640x480 ; fi +if [ "x${GRUB_GFXMODE}" = "x" ] ; then GRUB_GFXMODE=auto ; fi if [ "x${GRUB_DEFAULT_BUTTON}" = "x" ] ; then GRUB_DEFAULT_BUTTON="$GRUB_DEFAULT" ; fi if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_entry}' ; fi @@ -84,11 +84,16 @@ if [ -n "${GRUB_VIDEO_BACKEND}" ]; then EOF else # Insert all available backends; GRUB will use the most appropriate. + have_video=0; for backend in $(cat "${GRUB_PREFIX}/video.lst"); do + have_video=1; cat <&2 ; exit 1 fi @@ -127,6 +132,19 @@ if loadfont `make_system_path_relative_to_its_root "${GRUB_FONT_PATH}"` ; then set gfxmode=${GRUB_GFXMODE} load_video insmod gfxterm +EOF + +# Gettext variables and module +if [ "x${LANG}" != "xC" ] && [ -d "${locale_dir}" ] ; then + prepare_grub_to_access_device $(${grub_probe} --target=device ${locale_dir}) | sed -e "s/^/ /" + cat << EOF + set locale_dir=(\$root)$(make_system_path_relative_to_its_root ${locale_dir}) + set lang=${grub_lang} + insmod gettext +EOF +fi + +cat <. -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" CLASS="--class gnu --class os" @@ -28,7 +28,7 @@ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU else OS="${GRUB_DISTRIBUTOR} GNU/Hurd" - CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" fi at_least_one=false @@ -81,14 +81,16 @@ do menuentry "${OS} ${KERNEL}" ${CLASS} { EOF prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading GNU Mach ...")" cat << EOF - echo '$(gettext_quoted "Loading GNU Mach ...")' + echo '$message' multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} EOF save_default_entry | sed -e "s/^/\t/" prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading the Hurd ...")" cat << EOF - echo '$(gettext_quoted "Loading the Hurd ...")' + echo '$message' module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ --multiboot-command-line='\${kernel-command-line}' \\ --host-priv-port='\${host-port}' \\ @@ -103,14 +105,15 @@ EOF menuentry "${OS} ${KERNEL} (recovery mode)" ${CLASS} { EOF prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading GNU Mach ...")" cat << EOF - echo '$(gettext_quoted "Loading GNU Mach ...")' + echo '$message' multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} -s EOF - save_default_entry | sed -e "s/^/\t/" prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading the Hurd ...")" cat << EOF - echo '$(gettext_quoted "Loading the Hurd ...")' + echo '$message' module /hurd/${hurd_fs}.static ${hurd_fs} \\ --multiboot-command-line='\${kernel-command-line}' \\ --host-priv-port='\${host-port}' \\ diff --git a/util/grub.d/10_illumos.in b/util/grub.d/10_illumos.in new file mode 100644 index 000000000..a4be7ba14 --- /dev/null +++ b/util/grub.d/10_illumos.in @@ -0,0 +1,52 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010,2011 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 . + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +CLASS="--class os" + +case "${GRUB_DISTRIBUTOR}" in + *) + OS="Illumos" + CLASS="--class illumos ${CLASS}" + ;; +esac + +echo "menuentry '${OS}' ${CLASS} {" +save_default_entry | sed -e "s/^/\t/" +prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" +message="$(gettext_printf "Loading kernel of Illumos ...")" + cat << EOF + insmod gzio + if cpuid -l ; then + ISADIR=amd64 + else + ISADIR= + fi + zfs-bootfs $($grub_mkrelpath /) ZFS_BOOTFS + multiboot $($grub_mkrelpath /platform/i86pc/kernel)/\$ISADIR/unix /platform/i86pc/kernel/\$ISADIR/unix -B \$ZFS_BOOTFS,console=text + module $($grub_mkrelpath /platform/i86pc)/\$ISADIR/boot_archive /platform/i86pc/\$ISADIR/boot_archive +} +EOF diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 591fbc4b1..dede4f6da 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -2,7 +2,7 @@ set -e # grub-mkconfig helper script. -# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# Copyright (C) 2006,2007,2008,2009,2010,2011 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,21 +17,20 @@ set -e # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" export TEXTDOMAIN=@PACKAGE@ -export TEXTDOMAINDIR=@localedir@ +export TEXTDOMAINDIR="@localedir@" CLASS="--class os" case "${GRUB_DISTRIBUTOR}" in Debian) OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" - CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) --class gnu-kfreebsd --class gnu ${CLASS}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) --class gnu-kfreebsd --class gnu ${CLASS}" ;; *) OS="FreeBSD" @@ -68,19 +67,26 @@ kfreebsd_entry () { os="$1" version="$2" - recovery="$3" # not used yet - args="$4" # not used yet - title="$(gettext_quoted "%s, with kFreeBSD %s")" + recovery="$3" + args="$4" + if ${recovery} ; then + title="$(gettext_quoted "%s, with kFreeBSD %s (recovery mode)")" + else + title="$(gettext_quoted "%s, with kFreeBSD %s")" + fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" - save_default_entry | sed -e "s/^/\t/" + if ! ${recovery} ; then + save_default_entry | sed -e "s/^/\t/" + fi if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" + message="$(gettext_printf "Loading kernel of FreeBSD %s ..." ${version})" cat << EOF - echo '$(printf "$(gettext_quoted "Loading kernel of FreeBSD %s ...")" ${version})' - kfreebsd ${rel_dirname}/${basename} + echo '$message' + kfreebsd ${rel_dirname}/${basename} ${args} EOF if test -n "${devices}" ; then @@ -91,6 +97,12 @@ EOF load_kfreebsd_module acpi true + for abstraction in dummy $(grub-probe -t abstraction --device ${GRUB_DEVICE}) ; do + case $abstraction in + lvm) load_kfreebsd_module geom_linux_lvm false ;; + esac + done + case "${kfreebsd_fs}" in zfs) load_kfreebsd_module opensolaris false @@ -103,7 +115,11 @@ EOF ;; esac - load_kfreebsd_module ${kfreebsd_fs} false + if [ x${kfreebsd_fs} = xufs ]; then + load_kfreebsd_module ${kfreebsd_fs} true + else + load_kfreebsd_module ${kfreebsd_fs} false + fi cat << EOF set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${kfreebsd_device} @@ -142,7 +158,7 @@ while [ "x$list" != "x" ] ; do # zpool name kfreebsd_device=$(grub-probe -t fs_label --device ${GRUB_DEVICE}) # filesystem name (empty string for the main filesystem) - kfreebsd_device="${kfreebsd_device}$(grub-mkrelpath / | sed -e "s,/*@$,,")" + kfreebsd_device="${kfreebsd_device}$(${grub_mkrelpath} / | sed -e "s,/*@$,,")" ;; *) kfreebsd_device=${kfreebsd_fs}id/${GRUB_DEVICE_UUID} @@ -172,7 +188,10 @@ while [ "x$list" != "x" ] ; do module_dir_rel=$(make_system_path_relative_to_its_root $module_dir) fi - kfreebsd_entry "${OS}" "${version}" + kfreebsd_entry "${OS}" "${version}" false + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + kfreebsd_entry "${OS}" "${version}" true "-s" + fi list=`echo $list | tr ' ' '\n' | grep -vx $kfreebsd | tr '\n' ' '` done diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index 14b85c7f1..d5586b375 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -17,14 +17,14 @@ set -e # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" export TEXTDOMAIN=@PACKAGE@ -export TEXTDOMAINDIR=@localedir@ +export TEXTDOMAINDIR="@localedir@" CLASS="--class gnu-linux --class gnu --class os" @@ -32,7 +32,7 @@ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" - CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but @@ -51,6 +51,14 @@ else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi +if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ]; then + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" + fi +fi + linux_entry () { os="$1" @@ -63,7 +71,9 @@ linux_entry () title="$(gettext_quoted "%s, with Linux %s")" fi printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" - save_default_entry | sed -e "s/^/\t/" + if ! ${recovery} ; then + save_default_entry | sed -e "s/^/\t/" + fi # Use ELILO's generic "efifb" when it's known to be available. # FIXME: We need an interface to select vesafb in case efifb can't be used. @@ -71,29 +81,47 @@ linux_entry () cat << EOF load_video EOF - if grep -qx "CONFIG_FB_EFI=y" /boot/config-${version} 2> /dev/null \ - && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" /boot/config-${version} 2> /dev/null; then + if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ + && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then cat << EOF set gfxpayload=keep EOF fi else + if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then + cat << EOF + load_video +EOF + fi cat << EOF set gfxpayload=$GRUB_GFXPAYLOAD_LINUX EOF fi - if [ -z "${prepare_boot_cache}" ]; then - prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" - fi - printf '%s\n' "${prepare_boot_cache}" cat << EOF - echo '$(printf "$(gettext_quoted "Loading Linux %s ...")" ${version})' + insmod gzio +EOF + + if [ x$dirname = x/ ]; then + if [ -z "${prepare_root_cache}" ]; then + prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_root_cache}" + else + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" + fi + message="$(gettext_printf "Loading Linux %s ..." ${version})" + cat << EOF + echo '$message' linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} EOF if test -n "${initrd}" ; then + message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF - echo '$(gettext_quoted "Loading initial ramdisk ...")' + echo '$message' initrd ${rel_dirname}/${initrd} EOF fi @@ -102,10 +130,19 @@ EOF EOF } -list=`for i in /boot/vmlinu[zx]-* /vmlinu[zx]-* ; do - if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi - done` +case x`uname -m` in + xi?86 | xx86_64) + list=`for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` ;; + *) + list=`for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` ;; +esac + prepare_boot_cache= +prepare_root_cache= while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` @@ -118,25 +155,42 @@ while [ "x$list" != "x" ] ; do linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" initrd= - for i in "initrd.img-${version}" "initrd-${version}.img" \ + for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \ "initrd-${version}" "initramfs-${version}.img" \ "initrd.img-${alt_version}" "initrd-${alt_version}.img" \ - "initrd-${alt_version}" "initramfs-${alt_version}.img"; do + "initrd-${alt_version}" "initramfs-${alt_version}.img" \ + "initramfs-genkernel-${version}" \ + "initramfs-genkernel-${alt_version}"; do if test -e "${dirname}/${i}" ; then initrd="$i" break fi done + + config= + for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do + if test -e "${i}" ; then + config="${i}" + break + fi + done + + initramfs= + if test -n "${config}" ; then + initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"` + fi + if test -n "${initrd}" ; then echo "Found initrd image: ${dirname}/${initrd}" >&2 - else - # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. + elif test -z "${initramfs}" ; then + # "UUID=" magic is parsed by initrd or initramfs. Since there's + # no initrd or builtin initramfs, it can't work here. linux_root_device_thisversion=${GRUB_DEVICE} fi linux_entry "${OS}" "${version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" - if [ "x${GRUB_DISABLE_LINUX_RECOVERY}" != "xtrue" ]; then + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" true \ "single ${GRUB_CMDLINE_LINUX}" fi diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in index 1a8c4eb36..df095ddc0 100644 --- a/util/grub.d/10_netbsd.in +++ b/util/grub.d/10_netbsd.in @@ -17,21 +17,74 @@ set -e # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" export TEXTDOMAIN=@PACKAGE@ -export TEXTDOMAINDIR=@localedir@ +export TEXTDOMAINDIR="@localedir@" if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then - OS=NetBSD + OS="NetBSD" else OS="${GRUB_DISTRIBUTOR} NetBSD" fi +netbsd_load_fs_module () +{ + loader="$1" # "knetbsd" or "multiboot" + kernel="$2" # absolute path to the kernel file + + case $(zcat -f "${kernel}" | file -bL - | cut -d , -f 2 | tr -d ' ') in + Intel80386) + karch="i386" + ;; + x86-64) + karch="amd64" + ;; + *) + return + ;; + esac + + case $(${grub_probe} --target=fs -d ${GRUB_DEVICE}) in + ext2) + kmod="ext2fs" + ;; + fat) + kmod="msdosfs" + ;; + ntfs) + kmod="ntfs" + ;; + ufs*) + kmod="ffs" + ;; + *) + return + ;; + esac + + kversion=$(zcat -f "${kernel}" | strings | sed -n -e '/^@(#)NetBSD/ { s/^@(#)NetBSD \([0-9\.]*\) .*$/\1/g ; p ; q ; }') + kmodule="/stand/${karch}/${kversion}/modules/${kmod}/${kmod}.kmod" + + if test -z "$karch" -o -z "$kversion" -o ! -f "${kmodule}"; then + return + fi + + kmodule_rel=$(make_system_path_relative_to_its_root "$kmodule") || return + prepare_grub_to_access_device $(${grub_probe} -t device "${kmodule}") | sed -e 's,^, ,' + case "${loader}" in + knetbsd) + printf "\tknetbsd_module_elf %s\n" "${kmodule_rel}" + ;; + multiboot) + printf "\tmodule %s\n" "${kmodule_rel}" + ;; + esac +} + netbsd_entry () { loader="$1" # "knetbsd" or "multiboot" @@ -59,6 +112,9 @@ netbsd_entry () "${kernel}" "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" ;; esac + + netbsd_load_fs_module "${loader}" "${kernel}" + printf "}\n" } @@ -72,15 +128,14 @@ for k in $(ls -t /netbsd*) ; do if ! grub_file_is_not_garbage "$k" ; then continue fi - if ! ((file -bL "$k" | grep -q "${pattern}") || - (zcat "$k" | file -bL - | grep -q "${pattern}")) 2>/dev/null ; then + if ! (zcat -f "$k" | file -bL - | grep -q "${pattern}") 2>/dev/null ; then continue fi echo "Found NetBSD kernel: $k" >&2 netbsd_entry "knetbsd" "$k" false "${GRUB_CMDLINE_NETBSD_DEFAULT}" netbsd_entry "multiboot" "$k" false "${GRUB_CMDLINE_NETBSD_DEFAULT}" - if [ "x${GRUB_DISABLE_NETBSD_RECOVERY}" != "xtrue" ]; then + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then netbsd_entry "knetbsd" "$k" true "-s" netbsd_entry "multiboot" "$k" true "-s" fi diff --git a/util/grub.d/10_windows.in b/util/grub.d/10_windows.in index fd068dd2d..8ee75d261 100644 --- a/util/grub.d/10_windows.in +++ b/util/grub.d/10_windows.in @@ -17,10 +17,11 @@ set -e # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" case "`uname 2>/dev/null`" in CYGWIN*) ;; @@ -41,14 +42,14 @@ get_os_name_from_boot_ini () sort | uniq | wc -l`" = 1 || return 1 # Search 'default=PARTITION' - local part=`sed -n 's,^default=,,p' "$1" | sed 's,\\\\,/,g;s,[ \t\r]*$,,;1q'` - test -n "$part" || return 1 + get_os_name_from_boot_ini_part=`sed -n 's,^default=,,p' "$1" | sed 's,\\\\,/,g;s,[ \t\r]*$,,;1q'` + test -n "$get_os_name_from_boot_ini_part" || return 1 # Search 'PARTITION="NAME" ...' - local name=`sed -n 's,\\\\,/,g;s,^'"$part"'="\([^"]*\)".*$,\1,p' "$1" | sed 1q` - test -n "$name" || return 1 + get_os_name_from_boot_ini_name=`sed -n 's,\\\\,/,g;s,^'"$get_os_name_from_boot_ini_part"'="\([^"]*\)".*$,\1,p' "$1" | sed 1q` + test -n "$get_os_name_from_boot_ini_name" || return 1 - echo "$name" + echo "$get_os_name_from_boot_ini_name" } diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in index 5333d44ec..ab6319feb 100644 --- a/util/grub.d/20_linux_xen.in +++ b/util/grub.d/20_linux_xen.in @@ -17,14 +17,14 @@ set -e # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ -libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" export TEXTDOMAIN=@PACKAGE@ -export TEXTDOMAINDIR=@localedir@ +export TEXTDOMAINDIR="@localedir@" CLASS="--class gnu-linux --class gnu --class os --class xen" @@ -32,7 +32,7 @@ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then OS=GNU/Linux else OS="${GRUB_DISTRIBUTOR} GNU/Linux" - CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr '[A-Z]' '[a-z]' | cut -d' ' -f1) ${CLASS}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" fi # loop-AES arranges things so that /dev/loop/X can be our root device, but @@ -51,6 +51,22 @@ else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} fi +# Allow overriding GRUB_CMDLINE_LINUX and GRUB_CMDLINE_LINUX_DEFAULT. +if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE}" ]; then + GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX_XEN_REPLACE}" +fi +if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" ]; then + GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" +fi + +if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ]; then + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" + fi +fi + linux_entry () { os="$1" @@ -60,25 +76,31 @@ linux_entry () args="$5" xen_args="$6" if ${recovery} ; then - title="$(gettext_quoted "%s, with Linux %s and XEN %s (recovery mode)")" + title="$(gettext_quoted "%s, with Xen %s and Linux %s (recovery mode)")" else - title="$(gettext_quoted "%s, with Linux %s and XEN %s")" + title="$(gettext_quoted "%s, with Xen %s and Linux %s")" + fi + printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${xen_version}" "${version}" + if ! ${recovery} ; then + save_default_entry | sed -e "s/^/\t/" fi - printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" "${xen_version}" - save_default_entry | sed -e "s/^/\t/" if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi printf '%s\n' "${prepare_boot_cache}" + xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})" + lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" cat << EOF - echo '$(printf "$(gettext_quoted "Loading Linux %s ...")" ${version})' + echo '$xmessage' multiboot ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} + echo '$lmessage' module ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} EOF if test -n "${initrd}" ; then + message="$(gettext_printf "Loading initial ramdisk ...")" cat << EOF - echo '$(gettext_quoted "Loading initial ramdisk ...")' + echo '$message' module ${rel_dirname}/${initrd} EOF fi @@ -87,11 +109,24 @@ EOF EOF } -linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do +linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* /boot/kernel-*; do + if grub_file_is_not_garbage "$i"; then basename=$(basename $i) version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") - if grub_file_is_not_garbage "$i" && grep -qx "CONFIG_XEN_DOM0=y" /boot/config-${version} 2> /dev/null ; then echo -n "$i " ; fi - done` + dirname=$(dirname $i) + config= + for j in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do + if test -e "${j}" ; then + config="${j}" + break + fi + done + if (grep -qx "CONFIG_XEN_DOM0=y" "${config}" 2> /dev/null || grep -qx "CONFIG_XEN_PRIVILEGED_GUEST=y" "${config}" 2> /dev/null); then echo -n "$i " ; fi + fi + done` +if [ "x${linux_list}" = "x" ] ; then + exit 0 +fi xen_list=`for i in /boot/xen*; do if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` @@ -118,7 +153,9 @@ while [ "x${xen_list}" != "x" ] ; do initrd= for i in "initrd.img-${version}" "initrd-${version}.img" \ "initrd-${version}" "initrd.img-${alt_version}" \ - "initrd-${alt_version}.img" "initrd-${alt_version}"; do + "initrd-${alt_version}.img" "initrd-${alt_version}" \ + "initramfs-genkernel-${version}" \ + "initramfs-genkernel-${alt_version}" ; do if test -e "${dirname}/${i}" ; then initrd="$i" break @@ -133,7 +170,7 @@ while [ "x${xen_list}" != "x" ] ; do linux_entry "${OS}" "${version}" "${xen_version}" false \ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" - if [ "x${GRUB_DISABLE_LINUX_RECOVERY}" != "xtrue" ]; then + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" "${xen_version}" true \ "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}" fi diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 728ac2378..5f4515240 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -17,11 +17,11 @@ set -e # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" -. ${libdir}/grub/grub-mkconfig_lib +. "@datadir@/@PACKAGE@/grub-mkconfig_lib" if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then exit 0 @@ -111,7 +111,7 @@ EOF prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" case ${LONGNAME} in - Windows\ Vista*|Windows\ 7*) + Windows\ Vista*|Windows\ 7*|Windows\ Server\ 2008*) ;; *) cat << EOF @@ -168,7 +168,7 @@ EOF done ;; macosx) - OSXUUID="`grub-probe --target=fs_uuid --device ${DEVICE} 2> /dev/null`" + OSXUUID="`${grub_probe} --target=fs_uuid --device ${DEVICE} 2> /dev/null`" osx_entry xnu_kernel 32 osx_entry xnu_kernel64 64 ;; diff --git a/util/ieee1275/devicemap.c b/util/ieee1275/devicemap.c deleted file mode 100644 index 19ab746ef..000000000 --- a/util/ieee1275/devicemap.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* Since OF path names can have "," characters in them, and GRUB - internally uses "," to indicate partitions (unlike OF which uses - ":" for this purpose) we escape such commas. */ - -static char * -escape_of_path (const char *orig_path) -{ - char *new_path, *d, c; - const char *p; - - if (!strchr (orig_path, ',')) - return (char *) orig_path; - - new_path = xmalloc (strlen (orig_path) * 2); - - p = orig_path; - d = new_path; - while ((c = *p++) != '\0') - { - if (c == ',') - *d++ = '\\'; - *d++ = c; - } - - free ((char *) orig_path); - - return new_path; -} - -void -grub_util_emit_devicemap_entry (FILE *fp, char *name, - int is_floppy __attribute__((unused)), - int *num_fd __attribute__((unused)), - int *num_hd __attribute__((unused))) -{ - const char *orig_path = grub_util_devname_to_ofpath (name); - char *ofpath = escape_of_path (orig_path); - - fprintf(fp, "(%s)\t%s\n", ofpath, name); - - free (ofpath); -} diff --git a/util/ieee1275/grub-ofpathname.c b/util/ieee1275/grub-ofpathname.c index 3ac6fce8b..03d47bc99 100644 --- a/util/ieee1275/grub-ofpathname.c +++ b/util/ieee1275/grub-ofpathname.c @@ -24,6 +24,8 @@ #include "progname.h" +#include + int main(int argc, char **argv) { char *of_path; @@ -32,9 +34,14 @@ int main(int argc, char **argv) grub_util_init_nls (); - if (argc != 2) + if (argc != 2 || strcmp (argv[1], "--help") == 0) { - printf("Usage: %s DEVICE\n", program_name); + printf(_("Usage: %s DEVICE\n"), program_name); + return 1; + } + if (strcmp (argv[1], "--version") == 0) + { + printf ("%s\n", PACKAGE_STRING); return 1; } diff --git a/util/ieee1275/ofpath.c b/util/ieee1275/ofpath.c index fa0d48cf9..9b3825fc2 100644 --- a/util/ieee1275/ofpath.c +++ b/util/ieee1275/ofpath.c @@ -23,6 +23,7 @@ #include #include #include +#include #endif #include @@ -53,6 +54,19 @@ grub_util_error (const char *fmt, ...) exit (1); } +void +grub_util_info (const char *fmt, ...) +{ + va_list ap; + + fprintf (stderr, "ofpath: info: "); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputc ('\n', stderr); +} + +#define _(x) x #endif static void @@ -81,64 +95,95 @@ trim_newline (char *path) *end-- = '\0'; } -#define OF_PATH_MAX 256 +#define MAX_DISK_CAT 64 -static void -find_obppath(char *of_path, const char *sysfs_path_orig) +static char * +find_obppath (const char *sysfs_path_orig) { char *sysfs_path, *path; + size_t path_size = strlen (sysfs_path_orig) + sizeof ("/obppath"); - sysfs_path = xmalloc (PATH_MAX); - path = xmalloc (PATH_MAX); + sysfs_path = xstrdup (sysfs_path_orig); + path = xmalloc (path_size); - strcpy(sysfs_path, sysfs_path_orig); while (1) { int fd; + char *of_path; + struct stat st; + size_t size; - snprintf(path, PATH_MAX, "%s/obppath", sysfs_path); + snprintf(path, path_size, "%s/obppath", sysfs_path); #if 0 printf("Trying %s\n", path); #endif fd = open(path, O_RDONLY); - if (fd < 0) + if (fd < 0 || fstat (fd, &st) < 0) { kill_trailing_dir(sysfs_path); if (!strcmp(sysfs_path, "/sys")) - grub_util_error("'obppath' not found in parent dirs of %s", - sysfs_path_orig); + { + grub_util_info (_("'obppath' not found in parent dirs of %s," + " no IEEE1275 name discovery"), + sysfs_path_orig); + free (path); + free (sysfs_path); + return NULL; + } continue; } - memset(of_path, 0, OF_PATH_MAX); - read(fd, of_path, OF_PATH_MAX); + size = st.st_size; + of_path = xmalloc (size + MAX_DISK_CAT + 1); + memset(of_path, 0, size + MAX_DISK_CAT + 1); + read(fd, of_path, size); close(fd); trim_newline(of_path); - break; + free (path); + free (sysfs_path); + return of_path; } - - free (path); - free (sysfs_path); } -static void -block_device_get_sysfs_path_and_link(const char *devicenode, - char *sysfs_path, int sysfs_path_len) +static char * +xrealpath (const char *in) { - char *rpath = xmalloc (PATH_MAX); + char *out; +#ifdef PATH_MAX + out = xmalloc (PATH_MAX); + out = realpath (in, out); +#else + out = realpath (in, NULL); +#endif + if (!out) + grub_util_error (_("cannot get the real path of `%s'"), in); + return out; +} - snprintf(sysfs_path, sysfs_path_len, "/sys/block/%s", devicenode); +static char * +block_device_get_sysfs_path_and_link(const char *devicenode) +{ + char *rpath; + char *rpath2; + char *ret; + size_t tmp_size = strlen (devicenode) + sizeof ("/sys/block/"); + char *tmp = xmalloc (tmp_size); - if (!realpath (sysfs_path, rpath)) - grub_util_error ("cannot get the real path of `%s'", sysfs_path); + memcpy (tmp, "/sys/block/", sizeof ("/sys/block/")); + strcat (tmp, devicenode); - strcat(rpath, "/device"); + rpath = xrealpath (tmp); + rpath2 = xmalloc (strlen (rpath) + sizeof ("/device")); + strcpy (rpath2, rpath); + strcat (rpath2, "/device"); - if (!realpath (rpath, sysfs_path)) - grub_util_error ("cannot get the real path of `%s'", rpath); + ret = xrealpath (rpath2); + free (tmp); free (rpath); + free (rpath2); + return ret; } static const char * @@ -157,28 +202,31 @@ trailing_digits (const char *p) return end + 1; } -static void -__of_path_common(char *of_path, char *sysfs_path, +static char * +__of_path_common(char *sysfs_path, const char *device, int devno) { const char *digit_string; - char disk[64]; + char disk[MAX_DISK_CAT]; + char *of_path = find_obppath(sysfs_path); - find_obppath(of_path, sysfs_path); + if (!of_path) + return NULL; digit_string = trailing_digits (device); if (*digit_string == '\0') { - sprintf(disk, "/disk@%d", devno); + snprintf(disk, sizeof (disk), "/disk@%d", devno); } else { int part; sscanf(digit_string, "%d", &part); - sprintf(disk, "/disk@%d:%c", devno, 'a' + (part - 1)); + snprintf(disk, sizeof (disk), "/disk@%d:%c", devno, 'a' + (part - 1)); } strcat(of_path, disk); + return of_path; } static char * @@ -196,71 +244,70 @@ get_basename(char *p) return ret; } -static void -of_path_of_vdisk(char *of_path, - const char *devname __attribute__((unused)), +static char * +of_path_of_vdisk(const char *devname __attribute__((unused)), const char *device, const char *devnode __attribute__((unused)), const char *devicenode) { char *sysfs_path, *p; int devno, junk; + char *ret; - sysfs_path = xmalloc (PATH_MAX); - block_device_get_sysfs_path_and_link(devicenode, - sysfs_path, PATH_MAX); + sysfs_path = block_device_get_sysfs_path_and_link(devicenode); p = get_basename (sysfs_path); sscanf(p, "vdc-port-%d-%d", &devno, &junk); - __of_path_common(of_path, sysfs_path, device, devno); + ret = __of_path_common (sysfs_path, device, devno); free (sysfs_path); + return ret; } -static void -of_path_of_ide(char *of_path, - const char *devname __attribute__((unused)), const char *device, +static char * +of_path_of_ide(const char *devname __attribute__((unused)), const char *device, const char *devnode __attribute__((unused)), const char *devicenode) { char *sysfs_path, *p; int chan, devno; + char *ret; - sysfs_path = xmalloc (PATH_MAX); - block_device_get_sysfs_path_and_link(devicenode, - sysfs_path, PATH_MAX); + sysfs_path = block_device_get_sysfs_path_and_link(devicenode); p = get_basename (sysfs_path); sscanf(p, "%d.%d", &chan, &devno); - __of_path_common(of_path, sysfs_path, device, devno); + ret = __of_path_common(sysfs_path, device, 2 * chan + devno); free (sysfs_path); + return ret; } static int vendor_is_ATA(const char *path) { int fd, err; - char *buf; + char *bufname; + char bufcont[3]; + size_t path_size; - buf = xmalloc (PATH_MAX); + path_size = strlen (path) + sizeof ("/vendor"); - snprintf(buf, PATH_MAX, "%s/vendor", path); - fd = open(buf, O_RDONLY); + bufname = xmalloc (path_size); + + snprintf(bufname, path_size, "%s/vendor", path); + fd = open(bufname, O_RDONLY); if (fd < 0) - grub_util_error ("cannot open 'vendor' node of `%s'", path); + grub_util_error (_("cannot open 'vendor' node of `%s'"), path); - memset(buf, 0, PATH_MAX); - err = read(fd, buf, PATH_MAX); + memset(bufcont, 0, sizeof (bufcont)); + err = read(fd, bufcont, sizeof (bufcont)); if (err < 0) - grub_util_error ("cannot read 'vendor' node of `%s'", path); + grub_util_error (_("cannot read 'vendor' node of `%s'"), path); close(fd); + free (bufname); - free (buf); - - if (!strncmp(buf, "ATA", 3)) - return 1; - return 0; + return (memcmp(bufcont, "ATA", 3) == 0); } static void @@ -270,6 +317,7 @@ check_sas (char *sysfs_path, int *tgt) char *p, *q, *path; char phy[16]; int fd; + size_t path_size; if (!ed) return; @@ -283,12 +331,14 @@ check_sas (char *sysfs_path, int *tgt) q++; *q = '\0'; - path = xmalloc (PATH_MAX); - sprintf (path, "%s/sas_device:%s/phy_identifier", p, ed); + path_size = (strlen (p) + strlen (ed) + + sizeof ("%s/sas_device:%s/phy_identifier")); + path = xmalloc (path_size); + snprintf (path, path_size, "%s/sas_device:%s/phy_identifier", p, ed); fd = open(path, O_RDONLY); if (fd < 0) - grub_util_error("cannot open SAS PHY ID `%s'\n", path); + grub_util_error(_("cannot open SAS PHY ID `%s'\n"), path); memset (phy, 0, sizeof (phy)); read (fd, phy, sizeof (phy)); @@ -297,35 +347,35 @@ check_sas (char *sysfs_path, int *tgt) free (path); free (p); + close (fd); } -static void -of_path_of_scsi(char *of_path, - const char *devname __attribute__((unused)), const char *device, +static char * +of_path_of_scsi(const char *devname __attribute__((unused)), const char *device, const char *devnode __attribute__((unused)), const char *devicenode) { const char *p, *digit_string, *disk_name; int host, bus, tgt, lun; - char *sysfs_path, disk[64]; + char *sysfs_path, disk[MAX_DISK_CAT - sizeof ("/fp@0,0")]; + char *of_path; - sysfs_path = xmalloc (PATH_MAX); - - block_device_get_sysfs_path_and_link(devicenode, - sysfs_path, PATH_MAX); + sysfs_path = block_device_get_sysfs_path_and_link(devicenode); p = get_basename (sysfs_path); sscanf(p, "%d:%d:%d:%d", &host, &bus, &tgt, &lun); check_sas (sysfs_path, &tgt); if (vendor_is_ATA(sysfs_path)) { - __of_path_common(of_path, sysfs_path, device, tgt); + of_path = __of_path_common(sysfs_path, device, tgt); free (sysfs_path); - return; + return of_path; } - find_obppath(of_path, sysfs_path); + of_path = find_obppath(sysfs_path); free (sysfs_path); + if (!of_path) + return NULL; if (strstr (of_path, "qlc")) strcat (of_path, "/fp@0,0"); @@ -338,16 +388,18 @@ of_path_of_scsi(char *of_path, digit_string = trailing_digits (device); if (*digit_string == '\0') { - sprintf(disk, "/%s@%x,%d", disk_name, tgt, lun); + snprintf(disk, sizeof (disk), "/%s@%x,%d", disk_name, tgt, lun); } else { int part; sscanf(digit_string, "%d", &part); - sprintf(disk, "/%s@%x,%d:%c", disk_name, tgt, lun, 'a' + (part - 1)); + snprintf(disk, sizeof (disk), + "/%s@%x,%d:%c", disk_name, tgt, lun, 'a' + (part - 1)); } strcat(of_path, disk); + return of_path; } static char * @@ -372,25 +424,30 @@ grub_util_devname_to_ofpath (const char *devname) { char *name_buf, *device, *devnode, *devicenode, *ofpath; - name_buf = xmalloc (PATH_MAX); - name_buf = realpath (devname, name_buf); - if (! name_buf) - grub_util_error ("cannot get the real path of `%s'", devname); + name_buf = xrealpath (devname); - device = get_basename (devname); - devnode = strip_trailing_digits (devname); + device = get_basename (name_buf); + devnode = strip_trailing_digits (name_buf); devicenode = strip_trailing_digits (device); - ofpath = xmalloc (OF_PATH_MAX); - if (device[0] == 'h' && device[1] == 'd') - of_path_of_ide(ofpath, name_buf, device, devnode, devicenode); + ofpath = of_path_of_ide(name_buf, device, devnode, devicenode); else if (device[0] == 's' && (device[1] == 'd' || device[1] == 'r')) - of_path_of_scsi(ofpath, name_buf, device, devnode, devicenode); + ofpath = of_path_of_scsi(name_buf, device, devnode, devicenode); else if (device[0] == 'v' && device[1] == 'd' && device[2] == 'i' && device[3] == 's' && device[4] == 'k') - of_path_of_vdisk(ofpath, name_buf, device, devnode, devicenode); + ofpath = of_path_of_vdisk(name_buf, device, devnode, devicenode); + else if (device[0] == 'f' && device[1] == 'd' + && device[2] == '0' && device[3] == '\0') + /* All the models I've seen have a devalias "floppy". + New models have no floppy at all. */ + ofpath = xstrdup ("floppy"); + else + { + grub_util_warn (_("unknown device type %s\n"), device); + return NULL; + } free (devnode); free (devicenode); @@ -406,12 +463,14 @@ int main(int argc, char **argv) if (argc != 2) { - printf("Usage: grub-ofpathname DEVICE\n"); + printf(_("Usage: %s DEVICE\n"), argv[0]); return 1; } of_path = grub_util_devname_to_ofpath (argv[1]); - printf("%s\n", of_path); + if (of_path) + printf("%s\n", of_path); + free (of_path); return 0; } diff --git a/util/import_gcry.py b/util/import_gcry.py index 494a4ae7b..e55ffd97b 100644 --- a/util/import_gcry.py +++ b/util/import_gcry.py @@ -20,6 +20,7 @@ import re import sys import os import datetime +import codecs if len (sys.argv) < 3: print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) @@ -40,9 +41,17 @@ except: print ("WARNING: %s already exists" % cipher_dir_out) cipher_files = os.listdir (cipher_dir_in) -conf = open (os.path.join ("grub-core", "Makefile.gcry.def"), "w") +conf = codecs.open (os.path.join ("grub-core", "Makefile.gcry.def"), "w", "utf-8") conf.write ("AutoGen definitions Makefile.tpl;\n\n") +confutil = codecs.open ("Makefile.utilgcry.def", "w", "utf-8") +confutil.write ("AutoGen definitions Makefile.tpl;\n\n") +confutil.write ("library = {\n"); +confutil.write (" name = libgrubgcry.a;\n"); +confutil.write (" cflags = '$(CFLAGS_GCRY)';\n"); +confutil.write (" cppflags = '$(CPPFLAGS_GCRY)';\n"); +confutil.write ("\n"); chlog = "" +modules = [] # Strictly speaking CRC32/CRC24 work on bytes so this value should be 1 # But libgcrypt uses 64. Let's keep the value for compatibility. Since @@ -61,7 +70,7 @@ mdblocksizes = {"_gcry_digest_spec_crc32" : 64, "_gcry_digest_spec_tiger" : 64, "_gcry_digest_spec_whirlpool" : 64} -cryptolist = open (os.path.join (cipher_dir_out, "crypto.lst"), "w") +cryptolist = codecs.open (os.path.join (cipher_dir_out, "crypto.lst"), "w", "utf-8") # rijndael is the only cipher using aliases. So no need for mangling, just # hardcode it @@ -73,6 +82,9 @@ cryptolist.write ("AES-128: gcry_rijndael\n"); cryptolist.write ("AES-192: gcry_rijndael\n"); cryptolist.write ("AES-256: gcry_rijndael\n"); +cryptolist.write ("ADLER32: adler32\n"); +cryptolist.write ("CRC64: crc64\n"); + for cipher_file in cipher_files: infile = os.path.join (cipher_dir_in, cipher_file) outfile = os.path.join (cipher_dir_out, cipher_file) @@ -88,16 +100,34 @@ for cipher_file in cipher_files: nch = False if re.match (".*\.[ch]$", cipher_file): isc = re.match (".*\.c$", cipher_file) - f = open (infile, "r") - fw = open (outfile, "w") + f = codecs.open (infile, "r", "utf-8") + fw = codecs.open (outfile, "w", "utf-8") fw.write ("/* This file was automatically imported with \n") - fw.write (" import_gcry.py. Please don't modify it */\n"); + fw.write (" import_gcry.py. Please don't modify it */\n") + fw.write ("#include \n") + if cipher_file == "camellia.h": + fw.write ("#include \n") + fw.write ("void camellia_setup128(const unsigned char *key, grub_uint32_t *subkey);\n") + fw.write ("void camellia_setup192(const unsigned char *key, grub_uint32_t *subkey);\n") + fw.write ("void camellia_setup256(const unsigned char *key, grub_uint32_t *subkey);\n") + fw.write ("void camellia_encrypt128(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_encrypt192(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_encrypt256(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_decrypt128(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_decrypt192(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_decrypt256(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("#define memcpy grub_memcpy\n") + # Whole libgcrypt is distributed under GPLv3+ or compatible + if isc: + fw.write ("GRUB_MOD_LICENSE (\"GPLv3+\");\n") + ciphernames = [] mdnames = [] hold = False skip = False skip2 = False ismd = False + iscipher = False iscryptostart = False iscomma = False isglue = False @@ -109,6 +139,7 @@ for cipher_file in cipher_files: isglue = True modname = "gcry_%s" % modname for line in f: + line = line if skip_statement: if not re.search (";", line) is None: skip_statement = False @@ -127,15 +158,22 @@ for cipher_file in cipher_files: sg = s.groups()[0] cryptolist.write (("%s: %s\n") % (sg, modname)) iscryptostart = False - if ismd: + if ismd or iscipher: if not re.search (" *};", line) is None: - if not mdblocksizes.has_key (mdname): - print ("ERROR: Unknown digest blocksize: %s\n" % mdname) - exit (1) if not iscomma: fw.write (" ,\n") - fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) + fw.write ("#ifdef GRUB_UTIL\n"); + fw.write (" .modname = \"%s\",\n" % modname); + fw.write ("#endif\n"); + if ismd: + if not (mdname in mdblocksizes): + print ("ERROR: Unknown digest blocksize: %s\n" + % mdname) + exit (1) + fw.write (" .blocksize = %s\n" + % mdblocksizes [mdname]) ismd = False + iscipher = False iscomma = not re.search (",$", line) is None # Used only for selftests. m = re.match ("(static byte|static unsigned char) (weak_keys_chksum)\[[0-9]*\] =", line) @@ -152,8 +190,10 @@ for cipher_file in cipher_files: if hold: hold = False # We're optimising for size. - if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info)", line) is None: + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info|_gcry_rmd160_mixblock|serpent_test)", line) is None: skip = True + if not re.match ("serpent_test", line) is None: + fw.write ("static const char *serpent_test (void) { return 0; }\n"); fname = re.match ("[a-zA-Z0-9_]*", line).group () chmsg = "(%s): Removed." % fname if nch: @@ -164,10 +204,9 @@ for cipher_file in cipher_files: continue else: fw.write (holdline) - m = re.match ("#include <.*>", line) + m = re.match ("# *include <(.*)>", line) if not m is None: - chmsg = "Removed including of %s" % \ - m.group () [len ("#include <"):len (m.group ()) - 1] + chmsg = "Removed including of %s" % m.groups ()[0] if nch: chlognew = "%s\n %s" % (chlognew, chmsg) else: @@ -176,14 +215,18 @@ for cipher_file in cipher_files: continue m = re.match ("gcry_cipher_spec_t", line) if isc and not m is None: + assert (not iscryptostart) + assert (not iscipher) assert (not iscryptostart) ciphername = line [len ("gcry_cipher_spec_t"):].strip () ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () ciphernames.append (ciphername) + iscipher = True iscryptostart = True m = re.match ("gcry_md_spec_t", line) if isc and not m is None: assert (not ismd) + assert (not iscipher) assert (not iscryptostart) mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () @@ -244,6 +287,7 @@ for cipher_file in cipher_files: % (cipher_file, cipher_file.replace ("-glue.c", ".c")) else: modfiles = "lib/libgcrypt-grub/cipher/%s" % cipher_file + modules.append (modname) chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname if nch: chlognew = "%s\n %s" % (chlognew, chmsg) @@ -278,6 +322,7 @@ for cipher_file in cipher_files: conf.write (" name = %s;\n" % modname) for src in modfiles.split(): conf.write (" common = %s;\n" % src) + confutil.write (" common = grub-core/%s;\n" % src) conf.write (" cflags = '$(CFLAGS_GCRY)';\n"); conf.write (" cppflags = '$(CPPFLAGS_GCRY)';\n"); conf.write ("};\n\n") @@ -295,28 +340,28 @@ cryptolist.close () chlog = "%s * crypto.lst: New file.\n" % chlog outfile = os.path.join (cipher_dir_out, "types.h") -fw=open (outfile, "w") +fw=codecs.open (outfile, "w", "utf-8") fw.write ("#include \n") fw.write ("#include \n") chlog = "%s * types.h: New file.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "memory.h") -fw=open (outfile, "w") +fw=codecs.open (outfile, "w", "utf-8") fw.write ("#include \n") chlog = "%s * memory.h: New file.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "cipher.h") -fw=open (outfile, "w") +fw=codecs.open (outfile, "w", "utf-8") fw.write ("#include \n") fw.write ("#include \n") chlog = "%s * cipher.h: Likewise.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "g10lib.h") -fw=open (outfile, "w") +fw=codecs.open (outfile, "w", "utf-8") fw.write ("#include \n") chlog = "%s * g10lib.h: Likewise.\n" % chlog fw.close () @@ -324,9 +369,35 @@ fw.close () infile = os.path.join (cipher_dir_in, "ChangeLog") outfile = os.path.join (cipher_dir_out, "ChangeLog") +conf.close (); -f=open (infile, "r") -fw=open (outfile, "w") +initfile = codecs.open (os.path.join (cipher_dir_out, "init.c"), "w", "utf-8") +for module in modules: + initfile.write ("extern void grub_%s_init (void);\n" % module) + initfile.write ("extern void grub_%s_fini (void);\n" % module) +initfile.write ("\n") +initfile.write ("void\n") +initfile.write ("grub_gcry_init_all (void)\n") +initfile.write ("{\n") +for module in modules: + initfile.write (" grub_%s_init ();\n" % module) +initfile.write ("}\n") +initfile.write ("\n") +initfile.write ("void\n") +initfile.write ("grub_gcry_fini_all (void)\n") +initfile.write ("{\n") +for module in modules: + initfile.write (" grub_%s_fini ();\n" % module) +initfile.write ("}\n") +initfile.close () + +confutil.write (" common = grub-core/lib/libgcrypt-grub/cipher/init.c;\n") +confutil.write ("};\n"); +confutil.close (); + + +f=codecs.open (infile, "r", "utf-8") +fw=codecs.open (outfile, "w", "utf-8") dt = datetime.date.today () fw.write ("%04d-%02d-%02d Automatic import tool\n" % \ (dt.year,dt.month, dt.day)) diff --git a/util/import_unicode.py b/util/import_unicode.py index 8d17e7ef6..ec3db0842 100644 --- a/util/import_unicode.py +++ b/util/import_unicode.py @@ -130,9 +130,13 @@ for line in infile: if begincode != -2 and (lastbiditype != "L" or lastcombtype != 0 or \ lastmirrortype): outfile.write (("{0x%x, 0x%x, GRUB_BIDI_TYPE_%s, %d, %d, GRUB_JOIN_TYPE_%s},\n" \ - % (begincode, lastcode, lastbiditype, \ + % (begincode, lastcode - begincode + 1, \ + lastbiditype, \ lastcombtype, lastmirrortype, \ lastjoin))) + if lastcode - begincode + 1 >= 0x200: + print "Too long range" + raise begincode = curcode lastcode = curcode lastjoin = curjoin diff --git a/util/lvm.c b/util/lvm.c index bb2c19fe3..0bc271e46 100644 --- a/util/lvm.c +++ b/util/lvm.c @@ -1,7 +1,7 @@ /* lvm.c - LVM support for GRUB utils. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2011 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,8 +17,7 @@ * along with GRUB. If not, see . */ -/* We only support LVM on Linux. */ -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #include @@ -26,8 +25,6 @@ #include #include -#define LVM_DEV_MAPPER_STRING "/dev/mapper/" - int grub_util_lvm_isvolume (char *name) { @@ -49,4 +46,4 @@ grub_util_lvm_isvolume (char *name) return 1; } -#endif /* ! __linux__ */ +#endif diff --git a/util/misc.c b/util/misc.c index cfbae609b..6ebaf30bc 100644 --- a/util/misc.c +++ b/util/misc.c @@ -55,6 +55,7 @@ #ifdef __MINGW32__ #include #include +#include "dirname.h" #endif #ifdef GRUB_UTIL @@ -88,10 +89,10 @@ grub_util_get_fp_size (FILE *fp) struct stat st; if (fflush (fp) == EOF) - grub_util_error ("fflush failed"); + grub_util_error (_("fflush failed")); if (fstat (fileno (fp), &st) == -1) - grub_util_error ("fstat failed"); + grub_util_error (_("fstat failed")); return st.st_size; } @@ -104,7 +105,7 @@ grub_util_get_image_size (const char *path) grub_util_info ("getting the size of %s", path); if (stat (path, &st) == -1) - grub_util_error ("cannot stat %s", path); + grub_util_error (_("cannot stat %s"), path); return st.st_size; } @@ -113,10 +114,10 @@ void grub_util_read_at (void *img, size_t size, off_t offset, FILE *fp) { if (fseeko (fp, offset, SEEK_SET) == -1) - grub_util_error ("seek failed"); + grub_util_error (_("seek failed")); if (fread (img, 1, size, fp) != size) - grub_util_error ("read failed"); + grub_util_error (_("read failed")); } char * @@ -133,7 +134,7 @@ grub_util_read_image (const char *path) fp = fopen (path, "rb"); if (! fp) - grub_util_error ("cannot open %s", path); + grub_util_error (_("cannot open %s"), path); grub_util_read_at (img, size, 0, fp); @@ -154,10 +155,10 @@ grub_util_load_image (const char *path, char *buf) fp = fopen (path, "rb"); if (! fp) - grub_util_error ("cannot open %s", path); + grub_util_error (_("cannot open %s"), path); if (fread (buf, 1, size, fp) != size) - grub_util_error ("cannot read %s", path); + grub_util_error (_("cannot read %s"), path); fclose (fp); } @@ -167,9 +168,9 @@ grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out) { grub_util_info ("writing 0x%x bytes at offset 0x%x", size, offset); if (fseeko (out, offset, SEEK_SET) == -1) - grub_util_error ("seek failed"); + grub_util_error (_("seek failed")); if (fwrite (img, 1, size, out) != size) - grub_util_error ("write failed"); + grub_util_error (_("write failed")); } void @@ -177,7 +178,7 @@ grub_util_write_image (const char *img, size_t size, FILE *out) { grub_util_info ("writing 0x%x bytes", size); if (fwrite (img, 1, size, out) != size) - grub_util_error ("write failed"); + grub_util_error (_("write failed")); } char * @@ -316,17 +317,13 @@ int fsync (int fno __attribute__ ((unused))) return 0; } -void sleep (int s) -{ - Sleep (s * 1000); -} - grub_int64_t grub_util_get_disk_size (char *name) { HANDLE hd; grub_int64_t size = -1LL; + strip_trailing_slashes(name); hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); diff --git a/util/powerpc/ieee1275/grub-mkrescue.in b/util/powerpc/ieee1275/grub-mkrescue.in index aefedff3f..d688431c3 100644 --- a/util/powerpc/ieee1275/grub-mkrescue.in +++ b/util/powerpc/ieee1275/grub-mkrescue.in @@ -121,13 +121,13 @@ if [ "x${modules}" = "x" ] ; then modules=`cd ${input_dir}/ && ls *.mod` fi -map_file=`mktemp` +map_file=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 cat >${map_file} < #include -#include #include #include @@ -34,39 +33,40 @@ #include #include #include +#include char ** -grub_util_raid_getmembers (char *name) +grub_util_raid_getmembers (const char *name, int bootable) { int fd, ret, i, j; - char *devname; char **devicelist; mdu_version_t version; mdu_array_info_t info; mdu_disk_info_t disk; - devname = xmalloc (strlen (name) + 6); - strcpy (devname, "/dev/"); - strcpy (devname+5, name); - - fd = open (devname, O_RDONLY); + fd = open (name, O_RDONLY); if (fd == -1) - grub_util_error ("can't open %s: %s", devname, strerror (errno)); - - free (devname); + grub_util_error (_("can't open %s: %s"), name, strerror (errno)); ret = ioctl (fd, RAID_VERSION, &version); if (ret != 0) - grub_util_error ("ioctl RAID_VERSION error: %s", strerror (errno)); + grub_util_error (_("ioctl RAID_VERSION error: %s"), strerror (errno)); - if (version.major != 0 || version.minor != 90) - grub_util_error ("unsupported RAID version: %d.%d", + if ((version.major != 0 || version.minor != 90) + && (version.major != 1 || version.minor != 0) + && (version.major != 1 || version.minor != 1) + && (version.major != 1 || version.minor != 2)) + grub_util_error (_("unsupported RAID version: %d.%d"), + version.major, version.minor); + + if (bootable && (version.major != 0 || version.minor != 90)) + grub_util_error (_("unsupported RAID version: %d.%d"), version.major, version.minor); ret = ioctl (fd, GET_ARRAY_INFO, &info); if (ret != 0) - grub_util_error ("ioctl GET_ARRAY_INFO error: %s", strerror (errno)); + grub_util_error (_("ioctl GET_ARRAY_INFO error: %s"), strerror (errno)); devicelist = xmalloc ((info.nr_disks + 1) * sizeof (char *)); @@ -75,7 +75,7 @@ grub_util_raid_getmembers (char *name) disk.number = i; ret = ioctl (fd, GET_DISK_INFO, &disk); if (ret != 0) - grub_util_error ("ioctl GET_DISK_INFO error: %s", strerror (errno)); + grub_util_error (_("ioctl GET_DISK_INFO error: %s"), strerror (errno)); if (disk.state & (1 << MD_DISK_ACTIVE)) { @@ -87,6 +87,8 @@ grub_util_raid_getmembers (char *name) devicelist[j] = NULL; + close (fd); + return devicelist; } diff --git a/util/resolve.c b/util/resolve.c index 63bd7ccb2..3eb8bfb14 100644 --- a/util/resolve.c +++ b/util/resolve.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Module. */ struct mod_list @@ -87,7 +88,7 @@ read_dep_list (FILE *fp) /* Get the target name. */ p = strchr (buf, ':'); if (! p) - grub_util_error ("invalid line format: %s", buf); + grub_util_error (_("invalid line format: %s"), buf); *p++ = '\0'; @@ -240,7 +241,7 @@ grub_util_resolve_dependencies (const char *prefix, path = grub_util_get_path (prefix, dep_list_file); fp = fopen (path, "r"); if (! fp) - grub_util_error ("cannot open %s", path); + grub_util_error (_("cannot open %s"), path); free (path); dep_list = read_dep_list (fp); diff --git a/util/update-grub_lib.in b/util/update-grub_lib.in deleted file mode 100644 index 998452e67..000000000 --- a/util/update-grub_lib.in +++ /dev/null @@ -1,23 +0,0 @@ -# stub for new grub-mkconfig_lib -# Copyright (C) 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 . - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ - -. ${libdir}/grub/grub-mkconfig_lib - -grub_warn "update-grub_lib is deprecated, use grub-mkconfig_lib instead"