diff --git a/.bzrignore b/.bzrignore index 69aedc290..9135d7f4a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -48,6 +48,7 @@ grub-kbdcomp grub-macho2img grub-menulst2cfg grub-mk* +grub-mount grub-pe2elf grub-probe grub_probe_init.c @@ -160,3 +161,4 @@ widthspec.bin widthspec.h docs/stamp-1 docs/version-dev.texi +Makefile.utilgcry.def diff --git a/ChangeLog b/ChangeLog index 1a68f911c..8a409fabc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,3962 @@ +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. diff --git a/Makefile.am b/Makefile.am index 9301c91a5..c5f486e0d 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 diff --git a/Makefile.util.def b/Makefile.util.def index 8812a783c..47aefee32 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -9,7 +9,8 @@ library = { common = grub-core/kern/command.c; common = grub-core/kern/device.c; common = grub-core/kern/disk.c; - common = grub-core/kern/emu/getroot.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; @@ -20,12 +21,20 @@ library = { 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; }; library = { name = libgrubmods.a; - cflags = '$(CFLAGS_GCRY)'; - cppflags = '$(CPPFLAGS_GCRY)'; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(top_srcdir)/grub-core/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; common_nodist = grub_script.tab.c; common_nodist = grub_script.yy.c; @@ -34,7 +43,8 @@ library = { common_nodist = grub_script.tab.h; 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; @@ -45,14 +55,16 @@ library = { 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; @@ -73,20 +85,19 @@ library = { common = grub-core/fs/ufs2.c; common = grub-core/fs/ufs.c; common = grub-core/fs/xfs.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/arg.c; - common = grub-core/lib/crypto.c; common = grub-core/lib/envblk.c; common = grub-core/lib/hexdump.c; - common = grub-core/lib/libgcrypt-grub/cipher/sha512.c; - common = grub-core/lib/libgcrypt-grub/cipher/crc.c; common = grub-core/lib/LzFind.c; common = grub-core/lib/LzmaEnc.c; - common = grub-core/lib/pbkdf2.c; 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; @@ -95,6 +106,7 @@ library = { 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; @@ -104,13 +116,16 @@ library = { 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; }; program = { name = grub-bin2h; common = util/bin2h.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; @@ -126,6 +141,7 @@ program = { extra_dist = util/grub-mkimagexx.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBLZMA)'; @@ -140,9 +156,10 @@ program = { common = util/grub-mkrelpath.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; program = { @@ -152,6 +169,7 @@ program = { common = util/grub-script-check.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -164,6 +182,7 @@ program = { common = util/grub-editenv.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -176,6 +195,7 @@ program = { common = util/grub-mkpasswd-pbkdf2.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -196,6 +216,7 @@ program = { common = util/grub-pe2elf.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL)'; @@ -214,9 +235,26 @@ program = { cppflags = '$(CPPFLAGS_GCRY)'; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + 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 = { @@ -228,6 +266,7 @@ program = { cflags = '$(freetype_cflags)'; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(freetype_libs)'; @@ -245,6 +284,7 @@ program = { common = util/devicemap.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -258,6 +298,7 @@ program = { common = util/ieee1275/ofpath.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -268,7 +309,6 @@ 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; @@ -276,6 +316,7 @@ program = { ldadd = libgrubmods.a; ldadd = libgrubkern.a; + ldadd = libgrubgcry.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -291,6 +332,7 @@ program = { ieee1275 = util/ieee1275/ofpath.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBGEOM)'; @@ -305,6 +347,7 @@ program = { common = util/grub-mklayout.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -342,6 +385,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; @@ -395,6 +445,12 @@ script = { enable = powerpc_ieee1275; }; +script = { + mansection = 1; + name = grub-mkstandalone; + common = util/grub-mkstandalone.in; +}; + script = { mansection = 8; installdir = sbin; @@ -616,6 +672,22 @@ program = { common = grub-core/tests/lib/test.c; cflags = -Wno-format; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; + ldadd = libgrubkern.a; + ldadd = grub-core/gnulib/libgnu.a; + 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)'; @@ -629,6 +701,7 @@ program = { common = grub-core/lib/i386/pc/vesa_modes_table.c; ldadd = libgrubmods.a; + ldadd = libgrubgcry.a; ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; 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 d14707aad..db719cd1d 100755 --- a/autogen.sh +++ b/autogen.sh @@ -26,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/config.h.in b/config.h.in index 3974ad7d5..39b8fbafd 100644 --- a/config.h.in +++ b/config.h.in @@ -36,6 +36,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 f674a90aa..7699e8330 100644 --- a/configure.ac +++ b/configure.ac @@ -154,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 @@ -412,21 +413,21 @@ if test "x$grub_cv_cc_fno_dwarf2_cfi_asm" = xyes; then TARGET_CFLAGS="$TARGET_CFLAGS -fno-dwarf2-cfi-asm" fi -if test "${target_cpu}-${platform}" = mipsel-loongson; then - AC_CACHE_CHECK([whether -march=loongson2f works], [grub_cv_cc_march_loongson2f], [ - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -march=loongson2f" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [grub_cv_cc_march_loongson2f=yes], - [grub_cv_cc_march_loongson2f=no]) - CFLAGS="$SAVE_CFLAGS" - ]) +# 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_march_loongson2f" = xyes; then - TARGET_CFLAGS="$TARGET_CFLAGS -march=loongson2f" - else - TARGET_CFLAGS="$TARGET_CFLAGS -march=mips3" - fi +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 @@ -480,6 +481,7 @@ 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 @@ -488,6 +490,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 @@ -604,7 +607,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 __ia64_trampoline __udivsi3 __umoddi3 __udivdi3 __divsi3 __modsi3 __umodsi3 __moddi3 __divdi3) +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" @@ -717,6 +720,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)])]) @@ -866,10 +880,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)])]) @@ -977,16 +1025,19 @@ 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]) @@ -1053,6 +1104,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 @@ -1063,5 +1119,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/grub.texi b/docs/grub.texi index 818417d41..1078a2183 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -89,6 +89,7 @@ This edition documents version @value{VERSION}. * 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 * Supported kernels:: The list of supported kernels * Troubleshooting:: Error messages produced by GRUB @@ -340,11 +341,17 @@ 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} or @@ -784,6 +791,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 @@ -855,6 +863,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 @@ -1203,7 +1236,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}. @xref{gfxmode}. +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. @@ -2202,42 +2236,64 @@ 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. +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/disk) +(memdisk) +(host) +(myloop) @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. @@ -3866,6 +3922,65 @@ 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 filesnames in FAT, Joliet part of +ISO9660 are treated as UTF-16 as per specification. BFS is 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 and HFS +never use unicode and GRUB assumes them to be in Latin1 and MacRoman +respectively. NTFS, HFS+, FAT and exFAT are case-insensitive 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. Also similar to POSIX systems GRUB make 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 ZFS subvolumes +marked as case insensitive files containing lowercase international characters +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 ones. Ligatures aren't supported though. This should cover +European, Middle Eastern (if you don't mind lack of la-alef ligature in +Arabic) and East Asian scripts. Notable unsupported scripts are Brahmic family +and derived as well as Mongolian and Tifinagh. 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. @node Security @chapter Authentication and authorisation @@ -3942,6 +4057,7 @@ X86 support is summarised in the following table. ``Yes'' means that the kernel @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) @@ -3967,6 +4083,7 @@ X86 support is summarised in the following table. ``Yes'' means that the kernel @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) @@ -3992,6 +4109,7 @@ X86 support is summarised in the following table. ``Yes'' means that the kernel @item @tab 32-bit EFI @tab 64-bit EFI @item BIOS chainloading @tab no (1) @tab no (1) @item NTLDR @tab no (1) @tab no (1) +@item 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 @@ -4017,6 +4135,7 @@ X86 support is summarised in the following table. ``Yes'' means that the kernel @item @tab 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) @@ -4330,11 +4449,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: diff --git a/docs/man/grub-mklayout.h2m b/docs/man/grub-mklayout.h2m index cda6f3676..1e43409c0 100644 --- a/docs/man/grub-mklayout.h2m +++ b/docs/man/grub-mklayout.h2m @@ -1,4 +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-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/gentpl.py b/gentpl.py index 6e2df076b..af210a040 100644 --- a/gentpl.py +++ b/gentpl.py @@ -30,12 +30,14 @@ GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" GROUPS["noemu"] = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu") # Groups based on hardware features -GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips"]; GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi") +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_loongson"] +GROUPS["videoinkernel"] = ["mips_loongson", "mips_qemu_mips"] GROUPS["videomodules"] = GRUB_PLATFORMS[:]; for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i) @@ -181,6 +183,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: @@ -243,10 +256,18 @@ def foreach_enabled_platform(closure): # 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): @@ -259,18 +280,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. @@ -487,7 +559,6 @@ def script_rules(): def data_rules(): return rules("data", data) -print "[+ AutoGen5 template +]\n" a = module_rules() b = kernel_rules() c = image_rules() @@ -497,11 +568,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 98e275f7e..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 @@ -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 @@ -141,7 +142,20 @@ 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 @@ -187,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 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 3fdf395b4..e183f884c 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -18,6 +18,18 @@ script = { 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; @@ -34,7 +46,7 @@ kernel = { 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'; @@ -102,6 +114,7 @@ kernel = { ieee1275 = kern/ieee1275/mmap.c; ieee1275 = kern/ieee1275/openfw.c; ieee1275 = term/ieee1275/ofconsole.c; + ieee1275 = kern/ieee1275/init.c; terminfoinkernel = term/terminfo.c; terminfoinkernel = term/tparm.c; @@ -143,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; @@ -153,8 +166,6 @@ 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; @@ -162,6 +173,11 @@ kernel = { 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; @@ -176,24 +192,22 @@ kernel = { 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_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; @@ -217,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; @@ -353,6 +368,15 @@ image = { enable = mips; }; +image = { + name = lzma_decompress; + i386_pc = boot/i386/pc/startup_raw.S; + + objcopyflags = '-O binary'; + ldflags = '$(TARGET_IMG_LDFLAGS) -Wl,-Ttext,0x8200'; + enable = i386_pc; +}; + image = { name = fwstart; mips_loongson = boot/mips/loongson/fwstart.S; @@ -362,8 +386,8 @@ image = { }; image = { - name = fwstart_fuloong; - mips_loongson = boot/mips/loongson/fuloong.S; + 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; @@ -397,11 +421,15 @@ module = { 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 = { @@ -436,18 +464,22 @@ module = { module = { name = pci; - noemu = bus/pci.c; - emu = bus/emu/pci.c; - emu = commands/lspci.c; + common = bus/pci.c; - enable = emu; enable = i386_pc; 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 = { @@ -622,6 +654,20 @@ module = { 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; @@ -717,22 +763,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; @@ -791,8 +826,6 @@ module = { name = usbtest; common = commands/usbtest.c; enable = usb; - enable = emu; - emu_condition = COND_GRUB_EMU_USB; }; module = { @@ -820,6 +853,22 @@ 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; @@ -868,8 +917,14 @@ module = { }; 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; }; @@ -884,8 +939,6 @@ module = { name = usbms; common = disk/usbms.c; enable = usb; - enable = emu; - emu_condition = COND_GRUB_EMU_USB; }; module = { @@ -944,24 +997,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 = { @@ -969,6 +1014,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; @@ -979,6 +1039,11 @@ module = { common = fs/fat.c; }; +module = { + name = exfat; + common = fs/exfat.c; +}; + module = { name = fshelp; common = fs/fshelp.c; @@ -1087,6 +1152,11 @@ module = { common = fs/zfs/zfs_fletcher.c; }; +module = { + name = zfscrypt; + common = fs/zfs/zfscrypt.c; +}; + module = { name = zfsinfo; common = fs/zfs/zfsinfo.c; @@ -1094,7 +1164,7 @@ module = { module = { name = pxe; - i386_pc = fs/i386/pc/pxe.c; + i386_pc = net/drivers/i386/pc/pxe.c; enable = i386_pc; }; @@ -1186,6 +1256,9 @@ module = { 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; }; @@ -1219,6 +1292,13 @@ 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; @@ -1292,7 +1372,9 @@ module = { name = chain; efi = loader/efi/chainloader.c; i386_pc = loader/i386/pc/chainloader.c; + i386_coreboot = loader/i386/coreboot/chainloader.c; enable = i386_pc; + enable = i386_coreboot; enable = efi; }; @@ -1351,7 +1433,7 @@ module = { extra_dist = script/yylex.l; extra_dist = script/parser.y; - cflags = '$(CFLAGS_POSIX) -Wno-error'; + cflags = '$(CFLAGS_POSIX)'; cppflags = '$(CPPFLAGS_POSIX)'; }; @@ -1385,6 +1467,11 @@ module = { common = partmap/sun.c; }; +module = { + name = part_plan; + common = partmap/plan.c; +}; + module = { name = part_dvh; common = partmap/dvh.c; @@ -1422,9 +1509,7 @@ module = { common = term/serial.c; x86 = term/ns8250.c; - enable = emu; enable = x86; - emu_condition = COND_GRUB_EMU_USB; }; module = { @@ -1448,8 +1533,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 = { @@ -1527,8 +1614,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 = { @@ -1565,6 +1654,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; @@ -1588,6 +1720,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; @@ -1604,3 +1744,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/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S index 635599a24..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 /* 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 2c7596026..4fe0df139 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 @@ -200,21 +199,12 @@ real_code_2: 1: - movl %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE), %ecx -#if GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4 < 0x200 - addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - 0x200), %ecx -#else - addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4)), %ecx -#endif + movl %ss:(DATA_ADDR + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE), %ecx + addl $((0x9000 - 0x8200) - (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4)), %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..0e6794f56 --- /dev/null +++ b/grub-core/boot/i386/pc/startup_raw.S @@ -0,0 +1,351 @@ +/* + * 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 + +/* + * This is the area for all of the special variables. + */ + +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) - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART - _start), %edx + movl reed_solomon_redundancy, %ecx + leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax + cld + call EXT_C (grub_reed_solomon_recover) + jmp post_reed_solomon + +#include "../../../kern/i386/realmode.S" + +#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 $(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 + +/* + * 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 + + .p2align 4 + +LOCAL(decompressor_end): diff --git a/grub-core/boot/mips/loongson/fuloong.S b/grub-core/boot/mips/loongson/fuloong2f.S similarity index 51% rename from grub-core/boot/mips/loongson/fuloong.S rename to grub-core/boot/mips/loongson/fuloong2f.S index 5df0d54c1..a88c81efe 100644 --- a/grub-core/boot/mips/loongson/fuloong.S +++ b/grub-core/boot/mips/loongson/fuloong2f.S @@ -1,2 +1,2 @@ -#define FULOONG 1 +#define FULOONG2F 1 #include "fwstart.S" diff --git a/grub-core/boot/mips/loongson/fwstart.S b/grub-core/boot/mips/loongson/fwstart.S index 38e87ad72..7ed5d30ae 100644 --- a/grub-core/boot/mips/loongson/fwstart.S +++ b/grub-core/boot/mips/loongson/fwstart.S @@ -26,7 +26,7 @@ #include #include -#ifdef FULOONG +#ifdef FULOONG2F #define GRUB_MACHINE_SERIAL_PORT GRUB_MACHINE_SERIAL_PORT2 #define GRUB_MACHINE_SERIAL_DIVISOR_115200 GRUB_MACHINE_SERIAL_PORT2_DIVISOR_115200 #else @@ -43,10 +43,10 @@ start: _start: __start: - /* Put serial init as soon as possible. But on Fuloong serial is past - Geode, so on Fuloong we need Geode first. + /* Put serial init as soon as possible. But on Fuloong2f serial is past + Geode, so on Fuloong2f we need Geode first. */ -#ifndef FULOONG +#ifndef FULOONG2F bal serial_hw_init nop #endif @@ -72,7 +72,7 @@ retry_cs5536: bnel $t2, $t3, 1b sll $t4, $t4, 1 -#ifndef FULOONG +#ifndef FULOONG2F bal message addiu $a0, $a0, %lo(cs5536_found) bal printhex @@ -95,7 +95,7 @@ retry_cs5536: bal gpio_init nop -#ifdef FULOONG +#ifdef FULOONG2F bal serial_hw_init nop #endif @@ -130,7 +130,7 @@ retry_cs5536: 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 and Fuloong have 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 @@ -252,7 +252,7 @@ gpio_init: /* In: none. Out: none. Clobbered: $t0, $t1, $t2, $a0, $a1, $a2. */ serial_hw_init: move $t2, $ra -#ifdef FULOONG +#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 \ @@ -471,7 +471,7 @@ regdump: .quad 0x0100020200010101 /* 4 */ .quad 0x0a04030603050203 /* 6 */ .quad 0x0f0e040000010a0b /* 7 */ -#ifdef FULOONG +#ifdef FULOONG2F .quad 0x0000000100000001 /* 8 */ #else .quad 0x0000010200000102 /* 8 */ @@ -482,7 +482,7 @@ regdump: .quad 0x002a3c0615000000 /* c */ .quad 0x002a002a002a002a /* d */ .quad 0x002a002a002a002a /* e */ -#ifdef FULOONG +#ifdef FULOONG2F .quad 0x00b40020005b0004 /* f */ #else .quad 0x00b40020006d0004 /* f */ @@ -503,7 +503,7 @@ regdump: /* Dump of GPIO connections. FIXME: Remove useless and macroify. */ gpio_dump: -#ifdef FULOONG +#ifdef FULOONG2F .long 0xffff0000, 0x2eefd110, 0xffff0000, 0xffff0000 .long 0x2eefd110, 0xffff0000, 0x1000efff, 0xefff1000 .long 0x3df3c20c, 0xffff0000, 0xffff0000, 0xffff0000 @@ -740,8 +740,8 @@ continue: lui $t0, %hi(cached_continue - 0x20000000) addiu $t0, $t0, %lo(cached_continue - 0x20000000) jr $t0 -#ifdef FULOONG - addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_FULOONG) +#ifdef FULOONG2F + addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_FULOONG2F) #else addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_YEELOONG) #endif diff --git a/grub-core/boot/mips/startup_raw.S b/grub-core/boot/mips/startup_raw.S index e6dfadaf9..bbbc1dbec 100644 --- a/grub-core/boot/mips/startup_raw.S +++ b/grub-core/boot/mips/startup_raw.S @@ -38,13 +38,13 @@ 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_KERNEL_MACHINE_UNCOMPRESSED_ADDR + . = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR uncompressed_addr: .long 0 codestart: @@ -54,8 +54,22 @@ codestart: /* Parse arguments. Has to be done before relocation. So need to do it in asm. */ #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) - lw $s4, %lo (((16 << 20) - 264) | 0x80000000) ($t0) + b 2f + lw $s4, %lo (((16 << 20) - 264) | 0x80000000) ($t0) + +1: + li $s4, 0 +2: #endif #ifdef GRUB_MACHINE_MIPS_LOONGSON @@ -95,7 +109,7 @@ argcont: DO_PARSE (memsizestr, $s4) DO_PARSE (highmemsizestr, $s5) DO_CHECKT1 (pmon_yeeloong_verstr, GRUB_ARCH_MACHINE_YEELOONG) - DO_CHECKT1 (pmon_fuloong_verstr, GRUB_ARCH_MACHINE_FULOONG) + DO_CHECKT1 (pmon_fuloong2f_verstr, GRUB_ARCH_MACHINE_FULOONG2F) 2: b argcont addiu $t0, $t0, 4 @@ -141,11 +155,12 @@ memsizestr: .asciiz "memsize=" highmemsizestr: .asciiz "highmemsize=" machtype_yeeloong_str1: .asciiz "machtype=8.9" machtype_yeeloong_str2: .asciiz "machtype=lemote-yeeloong-" -machtype_fuloong_str: .asciiz "machtype=lemote-fuloong-" +machtype_fuloong2f_str: .asciiz "machtype=lemote-fuloong-2f" +machtype_fuloong2e_str: .asciiz "machtype=lemote-fuloong-2e" pmon_yeeloong_str: .asciiz "PMON_VER=LM8" -pmon_fuloong_str: .asciiz "PMON_VER=LM6" +pmon_fuloong2f_str: .asciiz "PMON_VER=LM6" pmon_yeeloong_verstr: .asciiz "Version=LM8" -pmon_fuloong_verstr: .asciiz "Version=LM6" +pmon_fuloong2f_verstr: .asciiz "Version=LM6" .p2align 2 argdone: @@ -159,8 +174,9 @@ argdone: 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_fuloong_str, GRUB_ARCH_MACHINE_FULOONG) - DO_CHECKA1 (pmon_fuloong_str, GRUB_ARCH_MACHINE_FULOONG) + 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 @@ -224,9 +240,9 @@ cmdlinedone: subu $a0, $a0, $t0 addu $a0, $a0, $s0 - lw $a1, (GRUB_KERNEL_MACHINE_UNCOMPRESSED_ADDR - BASE_ADDR)($s0) - 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, 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/cs5536.c b/grub-core/bus/cs5536.c index 58ffeb60a..9e7796ea1 100644 --- a/grub-core/bus/cs5536.c +++ b/grub-core/bus/cs5536.c @@ -97,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 @@ -281,7 +279,7 @@ grub_cs5536_init_geode (grub_pci_device_t dev) | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1); break; - case GRUB_ARCH_MACHINE_FULOONG: + 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 diff --git a/grub-core/bus/pci.c b/grub-core/bus/pci.c index 51006a20e..f007ec33a 100644 --- a/grub-core/bus/pci.c +++ b/grub-core/bus/pci.c @@ -115,16 +115,6 @@ grub_pci_iterate (grub_pci_iteratefunc_t hook) continue; } -#ifdef GRUB_MACHINE_MIPS_LOONGSON - /* Skip ghosts. */ - if (id == GRUB_LOONGSON_OHCI_PCIID - && dev.function == GRUB_LOONGSON_OHCI_GHOST_FUNCTION) - continue; - if (id == GRUB_LOONGSON_EHCI_PCIID - && dev.function == GRUB_LOONGSON_EHCI_GHOST_FUNCTION) - continue; -#endif - if (hook (dev, id)) return; diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index df0d0f4af..3f5ca7b03 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -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/uhci.c b/grub-core/bus/usb/uhci.c index 99e597f6d..a9a4c45a2 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -36,11 +36,33 @@ GRUB_MOD_LICENSE ("GPLv3+"); 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 @@ -181,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); @@ -195,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) @@ -252,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. */ @@ -285,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"); @@ -506,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); diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index 8f4429627..2531b8e11 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -138,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) { @@ -165,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; @@ -173,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; @@ -297,6 +298,7 @@ grub_acpi_create_ebda (void) return GRUB_ERR_NONE; } +#endif /* Create tables common to ACPIv1 and ACPIv2+ */ static void @@ -328,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; } @@ -365,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; @@ -383,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)); @@ -408,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; @@ -428,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); @@ -463,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; @@ -506,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) @@ -516,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]); @@ -540,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)) @@ -732,13 +733,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 9a4cda521..177ec15f0 100644 --- a/grub-core/commands/acpihalt.c +++ b/grub-core/commands/acpihalt.c @@ -33,6 +33,7 @@ typedef uint8_t grub_uint8_t; #endif #include +#include #ifndef GRUB_DSDT_TEST #include @@ -327,6 +328,6 @@ grub_acpi_halt (void) grub_millisleep (1500); - grub_printf ("ACPI shutdown failed\n"); + grub_puts_ (N_("ACPI shutdown failed")); } #endif diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c index 7714011bf..5149074c7 100644 --- a/grub-core/commands/boot.c +++ b/grub-core/commands/boot.c @@ -31,17 +31,17 @@ 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 @@ -51,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"); @@ -96,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; @@ -143,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/cmp.c b/grub-core/commands/cmp.c index 0222927b6..5d5925dd5 100644 --- a/grub-core/commands/cmp.c +++ b/grub-core/commands/cmp.c @@ -42,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]); @@ -51,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; @@ -78,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; } } @@ -89,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/efi/fixvideo.c b/grub-core/commands/efi/fixvideo.c index c53e47d8a..a58c27916 100644 --- a/grub-core/commands/efi/fixvideo.c +++ b/grub-core/commands/efi/fixvideo.c @@ -56,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"); } } @@ -82,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 138311222..5eb490fd4 100644 --- a/grub-core/commands/efi/loadbios.c +++ b/grub-core/commands/efi/loadbios.c @@ -49,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; } @@ -67,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; } @@ -209,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/gptsync.c b/grub-core/commands/gptsync.c index e92dc20ec..88d4b6296 100644 --- a/grub-core/commands/gptsync.c +++ b/grub-core/commands/gptsync.c @@ -231,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 317f7753f..f8596ecdc 100644 --- a/grub-core/commands/halt.c +++ b/grub-core/commands/halt.c @@ -24,13 +24,12 @@ GRUB_MOD_LICENSE ("GPLv3+"); -static grub_err_t +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 6825d4811..fb737c2f8 100644 --- a/grub-core/commands/hashsum.c +++ b/grub-core/commands/hashsum.c @@ -141,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); @@ -155,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); @@ -166,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, @@ -257,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 0c12b8814..85189e8bc 100644 --- a/grub-core/commands/hdparm.c +++ b/grub-core/commands/hdparm.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -63,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; @@ -126,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"); @@ -140,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) @@ -151,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) @@ -160,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)); @@ -275,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) @@ -285,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; @@ -313,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) { @@ -332,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 @@ -361,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)); } } @@ -369,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 @@ -385,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*")); @@ -394,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/i386/cmostest.c b/grub-core/commands/i386/cmostest.c index c79bd0387..6a4290155 100644 --- a/grub-core/commands/i386/cmostest.c +++ b/grub-core/commands/i386/cmostest.c @@ -20,6 +20,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -46,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"); @@ -63,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; @@ -78,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/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c index c9c8881b4..6e82be437 100644 --- a/grub-core/commands/i386/pc/drivemap.c +++ b/grub-core/commands/i386/pc/drivemap.c @@ -32,7 +32,7 @@ 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[] = { @@ -178,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) { @@ -363,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/lsapm.c b/grub-core/commands/i386/pc/lsapm.c index 17bcfd6eb..45b43b242 100644 --- a/grub-core/commands/i386/pc/lsapm.c +++ b/grub-core/commands/i386/pc/lsapm.c @@ -74,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 57980eb92..1adf296ec 100644 --- a/grub-core/commands/i386/pc/play.c +++ b/grub-core/commands/i386/pc/play.c @@ -192,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)) { @@ -227,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/pxecmd.c b/grub-core/commands/i386/pc/pxecmd.c deleted file mode 100644 index dffa15a3a..000000000 --- a/grub-core/commands/i386/pc/pxecmd.c +++ /dev/null @@ -1,54 +0,0 @@ -/* pxe.c - command to control the pxe driver */ -/* - * 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 - -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))) -{ - if (! grub_pxe_pxenv) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment"); - - grub_pxe_unload (); - - return 0; -} - -static grub_command_t cmd; - -GRUB_MOD_INIT(pxecmd) -{ - cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload, - 0, - N_("Unload PXE environment.")); -} - -GRUB_MOD_FINI(pxecmd) -{ - grub_unregister_command (cmd); -} diff --git a/grub-core/commands/i386/pc/sendkey.c b/grub-core/commands/i386/pc/sendkey.c index a55d17bd0..ab1090672 100644 --- a/grub-core/commands/i386/pc/sendkey.c +++ b/grub-core/commands/i386/pc/sendkey.c @@ -26,6 +26,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv2+"); @@ -35,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[] @@ -62,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 */ @@ -364,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 de068951d..844485077 100644 --- a/grub-core/commands/ieee1275/suspend.c +++ b/grub-core/commands/ieee1275/suspend.c @@ -31,7 +31,7 @@ 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/legacycfg.c b/grub-core/commands/legacycfg.c index e68b3315a..4de2d84d5 100644 --- a/grub-core/commands/legacycfg.c +++ b/grub-core/commands/legacycfg.c @@ -344,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) @@ -723,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; diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c index 5d53a8e66..1073712d5 100644 --- a/grub-core/commands/loadenv.c +++ b/grub-core/commands/loadenv.c @@ -43,7 +43,7 @@ open_envblk_file (char *filename) if (! filename) { - char *prefix; + const char *prefix; prefix = grub_env_get ("prefix"); if (prefix) @@ -346,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 4c4051a22..db9307780 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -31,6 +31,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -60,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; diff --git a/grub-core/commands/lsmmap.c b/grub-core/commands/lsmmap.c index 44598f0df..4815fd174 100644 --- a/grub-core/commands/lsmmap.c +++ b/grub-core/commands/lsmmap.c @@ -26,13 +26,13 @@ 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 @@ -46,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 03541df6c..9f836298f 100644 --- a/grub-core/commands/lspci.c +++ b/grub-core/commands/lspci.c @@ -29,7 +29,7 @@ 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 3b51189d6..5984288ce 100644 --- a/grub-core/commands/memrw.c +++ b/grub-core/commands/memrw.c @@ -31,7 +31,7 @@ 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 4849f8bb8..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[] = { diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index c7d1ec4f5..f436cd55d 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -90,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)), @@ -165,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; @@ -185,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/loongson/lsspd.c b/grub-core/commands/mips/loongson/lsspd.c index c1c5e2ef7..76999368f 100644 --- a/grub-core/commands/mips/loongson/lsspd.c +++ b/grub-core/commands/mips/loongson/lsspd.c @@ -23,6 +23,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -38,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; @@ -85,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 a54286161..ab5ab5ea4 100644 --- a/grub-core/commands/parttool.c +++ b/grub-core/commands/parttool.c @@ -37,9 +37,9 @@ 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, @@ -128,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; @@ -137,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/probe.c b/grub-core/commands/probe.c index c5f946340..a1d68cdeb 100644 --- a/grub-core/commands/probe.c +++ b/grub-core/commands/probe.c @@ -74,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) @@ -136,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); diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c index 8e18083c0..46d364c99 100644 --- a/grub-core/commands/reboot.c +++ b/grub-core/commands/reboot.c @@ -24,13 +24,12 @@ GRUB_MOD_LICENSE ("GPLv3+"); -static grub_err_t +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/setpci.c b/grub-core/commands/setpci.c index 70f5bcdad..81e7f726d 100644 --- a/grub-core/commands/setpci.c +++ b/grub-core/commands/setpci.c @@ -66,12 +66,12 @@ static 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} }; @@ -128,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/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/videoinfo.c b/grub-core/commands/videoinfo.c index 3e0c1a12e..9e12ff55e 100644 --- a/grub-core/commands/videoinfo.c +++ b/grub-core/commands/videoinfo.c @@ -28,6 +28,7 @@ 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) @@ -41,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) @@ -116,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; } @@ -145,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 ()) @@ -164,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 dc7a6485f..11949a6fc 100644 --- a/grub-core/commands/videotest.c +++ b/grub-core/commands/videotest.c @@ -74,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); @@ -191,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 32561abe6..d991b2010 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; } @@ -288,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; @@ -340,20 +342,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; @@ -423,8 +422,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; @@ -439,7 +436,7 @@ wildcard_expand (const char *s, char ***strs) else if (*start == '/') /* no device part */ { - char *root; + const char *root; char *prefix; root = grub_env_get ("root"); diff --git a/grub-core/commands/xnu_uuid.c b/grub-core/commands/xnu_uuid.c index f618b4ec0..3d152a6d6 100644 --- a/grub-core/commands/xnu_uuid.c +++ b/grub-core/commands/xnu_uuid.c @@ -51,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); @@ -75,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); @@ -91,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..10b7be687 --- /dev/null +++ b/grub-core/disk/ahci.c @@ -0,0 +1,738 @@ +/* + * 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; + 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->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 index e8416634a..170bf521d 100644 --- a/grub-core/disk/arc/arcdisk.c +++ b/grub-core/disk/arc/arcdisk.c @@ -1,7 +1,7 @@ /* ofdisk.c - Open Firmware disk access. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2006,2007,2008,2009 Free Software Foundation, Inc. + * 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 @@ -79,7 +79,8 @@ arcdisk_hash_add (char *devpath) static int -grub_arcdisk_iterate (int (*hook_in) (const char *name)) +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) @@ -90,6 +91,9 @@ grub_arcdisk_iterate (int (*hook_in) (const char *name)) return 0; return hook_in (name); } + if (pull != GRUB_DISK_PULL_NONE) + return 0; + return grub_arc_iterate_devs (hook, 1); } @@ -105,11 +109,6 @@ reopen (const char *name) grub_dprintf ("arcdisk", "using already opened %s\n", name); return GRUB_ERR_NONE; } - if (GRUB_ARC_FIRMWARE_VECTOR->open (name, 0, &handle)) - { - grub_dprintf ("arcdisk", "couldn't open %s\n", name); - return grub_error (GRUB_ERR_IO, "couldn't open %s", name); - } if (last_path) { GRUB_ARC_FIRMWARE_VECTOR->close (last_handle); @@ -117,6 +116,11 @@ reopen (const char *name) last_path = NULL; last_handle = 0; } + if (GRUB_ARC_FIRMWARE_VECTOR->open (name, 0, &handle)) + { + grub_dprintf ("arcdisk", "couldn't open %s\n", name); + return grub_error (GRUB_ERR_IO, "couldn't open %s", name); + } last_path = grub_strdup (name); if (!last_path) return grub_errno; diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c index 12e70d91b..50559a815 100644 --- a/grub-core/disk/ata.c +++ b/grub-core/disk/ata.c @@ -21,169 +21,74 @@ #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_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 }; - -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_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY) - && grub_ata_wait_not_busy (dev, dev->present ? GRUB_ATA_TOUT_DEV_INIT - : GRUB_ATA_TOUT_STD)) + 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); - dev->present = 0; - 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, dev->present ? GRUB_ATA_TOUT_DEV_INIT - : GRUB_ATA_TOUT_STD)) + if (parms.size != GRUB_DISK_SECTOR_SIZE) { - grub_free (info); - dev->present = 0; - 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; @@ -195,131 +100,55 @@ 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_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY) - && grub_ata_wait_not_busy (dev, dev->present ? GRUB_ATA_TOUT_DEV_INIT - : GRUB_ATA_TOUT_STD)) + parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_DEVICE; + + err = dev->dev->readwrite (dev, &parms, *dev->present); + + if (err || parms.size != GRUB_DISK_SECTOR_SIZE) { - dev->present = 0; - 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, dev->present ? GRUB_ATA_TOUT_DEV_INIT - : 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) { - dev->present = 0; + *dev->present = 0; /* No device, return error but don't print message. */ return GRUB_ERR_UNKNOWN_DEVICE; } else { - dev->present = 0; + *dev->present = 0; /* 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; - } - /* Now it is certain that this is not an ATAPI device. */ dev->atapi = 0; @@ -338,228 +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->present = 1; - 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; -} - -#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS -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; -} -#else -static grub_err_t -grub_ata_initialize (void) -{ - int i; - for (i = 0; i < 2; i++) - { - grub_ata_device_initialize (i, 0, grub_ata_ioaddress[i], - grub_ata_ioaddress2[i]); - grub_ata_device_initialize (i, 1, grub_ata_ioaddress[i], - grub_ata_ioaddress2[i]); - } - return 0; -} -#endif - -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) { @@ -581,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; } @@ -596,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; } @@ -627,70 +273,74 @@ 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_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; 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; } @@ -700,75 +350,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 @@ -803,70 +497,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; } @@ -882,64 +541,100 @@ grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)), } 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 eb9cb5f85..000000000 --- a/grub-core/disk/ata_pthru.c +++ /dev/null @@ -1,108 +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 - -GRUB_MOD_LICENSE ("GPLv3+"); - -/* 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..2852b65c4 --- /dev/null +++ b/grub-core/disk/cryptodisk.c @@ -0,0 +1,883 @@ +/* + * 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; +} + +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); +} + +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_size_t i; + gcry_err_code_t err; + + /* The only mode without IV. */ + if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey) + return 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: + 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: + 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); + 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); + + 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: + 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_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_decrypt (dev, (grub_uint8_t *) buf, + size << disk->log_sector_size, + sector); + return grub_crypto_gcry_error (gcry_err); +} + +static grub_err_t +grub_cryptodisk_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; +} + +#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) +{ + 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; + } +} + +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/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index 08094fa5c..bbb8c93b1 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"); @@ -711,7 +667,35 @@ grub_efidisk_get_device_handle (grub_disk_t disk) char * grub_efidisk_get_device_name (grub_efi_handle_t *handle) { - grub_efi_device_path_t *dp, *ldp; + grub_efi_device_path_t *dp, *ldp, *sdp; + /* This is a hard disk partition. */ + grub_disk_t parent = 0; + auto int find_parent_disk (const char *name); + + /* 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 (grub_efi_compare_device_paths (d->device_path, sdp) == 0) + { + parent = disk; + return 1; + } + } + + grub_disk_close (disk); + return 0; + } dp = grub_efi_get_device_path (handle); if (! dp) @@ -725,40 +709,12 @@ 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 *partition_name = NULL; char *device_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); 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 +722,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 +741,11 @@ 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); + sdp = dup_dp; + + grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_NONE); + if (!parent) + grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_REMOVABLE); grub_free (dup_dp); if (! parent) @@ -793,19 +753,24 @@ 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; + device_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; + } + + device_name = grub_xasprintf ("%s,%s", parent->name, partition_name); + grub_free (partition_name); + } grub_disk_close (parent); return device_name; @@ -813,38 +778,17 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) 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; + sdp = dp; - 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); + grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_NONE); + if (!parent) + grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_REMOVABLE); + if (!parent) + return NULL; + device_name = grub_strdup (parent->name); + grub_disk_close (parent); return 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 3baf20717..173e734d8 100644 --- a/grub-core/disk/i386/pc/biosdisk.c +++ b/grub-core/disk/i386/pc/biosdisk.c @@ -27,6 +27,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -284,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; } @@ -340,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; } @@ -349,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) { @@ -369,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++); + } } } } @@ -431,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; @@ -445,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; @@ -503,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_uint64_t offset; + struct grub_biosdisk_data *data = disk->data; + grub_uint32_t sectors = data->sectors; /* OFFSET = SECTOR % SECTORS */ grub_divmod64 (sector, sectors, &offset); @@ -514,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; } @@ -524,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; @@ -547,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; } @@ -570,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; } @@ -610,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; @@ -622,15 +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 (grub_boot_drive >= 0x90) - cd_drive = grub_boot_drive; + 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 e9450167e..94d62bc4f 100644 --- a/grub-core/disk/ieee1275/nand.c +++ b/grub-core/disk/ieee1275/nand.c @@ -32,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) @@ -46,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 7d1e81b30..b4a8d969c 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -152,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++) @@ -252,14 +257,24 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) 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 diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index d50f353b1..dca83b7c6 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -133,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)) 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 563b49b49..f3a99c66e 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,22 +23,28 @@ #include #include #include +#include +#include #ifdef GRUB_UTIL #include +#include #endif GRUB_MOD_LICENSE ("GPLv3+"); static struct grub_lvm_vg *vg_list; static int lv_count; +static int scan_depth = 0; + +static int is_lv_readable (struct grub_lvm_lv *lv); /* 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) @@ -63,7 +69,7 @@ grub_lvm_checkvalue (char **p, char *str, char *tmpl) #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) @@ -95,17 +101,664 @@ grub_lvm_check_flag (char *p, char *str, char *flag) } } -static int -grub_lvm_iterate (int (*hook) (const char *name)) +static struct grub_lvm_lv * +find_lv (const char *name) { 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->fullname, name) == 0 + || grub_strcmp (lv->compatname, name) == 0) + && is_lv_readable (lv)) + return lv; + } + return NULL; +} + +static void +do_lvm_scan (const char *scan_for) +{ + auto int grub_lvm_scan_device (const char *name); + int grub_lvm_scan_device (const char *name) + { + grub_err_t err; + grub_disk_t disk; + 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]; + char *metadatabuf, *p, *q, *vgname; + struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf; + struct grub_lvm_pv_header *pvh; + struct grub_lvm_disk_locn *dlocn; + 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; + } + + for (vg = vg_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 + && grub_partition_get_start (pv->disk->partition) + == grub_partition_get_start (disk->partition) + && grub_disk_get_size (pv->disk) + == grub_disk_get_size (disk)) + { + grub_disk_close (disk); + return 0; + } + + /* Search for label. */ + for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) + { + err = grub_disk_read (disk, i, 0, sizeof(buf), buf); + if (err) + goto fail; + + if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID, + sizeof (lh->id))) + && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL, + sizeof (lh->type)))) + break; + } + + /* Return if we didn't find a label. */ + if (i == GRUB_LVM_LABEL_SCAN_SECTORS) + { +#ifdef GRUB_UTIL + grub_util_info ("no LVM signature found"); +#endif + goto fail; + } + + pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl)); + + for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++) + { + pv_id[j++] = pvh->pv_uuid[i]; + if ((i != 1) && (i != 29) && (i % 4 == 1)) + pv_id[j++] = '-'; + } + pv_id[j] = '\0'; + + dlocn = pvh->disk_areas_xl; + + dlocn++; + /* Is it possible to have multiple data/metadata areas? I haven't + seen devices that have it. */ + if (dlocn->offset) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "we don't support multiple LVM data areas"); + +#ifdef GRUB_UTIL + grub_util_info ("we don't support multiple LVM data areas\n"); +#endif + goto fail; + } + + dlocn++; + mda_offset = grub_le_to_cpu64 (dlocn->offset); + mda_size = grub_le_to_cpu64 (dlocn->size); + + /* It's possible to have multiple copies of metadata areas, we just use the + first one. */ + + /* Allocate buffer space for the circular worst-case scenario. */ + metadatabuf = grub_malloc (2 * mda_size); + if (! metadatabuf) + goto fail; + + err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf); + if (err) + goto fail2; + + mdah = (struct grub_lvm_mda_header *) metadatabuf; + if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC, + sizeof (mdah->magic))) + || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unknown LVM metadata header"); +#ifdef GRUB_UTIL + grub_util_info ("unknown LVM metadata header\n"); +#endif + goto fail2; + } + + rlocn = mdah->raw_locns; + if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > + grub_le_to_cpu64 (mdah->size)) + { + /* 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)); + } + p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset); + + while (*q != ' ' && q < metadatabuf + mda_size) + q++; + + if (q == metadatabuf + mda_size) + { +#ifdef GRUB_UTIL + grub_util_info ("error parsing metadata\n"); +#endif + goto fail2; + } + + vgname_len = q - p; + vgname = grub_malloc (vgname_len + 1); + if (!vgname) + goto fail2; + + grub_memcpy (vgname, p, vgname_len); + vgname[vgname_len] = '\0'; + + p = grub_strstr (q, "id = \""); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("couldn't find ID\n"); +#endif + goto fail3; + } + p += sizeof ("id = \"") - 1; + grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN); + vg_id[GRUB_LVM_ID_STRLEN] = '\0'; + + for (vg = vg_list; vg; vg = vg->next) + { + if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN)) + break; + } + + if (! vg) + { + /* First time we see this volume group. We've to create the + whole volume group structure. */ + vg = grub_malloc (sizeof (*vg)); + if (! vg) + goto fail3; + vg->name = vgname; + grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1); + + vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown extent size\n"); +#endif + goto fail4; + } + + vg->lvs = NULL; + vg->pvs = NULL; + + p = grub_strstr (p, "physical_volumes {"); + if (p) + { + p += sizeof ("physical_volumes {") - 1; + + /* Add all the pvs to the volume group. */ + while (1) + { + int s; + while (grub_isspace (*p)) + p++; + + if (*p == '}') + break; + + pv = grub_malloc (sizeof (*pv)); + q = p; + while (*q != ' ') + q++; + + s = q - p; + pv->name = grub_malloc (s + 1); + grub_memcpy (pv->name, p, s); + pv->name[s] = '\0'; + + p = grub_strstr (p, "id = \""); + if (p == NULL) + goto pvs_fail; + p += sizeof("id = \"") - 1; + + grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN); + pv->id[GRUB_LVM_ID_STRLEN] = '\0'; + + pv->start = grub_lvm_getvalue (&p, "pe_start = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown pe_start\n"); +#endif + goto pvs_fail; + } + + p = grub_strchr (p, '}'); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("error parsing pe_start\n"); +#endif + goto pvs_fail; + } + p++; + + pv->disk = NULL; + pv->next = vg->pvs; + vg->pvs = pv; + + continue; + pvs_fail: + grub_free (pv->name); + grub_free (pv); + goto fail4; + } + } + + p = grub_strstr (p, "logical_volumes"); + if (p) + { + p += 18; + + /* 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; + int is_pvmove; + + while (grub_isspace (*p)) + p++; + + if (*p == '}') + break; + + lv = grub_malloc (sizeof (*lv)); + + q = p; + while (*q != ' ') + q++; + + s = q - p; + lv->name = grub_strndup (p, s); + if (!lv->name) + goto lvs_fail; + lv->compatname = grub_malloc (vgname_len + 1 + s + 1); + if (!lv->compatname) + goto lvs_fail; + grub_memcpy (lv->compatname, vgname, vgname_len); + lv->compatname[vgname_len] = '-'; + grub_memcpy (lv->compatname + vgname_len + 1, p, s); + lv->compatname[vgname_len + 1 + s] = '\0'; + + { + const char *iptr; + char *optr; + lv->fullname = grub_malloc (sizeof("lvm/") + 2 * vgname_len + + 1 + 2 * s + 1); + if (!lv->fullname) + goto lvs_fail; + + optr = lv->fullname; + grub_memcpy (optr, "lvm/", sizeof ("lvm/") - 1); + optr += 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; + + 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) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown segment_count\n"); +#endif + goto lvs_fail; + } + lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count); + seg = lv->segments; + + for (i = 0; i < lv->segment_count; i++) + { + + p = grub_strstr (p, "segment"); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown segment\n"); +#endif + goto lvs_segment_fail; + } + + seg->start_extent = grub_lvm_getvalue (&p, "start_extent = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown start_extent\n"); +#endif + goto lvs_segment_fail; + } + seg->extent_count = grub_lvm_getvalue (&p, "extent_count = "); + if (p == NULL) + { +#ifdef GRUB_UTIL + grub_util_info ("unknown extent_count\n"); +#endif + goto lvs_segment_fail; + } + + p = grub_strstr (p, "type = \""); + if (p == NULL) + goto lvs_segment_fail; + p += sizeof("type = \"") - 1; + + lv->size += seg->extent_count * vg->extent_size; + + if (grub_memcmp (p, "striped\"", + sizeof ("striped\"") - 1) == 0) + { + struct grub_lvm_node *stripe; + + seg->type = GRUB_LVM_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; + } + + 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'; + + stripe->start = grub_lvm_getvalue (&p, ","); + if (p == NULL) + continue; + + stripe++; + } + } + else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1) + == 0) + { + seg->type = GRUB_LVM_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 + { +#ifdef GRUB_UTIL + char *p2; + p2 = grub_strchr (p, '"'); + if (p2) + *p2 = 0; + grub_util_info ("unknown LVM type %s\n", p); + if (p2) + *p2 ='"'; +#endif + /* Found a non-supported type, give up and move on. */ + skip_lv = 1; + break; + } + + seg++; + + continue; + lvs_segment_fail2: + grub_free (seg->nodes); + lvs_segment_fail: + goto fail4; + } + + if (p != NULL) + p = grub_strchr (p, '}'); + if (p == NULL) + goto lvs_fail; + p += 3; + + if (skip_lv) + { + grub_free (lv->name); + grub_free (lv); + continue; + } + + lv->number = lv_count++; + lv->vg = vg; + lv->next = vg->lvs; + vg->lvs = lv; + + continue; + lvs_fail: + grub_free (lv->name); + grub_free (lv); + goto fail4; + } + } + + /* Match lvs. */ + { + struct grub_lvm_lv *lv1; + struct grub_lvm_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 + grub_strlen (vg->name) + 1, + lv1->segments[i].nodes[j].name) == 0) + lv1->segments[i].nodes[j].lv = lv2; + } + + } + + vg->next = vg_list; + vg_list = vg; + } + 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; + + /* Failure path. */ + fail4: + grub_free (vg); + 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; + grub_print_error (); + if (scan_for && find_lv (scan_for)) + return 1; + return 0; + } + + scan_depth++; + grub_device_iterate (&grub_lvm_scan_device); + scan_depth--; +} + +static int +grub_lvm_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) +{ + struct grub_lvm_vg *vg; + unsigned old_count = 0; + if (pull == GRUB_DISK_PULL_RESCAN && scan_depth) + return 0; + + if (pull == GRUB_DISK_PULL_RESCAN) + { + old_count = lv_count; + if (!scan_depth) + do_lvm_scan (NULL); + } + if (pull != GRUB_DISK_PULL_RESCAN && pull != GRUB_DISK_PULL_NONE) + return GRUB_ERR_NONE; 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 (lv->visible && hook (lv->name)) - return 1; + if (lv->visible && lv->number >= old_count) + { + if (hook (lv->fullname)) + return 1; + } } return 0; @@ -123,7 +776,7 @@ grub_lvm_memberlist (grub_disk_t disk) for (pv = lv->vg->pvs; pv; pv = pv->next) { if (!pv->disk) - grub_util_error ("Couldn't find PV %s. Check your device.map", + grub_util_error (_("Couldn't find PV %s. Check your device.map"), pv->name); tmp = grub_malloc (sizeof (*tmp)); tmp->disk = pv->disk; @@ -138,17 +791,23 @@ grub_lvm_memberlist (grub_disk_t disk) 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; + int explicit = 0; - if (lv) - break; + if (grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) == 0) + explicit = 1; + + lv = find_lv (name); + + if (! lv && !scan_depth && explicit) + { + do_lvm_scan (name); + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + lv = find_lv (name); } if (! lv) @@ -285,6 +944,49 @@ read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector, return grub_error (GRUB_ERR_IO, "unknown LVM segment"); } +static grub_err_t +is_node_readable (const struct grub_lvm_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_lvm_lv *lv) +{ + unsigned int i, j; + + if (!lv) + return 0; + + /* Find the right segment. */ + for (i = 0; i < lv->segment_count; i++) + switch (lv->segments[i].type) + { + case GRUB_LVM_STRIPED: + for (j = 0; j < lv->segments[i].node_count; j++) + if (!is_node_readable (lv->segments[i].nodes + j)) + return 0; + break; + case GRUB_LVM_MIRROR: + for (j = 0; j < lv->segments[i].node_count; j++) + if (is_node_readable (lv->segments[i].nodes + j)) + break; + if (j == lv->segments[i].node_count) + return 0; + default: + return 0; + } + + return 1; +} + + static grub_err_t grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) @@ -301,565 +1003,6 @@ grub_lvm_write (grub_disk_t disk __attribute ((unused)), return GRUB_ERR_NOT_IMPLEMENTED_YET; } -static int -grub_lvm_scan_device (const char *name) -{ - grub_err_t err; - grub_disk_t disk; - 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]; - char *metadatabuf, *p, *q, *vgname; - struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf; - struct grub_lvm_pv_header *pvh; - struct grub_lvm_disk_locn *dlocn; - 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; - } - - /* Search for label. */ - for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) - { - err = grub_disk_read (disk, i, 0, sizeof(buf), buf); - if (err) - goto fail; - - if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID, - sizeof (lh->id))) - && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL, - sizeof (lh->type)))) - break; - } - - /* Return if we didn't find a label. */ - if (i == GRUB_LVM_LABEL_SCAN_SECTORS) - { -#ifdef GRUB_UTIL - grub_util_info ("no LVM signature found"); -#endif - goto fail; - } - - pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl)); - - for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++) - { - pv_id[j++] = pvh->pv_uuid[i]; - if ((i != 1) && (i != 29) && (i % 4 == 1)) - pv_id[j++] = '-'; - } - pv_id[j] = '\0'; - - dlocn = pvh->disk_areas_xl; - - dlocn++; - /* Is it possible to have multiple data/metadata areas? I haven't - seen devices that have it. */ - if (dlocn->offset) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "we don't support multiple LVM data areas"); - -#ifdef GRUB_UTIL - grub_util_info ("we don't support multiple LVM data areas\n"); -#endif - goto fail; - } - - dlocn++; - mda_offset = grub_le_to_cpu64 (dlocn->offset); - mda_size = grub_le_to_cpu64 (dlocn->size); - - /* It's possible to have multiple copies of metadata areas, we just use the - first one. */ - - /* Allocate buffer space for the circular worst-case scenario. */ - metadatabuf = grub_malloc (2 * mda_size); - if (! metadatabuf) - goto fail; - - err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf); - if (err) - goto fail2; - - mdah = (struct grub_lvm_mda_header *) metadatabuf; - if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC, - sizeof (mdah->magic))) - || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) - { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unknown LVM metadata header"); -#ifdef GRUB_UTIL - grub_util_info ("unknown LVM metadata header\n"); -#endif - goto fail2; - } - - rlocn = mdah->raw_locns; - if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > - grub_le_to_cpu64 (mdah->size)) - { - /* 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)); - } - p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset); - - while (*q != ' ' && q < metadatabuf + mda_size) - q++; - - if (q == metadatabuf + mda_size) - { -#ifdef GRUB_UTIL - grub_util_info ("error parsing metadata\n"); -#endif - goto fail2; - } - - vgname_len = q - p; - vgname = grub_malloc (vgname_len + 1); - if (!vgname) - goto fail2; - - grub_memcpy (vgname, p, vgname_len); - vgname[vgname_len] = '\0'; - - p = grub_strstr (q, "id = \""); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("couldn't find ID\n"); -#endif - goto fail3; - } - p += sizeof ("id = \"") - 1; - grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN); - vg_id[GRUB_LVM_ID_STRLEN] = '\0'; - - for (vg = vg_list; vg; vg = vg->next) - { - if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN)) - break; - } - - if (! vg) - { - /* First time we see this volume group. We've to create the - whole volume group structure. */ - vg = grub_malloc (sizeof (*vg)); - if (! vg) - goto fail3; - vg->name = vgname; - grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1); - - vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown extent size\n"); -#endif - goto fail4; - } - - vg->lvs = NULL; - vg->pvs = NULL; - - p = grub_strstr (p, "physical_volumes {"); - if (p) - { - p += sizeof ("physical_volumes {") - 1; - - /* Add all the pvs to the volume group. */ - while (1) - { - int s; - while (grub_isspace (*p)) - p++; - - if (*p == '}') - break; - - pv = grub_malloc (sizeof (*pv)); - q = p; - while (*q != ' ') - q++; - - s = q - p; - pv->name = grub_malloc (s + 1); - grub_memcpy (pv->name, p, s); - pv->name[s] = '\0'; - - p = grub_strstr (p, "id = \""); - if (p == NULL) - goto pvs_fail; - p += sizeof("id = \"") - 1; - - grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN); - pv->id[GRUB_LVM_ID_STRLEN] = '\0'; - - pv->start = grub_lvm_getvalue (&p, "pe_start = "); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown pe_start\n"); -#endif - goto pvs_fail; - } - - p = grub_strchr (p, '}'); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("error parsing pe_start\n"); -#endif - goto pvs_fail; - } - p++; - - pv->disk = NULL; - pv->next = vg->pvs; - vg->pvs = pv; - - continue; - pvs_fail: - grub_free (pv->name); - grub_free (pv); - goto fail4; - } - } - - p = grub_strstr (p, "logical_volumes"); - if (p) - { - p += 18; - - /* 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; - int is_pvmove; - - while (grub_isspace (*p)) - p++; - - if (*p == '}') - break; - - lv = grub_malloc (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->size = 0; - - 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) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown segment_count\n"); -#endif - goto lvs_fail; - } - lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count); - seg = lv->segments; - - for (i = 0; i < lv->segment_count; i++) - { - - p = grub_strstr (p, "segment"); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown segment\n"); -#endif - goto lvs_segment_fail; - } - - seg->start_extent = grub_lvm_getvalue (&p, "start_extent = "); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown start_extent\n"); -#endif - goto lvs_segment_fail; - } - seg->extent_count = grub_lvm_getvalue (&p, "extent_count = "); - if (p == NULL) - { -#ifdef GRUB_UTIL - grub_util_info ("unknown extent_count\n"); -#endif - goto lvs_segment_fail; - } - - p = grub_strstr (p, "type = \""); - if (p == NULL) - goto lvs_segment_fail; - p += sizeof("type = \"") - 1; - - lv->size += seg->extent_count * vg->extent_size; - - if (grub_memcmp (p, "striped\"", - sizeof ("striped\"") - 1) == 0) - { - struct grub_lvm_node *stripe; - - seg->type = GRUB_LVM_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; - } - - 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'; - - stripe->start = grub_lvm_getvalue (&p, ","); - if (p == NULL) - continue; - - stripe++; - } - } - else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1) - == 0) - { - seg->type = GRUB_LVM_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 - { -#ifdef GRUB_UTIL - char *p2; - p2 = grub_strchr (p, '"'); - if (p2) - *p2 = 0; - grub_util_info ("unknown LVM type %s\n", p); - if (p2) - *p2 ='"'; -#endif - /* Found a non-supported type, give up and move on. */ - skip_lv = 1; - break; - } - - seg++; - - continue; - lvs_segment_fail2: - grub_free (seg->nodes); - lvs_segment_fail: - goto fail4; - } - - if (p != NULL) - p = grub_strchr (p, '}'); - if (p == NULL) - goto lvs_fail; - p += 3; - - if (skip_lv) - { - grub_free (lv->name); - grub_free (lv); - continue; - } - - lv->number = lv_count++; - lv->vg = vg; - lv->next = vg->lvs; - vg->lvs = lv; - - continue; - lvs_fail: - grub_free (lv->name); - grub_free (lv); - goto fail4; - } - } - - /* Match lvs. */ - { - struct grub_lvm_lv *lv1; - struct grub_lvm_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 + grub_strlen (vg->name) + 1, - lv1->segments[i].nodes[j].name) == 0) - lv1->segments[i].nodes[j].lv = lv2; - } - - } - - vg->next = vg_list; - vg_list = vg; - } - 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; - - /* Failure path. */ - fail4: - grub_free (vg); - 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; - grub_print_error (); - return 0; -} - static struct grub_disk_dev grub_lvm_dev = { .name = "lvm", @@ -878,13 +1021,6 @@ static struct grub_disk_dev grub_lvm_dev = 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); } diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.c index 0e2d85009..7ee513d26 100644 --- a/grub-core/disk/mdraid_linux.c +++ b/grub-core/disk/mdraid_linux.c @@ -216,11 +216,11 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, array->chunk_size = grub_le_to_cpu32 (sb.chunk_size) >> 9; array->index = grub_le_to_cpu32 (sb.this_disk.number); array->uuid_len = 16; - array->uuid = grub_malloc (16); + uuid = grub_malloc (16); + array->uuid = (char *) uuid; if (!array->uuid) return grub_errno; - uuid = (grub_uint32_t *) array->uuid; uuid[0] = grub_swap_bytes32 (sb.set_uuid0); uuid[1] = grub_swap_bytes32 (sb.set_uuid1); uuid[2] = grub_swap_bytes32 (sb.set_uuid2); diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c index 114ac0d9e..4de0971ae 100644 --- a/grub-core/disk/memdisk.c +++ b/grub-core/disk/memdisk.c @@ -30,8 +30,12 @@ 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"); } @@ -82,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..ff76cc1fb --- /dev/null +++ b/grub-core/disk/pata.c @@ -0,0 +1,538 @@ +/* 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->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 index c6be3efde..db1e969b3 100644 --- a/grub-core/disk/raid.c +++ b/grub-core/disk/raid.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include #endif @@ -33,6 +34,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); 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 grub_raid_t grub_raid_list; +static int inscnt = 0; + +static struct grub_raid_array * +find_array (const char *name); static char @@ -78,14 +84,102 @@ grub_is_array_readable (struct grub_raid_array *array) return 0; } +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, + grub_raid_t raid __attribute__ ((unused))); + +static int scan_depth = 0; + +static void +scan_devices (const char *arname) +{ + grub_raid_t raid; + + auto int hook (const char *name); + int hook (const char *name) + { + grub_disk_t disk; + struct grub_raid_array array; + struct grub_raid_array *arr; + grub_disk_addr_t start_sector; + + grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n", + raid->name, name); +#ifdef GRUB_UTIL + grub_util_info ("Scanning for %s RAID devices on disk %s", + raid->name, name); +#endif + + disk = grub_disk_open (name); + if (!disk) + return 0; + + for (arr = array_list; arr != NULL; arr = arr->next) + { + struct grub_raid_member *m; + for (m = arr->members; m < arr->members + arr->nr_devs; m++) + if (m->device && m->device->id == disk->id + && m->device->dev->id == disk->dev->id + && grub_partition_get_start (m->device->partition) + == grub_partition_get_start (disk->partition) + && grub_disk_get_size (m->device) + == grub_disk_get_size (disk)) + { + grub_disk_close (disk); + return 0; + } + } + + if ((disk->total_sectors != GRUB_ULONG_MAX) && + (! raid->detect (disk, &array, &start_sector)) && + (! insert_array (disk, &array, start_sector, raid->name, + raid))) + 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); + + if (arname && find_array (arname)) + return 1; + + return 0; + } + + if (scan_depth) + return; + + scan_depth++; + for (raid = grub_raid_list; raid; raid = raid->next) + grub_device_iterate (&hook); + scan_depth--; +} + static int -grub_raid_iterate (int (*hook) (const char *name)) +grub_raid_iterate (int (*hook) (const char *name), + grub_disk_pull_t pull) { struct grub_raid_array *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 != NULL; array = array->next) { - if (grub_is_array_readable (array)) + if (grub_is_array_readable (array) && array->became_readable_at >= islcnt) if (hook (array->name)) return 1; } @@ -134,11 +228,10 @@ ascii2hex (char c) return 0; } -static grub_err_t -grub_raid_open (const char *name, grub_disk_t disk) +static struct grub_raid_array * +find_array (const char *name) { struct grub_raid_array *array; - unsigned n; if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0) { @@ -155,7 +248,7 @@ grub_raid_open (const char *name, grub_disk_t disk) if (uuid_len == (unsigned) array->uuid_len && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0) if (grub_is_array_readable (array)) - break; + return array; } } else @@ -163,8 +256,33 @@ grub_raid_open (const char *name, grub_disk_t disk) { if (!grub_strcmp (array->name, name)) if (grub_is_array_readable (array)) - break; + return array; } + return NULL; +} + +static grub_err_t +grub_raid_open (const char *name, grub_disk_t disk) +{ + struct grub_raid_array *array; + unsigned n; + + if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", + name); + + array = find_array (name); + + if (! array) + { + scan_devices (name); + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + array = find_array (name); + } if (!array) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", @@ -214,23 +332,6 @@ 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) @@ -524,6 +625,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, grub_raid_t raid __attribute__ ((unused))) { struct grub_raid_array *array = 0, *p; + int was_readable = 0; /* See whether the device is part of an array we have already seen a device from. */ @@ -534,6 +636,8 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, grub_free (new_array->uuid); array = p; + was_readable = grub_is_array_readable (array); + /* Do some checks before adding the device to the array. */ if (new_array->index >= array->allocated_devs) @@ -679,6 +783,49 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, scanner_name); #endif + { + int max_used_number = 0, len, need_new_name = 0; + int add_us = 0; + len = grub_strlen (array->name); + if (len && grub_isdigit (array->name[len-1])) + add_us = 1; + for (p = array_list; p != NULL; p = p->next) + { + int cur_num; + char *num, *end; + if (grub_strncmp (p->name, array->name, len) != 0) + continue; + if (p->name[len] == 0) + { + need_new_name = 1; + continue; + } + if (add_us && p->name[len] != '_') + continue; + if (add_us) + num = p->name + len + 1; + else + num = p->name + len; + if (!grub_isdigit (num[0])) + continue; + cur_num = grub_strtoull (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%s%d", array->name, add_us ? "_" : "", + max_used_number + 1); + if (!tmp) + return grub_errno; + grub_free (array->name); + array->name = tmp; + } + } + /* Add our new array to the list. */ array->next = array_list; array_list = array; @@ -693,12 +840,12 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, array->members[new_array->index].device = disk; array->members[new_array->index].start_sector = start_sector; array->nr_devs++; + if (!was_readable && grub_is_array_readable (array)) + array->became_readable_at = inscnt++; return 0; } -static grub_raid_t grub_raid_list; - static void free_array (void) { @@ -729,45 +876,8 @@ free_array (void) 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 %s RAID devices on disk %s\n", - grub_raid_list->name, name); -#ifdef GRUB_UTIL - grub_util_info ("Scanning for %s RAID devices on disk %s", - grub_raid_list->name, name); -#endif - - 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, - grub_raid_list))) - 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 diff --git a/grub-core/disk/raid5_recover.c b/grub-core/disk/raid5_recover.c index c26d05e94..dfc89a71d 100644 --- a/grub-core/disk/raid5_recover.c +++ b/grub-core/disk/raid5_recover.c @@ -23,6 +23,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -57,7 +58,7 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr, return err; } - grub_raid_block_xor (buf, buf2, size); + grub_crypto_xor (buf, buf2, buf2, size); } grub_free (buf2); diff --git a/grub-core/disk/raid6_recover.c b/grub-core/disk/raid6_recover.c index 25b50eb6b..05d8511c5 100644 --- a/grub-core/disk/raid6_recover.c +++ b/grub-core/disk/raid6_recover.c @@ -23,70 +23,44 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); -static grub_uint8_t raid6_table1[256][256]; -static grub_uint8_t raid6_table2[256][256]; +/* 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 @@ -122,12 +96,12 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, { if ((array->members[pos].device) && (! grub_disk_read (array->members[pos].device, - array->members[i].start_sector + sector, + array->members[pos].start_sector + sector, 0, size, 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 (i, buf, size); + grub_crypto_xor (qbuf, qbuf, buf, size); } else { @@ -154,10 +128,10 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, /* One bad device */ if ((array->members[p].device) && (! grub_disk_read (array->members[p].device, - array->members[i].start_sector + sector, + array->members[p].start_sector + sector, 0, size, buf))) { - grub_raid_block_xor (buf, pbuf, size); + grub_crypto_xor (buf, buf, pbuf, size); goto quit; } @@ -169,17 +143,17 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, grub_errno = GRUB_ERR_NONE; if (grub_disk_read (array->members[q].device, - array->members[i].start_sector + sector, 0, size, buf)) + array->members[q].start_sector + sector, 0, size, 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->members[p].device) || (! array->members[q].device)) { @@ -188,26 +162,26 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p, } if (grub_disk_read (array->members[p].device, - array->members[i].start_sector + sector, + array->members[p].start_sector + sector, 0, size, buf)) goto quit; - grub_raid_block_xor (pbuf, buf, size); + grub_crypto_xor (pbuf, pbuf, buf, size); if (grub_disk_read (array->members[q].device, - array->members[i].start_sector + sector, + array->members[q].start_sector + sector, 0, size, 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 d683cbfe7..610cc4dc5 100644 --- a/grub-core/disk/scsi.c +++ b/grub-core/disk/scsi.c @@ -32,6 +32,12 @@ 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) { @@ -316,13 +322,14 @@ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector, 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; @@ -331,7 +338,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); @@ -345,7 +352,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); @@ -357,7 +364,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; @@ -372,6 +379,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 @@ -396,15 +404,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; @@ -465,22 +483,26 @@ grub_scsi_open (const char *name, grub_disk_t disk) 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; + disk->total_sectors = scsi->size; + 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; + (1 << disk->log_sector_size) < scsi->blocksize; + disk->log_sector_size++); grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n", scsi->size, scsi->blocksize); - grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n", + 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"); } @@ -503,36 +525,36 @@ 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 - 1)) != 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: + err = grub_scsi_read10 (disk, sector, len, buf); + if (err) + return err; + break; - grub_uint64_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: + 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 diff --git a/grub-core/disk/usbms.c b/grub-core/disk/usbms.c index 2f1dbd487..a4c2addf1 100644 --- a/grub-core/disk/usbms.c +++ b/grub-core/disk/usbms.c @@ -211,16 +211,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; } @@ -390,8 +394,12 @@ grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, } 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]) @@ -406,8 +414,6 @@ 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, 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/main.c b/grub-core/efiemu/main.c index 7ad3abb0d..f2c038110 100644 --- a/grub-core/efiemu/main.c +++ b/grub-core/efiemu/main.c @@ -149,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)); @@ -226,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) 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/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 26eac4c05..3737480cf 100644 --- a/grub-core/font/font.c +++ b/grub-core/font/font.c @@ -608,7 +608,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"); } diff --git a/grub-core/font/font_cmd.c b/grub-core/font/font_cmd.c index 98f0b88d6..b38eccd6d 100644 --- a/grub-core/font/font_cmd.c +++ b/grub-core/font/font_cmd.c @@ -49,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 e17540e2f..0ad5e6672 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -25,6 +25,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -32,15 +33,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); struct grub_affs_bblock { grub_uint8_t type[3]; - grub_uint8_t flags; + grub_uint8_t version; grub_uint32_t checksum; grub_uint32_t rootblock; } __attribute__ ((packed)); -/* Set if the filesystem is a AFFS filesystem. Otherwise this is an - OFS filesystem. */ -#define GRUB_AFFS_FLAG_FFS 1 - /* The affs rootblock. */ struct grub_affs_rblock { @@ -85,19 +82,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; - grub_disk_addr_t block; + 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. */ @@ -120,32 +117,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_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; @@ -153,21 +164,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, - grub_be_to_cpu32 (node->di.size), 0); -} - - static struct grub_affs_data * grub_affs_mount (grub_disk_t disk) { @@ -178,7 +174,7 @@ grub_affs_mount (grub_disk_t disk) int checksum = 0; int blocksize = 0; - data = grub_malloc (sizeof (struct grub_affs_data)); + data = grub_zalloc (sizeof (struct grub_affs_data)); if (!data) return 0; @@ -196,18 +192,12 @@ grub_affs_mount (grub_disk_t disk) } /* Test if the filesystem is a OFS filesystem. */ - if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS)) + if (data->bblock.version < 1) { grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported"); 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); @@ -270,18 +260,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; } @@ -300,25 +293,25 @@ 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, - grub_disk_addr_t block, + 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, - grub_disk_addr_t block, + int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block, const struct grub_affs_file *fil) { int type; - node = grub_malloc (sizeof (*node)); + grub_uint8_t name_u8[sizeof (fil->name) * GRUB_MAX_UTF8_PER_LATIN1 + 1]; + + node = grub_zalloc (sizeof (*node)); if (!node) { grub_free (hashtable); return 1; } - if ((int) grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR) + 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_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; @@ -330,7 +323,10 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, node->di = *fil; node->parent = dir; - if (hook (name, type, node)) + *grub_latin1_to_utf8 (name_u8, fil->name, + grub_min (fil->namelen, sizeof (fil->name))) = '\0'; + + if (hook ((char *) name_u8, type, node)) { grub_free (hashtable); return 1; @@ -339,7 +335,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, } /* Create the directory entries for `.' and `..'. */ - node = grub_malloc (sizeof (*node)); + node = grub_zalloc (sizeof (*node)); if (!node) return 1; @@ -348,7 +344,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, return 1; if (dir->parent) { - node = grub_malloc (sizeof (*node)); + node = grub_zalloc (sizeof (*node)); if (!node) return 1; *node = *dir->parent; @@ -356,7 +352,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, return 1; } - hashtable = grub_malloc (data->htsize * sizeof (*hashtable)); + hashtable = grub_zalloc (data->htsize * sizeof (*hashtable)); if (!hashtable) return 1; @@ -367,7 +363,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, for (i = 0; i < data->htsize; i++) { - grub_uint64_t next; + grub_uint32_t next; if (!hashtable[i]) continue; @@ -385,9 +381,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, if (grub_errno) goto fail; - file.name[file.namelen] = '\0'; - - if (grub_affs_create_node ((char *) (file.name), next, &file)) + if (grub_affs_create_node (next, &file)) return 1; next = grub_be_to_cpu32 (file.next); @@ -441,10 +435,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); @@ -452,7 +449,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) @@ -460,13 +456,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, diff --git a/grub-core/fs/afs.c b/grub-core/fs/afs.c index 35ef49937..00a5e3113 100644 --- a/grub-core/fs/afs.c +++ b/grub-core/fs/afs.c @@ -1,720 +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 - -GRUB_MOD_LICENSE ("GPLv3+"); - -#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 533529e3f..db251ffd7 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -26,11 +26,23 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); #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]; @@ -41,7 +53,7 @@ struct grub_btrfs_device } __attribute__ ((packed)); struct grub_btrfs_superblock -{ +{ grub_btrfs_checksum_t checksum; grub_btrfs_uuid_t uuid; grub_uint8_t dummy[0x10]; @@ -160,7 +172,8 @@ struct grub_btrfs_leaf_descriptor { unsigned depth; unsigned allocated; - struct { + struct + { grub_disk_addr_t addr; unsigned iter; unsigned maxiter; @@ -179,7 +192,7 @@ struct grub_btrfs_time { grub_int64_t sec; grub_uint32_t nanosec; -} __attribute__ ((aligned(4))); +} __attribute__ ((aligned (4))); struct grub_btrfs_inode { @@ -215,12 +228,13 @@ struct grub_btrfs_extent_data #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 }; + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 +}; static grub_err_t grub_btrfs_read_logical (struct grub_btrfs_data *data, @@ -283,7 +297,7 @@ free_iterator (struct grub_btrfs_leaf_descriptor *desc) } static grub_err_t -save_ref (struct grub_btrfs_leaf_descriptor *desc, +save_ref (struct grub_btrfs_leaf_descriptor *desc, grub_disk_addr_t addr, unsigned i, unsigned m, int l) { desc->depth++; @@ -307,7 +321,7 @@ save_ref (struct grub_btrfs_leaf_descriptor *desc, static int next (struct grub_btrfs_data *data, struct grub_btrfs_leaf_descriptor *desc, - grub_disk_addr_t *outaddr, grub_size_t *outsize, + grub_disk_addr_t * outaddr, grub_size_t * outsize, struct grub_btrfs_key *key_out) { grub_err_t err; @@ -330,17 +344,17 @@ next (struct grub_btrfs_data *data, 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)); + + 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)); + 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, + 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 @@ -354,12 +368,12 @@ next (struct grub_btrfs_data *data, *outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header) + grub_le_to_cpu32 (leaf.offset); *key_out = leaf.key; - return 1; + return 1; } static grub_err_t lower_bound (struct grub_btrfs_data *data, - const struct grub_btrfs_key *key_in, + 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, @@ -410,8 +424,9 @@ lower_bound (struct grub_btrfs_data *data, 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); - + node.key.object_id, node.key.type, + node.key.offset); + if (key_cmp (&node.key, key_in) == 0) { err = GRUB_ERR_NONE; @@ -433,7 +448,7 @@ lower_bound (struct grub_btrfs_data *data, err = GRUB_ERR_NONE; if (desc) err = save_ref (desc, addr - sizeof (head), i - 1, - grub_le_to_cpu32 (head.nitems), 0); + grub_le_to_cpu32 (head.nitems), 0); if (err) return err; addr = grub_le_to_cpu64 (node_last.addr); @@ -457,7 +472,7 @@ lower_bound (struct grub_btrfs_data *data, &leaf, sizeof (leaf)); if (err) return err; - + grub_dprintf ("btrfs", "leaf (depth %d) %" PRIxGRUB_UINT64_T " %x %" PRIxGRUB_UINT64_T "\n", depth, @@ -465,31 +480,31 @@ lower_bound (struct grub_btrfs_data *data, if (key_cmp (&leaf.key, key_in) == 0) { - grub_memcpy (key_out, &leaf.key, sizeof(*key_out)); + 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; + 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)); + 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; + return GRUB_ERR_NONE; } *outsize = 0; *outaddr = 0; @@ -503,8 +518,7 @@ lower_bound (struct grub_btrfs_data *data, } static grub_device_t -find_device (struct grub_btrfs_data *data, grub_uint64_t id, - int do_rescan) +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); @@ -540,7 +554,7 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t id, grub_device_close (dev); return 0; } - + dev_found = dev; return 1; } @@ -579,17 +593,16 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t id, } static grub_err_t -grub_btrfs_read_logical (struct grub_btrfs_data *data, - grub_disk_addr_t addr, +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; + struct grub_btrfs_chunk_item *chunk; grub_uint64_t csize; - grub_err_t err = 0; + grub_err_t err = 0; struct grub_btrfs_key key_out; int challoc = 0; grub_device_t dev; @@ -601,15 +614,15 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, addr); for (ptr = data->sblock.bootstrap_mapping; ptr < data->sblock.bootstrap_mapping - + sizeof (data->sblock.bootstrap_mapping) - - sizeof (struct grub_btrfs_key); - ) + + 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_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 @@ -704,11 +717,11 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 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; + stripe_offset = + low + grub_le_to_cpu64 (chunk->stripe_length) * high; csize = grub_le_to_cpu64 (chunk->stripe_length) - low; break; } @@ -719,14 +732,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, middle = grub_divmod64 (off, grub_le_to_cpu64 (chunk->stripe_length), &low); - + high = grub_divmod64 (middle, - grub_le_to_cpu16 (chunk->nsubstripes), + grub_le_to_cpu16 (chunk->nstripes) + / grub_le_to_cpu16 (chunk->nsubstripes), &stripen); - stripen *= grub_le_to_cpu16 (chunk->nstripes) - / grub_le_to_cpu16 (chunk->nsubstripes); - redundancy = grub_le_to_cpu16 (chunk->nstripes) - / grub_le_to_cpu16 (chunk->nsubstripes); + 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; @@ -759,7 +771,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, paddr = stripe->offset + stripe_offset; grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T - "+0x%" PRIxGRUB_UINT64_T " (%d stripes (%d substripes) of %" + "+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), @@ -769,7 +782,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, 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, + " for laddr 0x%" PRIxGRUB_UINT64_T "\n", paddr, addr); dev = find_device (data, stripe->device_id, j); @@ -815,7 +828,7 @@ grub_btrfs_mount (grub_device_t dev) } data = grub_zalloc (sizeof (*data)); - if (! data) + if (!data) return NULL; err = read_sblock (dev->disk, &data->sblock); @@ -866,8 +879,7 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data, 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); + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL); if (err) return err; if (num != key_out.object_id @@ -877,6 +889,76 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data, 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_min(osize, GRUB_BTRFS_LZO_BLOCK_SIZE - off); + + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, buf, &usize, + NULL) != LZO_E_OK) + return -1; + + to_copy = grub_min(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, @@ -909,6 +991,12 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, 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); @@ -917,26 +1005,22 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, if (!data->extent) return grub_errno; - err = grub_btrfs_read_logical (data, elemaddr, - data->extent, elemsize); + 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); + 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); + >= (char *) &data->extent->filled + sizeof (data->extent->filled)) + data->extend = + data->extstart + grub_le_to_cpu64 (data->extent->filled); - grub_dprintf ("btrfs", "extent 0x%" PRIxGRUB_UINT64_T "+0x%" - PRIxGRUB_UINT64_T " (0x%" - PRIxGRUB_UINT64_T ")\n", + 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), - grub_le_to_cpu64 (data->extent->filled)); + grub_le_to_cpu64 (data->extent->size)); if (data->extend <= pos) { grub_error (GRUB_ERR_BAD_FS, "extent not found"); @@ -956,7 +1040,8 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, } if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE - && data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB) + && 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", @@ -966,8 +1051,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, if (data->extent->encoding) { - grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "encoding not supported"); + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "encoding not supported"); return -1; } @@ -983,6 +1067,15 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, != (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; @@ -992,10 +1085,13 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_memset (buf, 0, csize); break; } - if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + + 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) @@ -1008,27 +1104,35 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_free (tmp); return -1; } - if (grub_zlib_decompress (tmp, zsize, extoff - + grub_le_to_cpu64 (data->extent->offset), - buf, csize) != (grub_ssize_t) csize) - { - 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); + + extoff, buf, csize); if (err) return -1; break; default: grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported extent type 0x%x", data->extent->type); + "unsupported extent type 0x%x", data->extent->type); return -1; } buf += csize; @@ -1054,6 +1158,7 @@ find_path (struct grub_btrfs_data *data, 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; @@ -1062,6 +1167,9 @@ find_path (struct grub_btrfs_data *data, key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; key->offset = 0; skip_default = 1; + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; while (1) { @@ -1086,25 +1194,29 @@ find_path (struct grub_btrfs_data *data, 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); + + 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); - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + grub_free (origpath); + return err; } struct grub_btrfs_dir_item *cdirel; @@ -1116,6 +1228,7 @@ find_path (struct grub_btrfs_data *data, if (!direl) { grub_free (path_alloc); + grub_free (origpath); return grub_errno; } } @@ -1125,12 +1238,13 @@ find_path (struct grub_btrfs_data *data, { 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; + < (grub_ssize_t) elemsize; cdirel = (void *) ((grub_uint8_t *) (direl + 1) + grub_le_to_cpu16 (cdirel->n) + grub_le_to_cpu16 (cdirel->m))) @@ -1144,7 +1258,9 @@ find_path (struct grub_btrfs_data *data, { grub_free (direl); grub_free (path_alloc); - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath); + grub_free (origpath); + return err; } if (!skip_default) @@ -1158,16 +1274,18 @@ find_path (struct grub_btrfs_data *data, { 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) @@ -1176,6 +1294,7 @@ find_path (struct grub_btrfs_data *data, { grub_free (direl); grub_free (path_alloc); + grub_free (origpath); return grub_errno; } @@ -1186,10 +1305,11 @@ find_path (struct grub_btrfs_data *data, { 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_memcpy (tmp + grub_le_to_cpu64 (inode.size), path, grub_strlen (path) + 1); grub_free (path_alloc); path = path_alloc = tmp; @@ -1218,6 +1338,7 @@ find_path (struct grub_btrfs_data *data, { grub_free (direl); grub_free (path_alloc); + grub_free (origpath); return err; } if (cdirel->key.object_id != key_out.object_id @@ -1225,14 +1346,16 @@ find_path (struct grub_btrfs_data *data, { grub_free (direl); grub_free (path_alloc); - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + 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)); + 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; @@ -1246,7 +1369,9 @@ find_path (struct grub_btrfs_data *data, { grub_free (direl); grub_free (path_alloc); - return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); + 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) @@ -1254,20 +1379,23 @@ find_path (struct grub_btrfs_data *data, break; default: grub_free (path_alloc); + grub_free (origpath); grub_free (direl); - return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x", + 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)) + 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; @@ -1286,23 +1414,28 @@ grub_btrfs_dir (grub_device_t device, const char *path, err = find_path (data, path, &key_in, &tree, &type); if (err) - return err; + { + grub_btrfs_unmount (data); + return err; + } if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a 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); + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc); if (err) - return 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) - { - free_iterator (&desc); - return -r; - } + goto out; } do { @@ -1320,18 +1453,21 @@ grub_btrfs_dir (grub_device_t device, const char *path, direl = grub_malloc (allocated + 1); if (!direl) { - free_iterator (&desc); - return grub_errno; + r = -grub_errno; + break; } } err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize); if (err) - return err; + { + r = -err; + break; + } for (cdirel = direl; (grub_uint8_t *) cdirel - (grub_uint8_t *) direl - < (grub_ssize_t) elemsize; + < (grub_ssize_t) elemsize; cdirel = (void *) ((grub_uint8_t *) (direl + 1) + grub_le_to_cpu16 (cdirel->n) + grub_le_to_cpu16 (cdirel->m))) @@ -1360,7 +1496,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, } while (r > 0); - out: +out: grub_free (direl); free_iterator (&desc); @@ -1432,7 +1568,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) *uuid = NULL; data = grub_btrfs_mount (device); - if (! data) + if (!data) return grub_errno; *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", @@ -1458,7 +1594,7 @@ grub_btrfs_label (grub_device_t device, char **label) *label = NULL; data = grub_btrfs_mount (device); - if (! data) + if (!data) return grub_errno; *label = grub_strndup (data->sblock.label, sizeof (data->sblock.label)); @@ -1468,26 +1604,55 @@ grub_btrfs_label (grub_device_t device, char **label) return grub_errno; } -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 - .reserved_first_sector = 1, -#endif - }; +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; -GRUB_MOD_INIT(btrfs) + 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 3a07873ec..3107d0194 100644 --- a/grub-core/fs/cpio.c +++ b/grub-core/fs/cpio.c @@ -25,28 +25,74 @@ GRUB_MOD_LICENSE ("GPLv3+"); -#ifndef MODE_USTAR -/* cpio support */ -#define MAGIC_BCPIO 070707 +#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]; @@ -71,60 +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_int32_t *mtime, 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 (mtime) - *mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_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]) @@ -133,18 +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 = grub_strtoul (hd.mtime, NULL, 8); + *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; } @@ -158,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; @@ -186,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] = '/'; + } + 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); @@ -202,35 +506,39 @@ 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) { grub_int32_t mtime; + grub_uint32_t mode; + grub_err_t err; - if (grub_cpio_find_file (data, &name, &mtime, &ofs)) + 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)); @@ -238,24 +546,44 @@ grub_cpio_dir (grub_device_t device, const char *path, 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); @@ -263,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, NULL, &ofs)) + grub_uint32_t mode; + int restart; + + if (grub_cpio_find_file (data, &fn, NULL, &ofs, &mode)) goto fail; if (!ofs) @@ -288,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; @@ -325,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); @@ -347,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); @@ -357,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 @@ -371,6 +719,10 @@ static struct grub_fs grub_cpio_fs = { #ifdef MODE_USTAR GRUB_MOD_INIT (tar) +#elif defined (MODE_ODC) +GRUB_MOD_INIT (odc) +#elif defined (MODE_NEWC) +GRUB_MOD_INIT (newc) #else GRUB_MOD_INIT (cpio) #endif @@ -381,6 +733,10 @@ 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) #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 0fdf151a2..6eb53d3f8 100644 --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@ -337,7 +337,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) { @@ -387,7 +387,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; diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c index f617bb0f4..0569120fb 100644 --- a/grub-core/fs/fat.c +++ b/grub-core/fs/fat.c @@ -30,28 +30,117 @@ GRUB_MOD_LICENSE ("GPLv3+"); -#define GRUB_FAT_DIR_ENTRY_SIZE 32 +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_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 +#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_MAXFILE 256 +#ifdef MODE_EXFAT +struct grub_exfat_bpb +{ + grub_uint8_t jmp_boot[3]; + grub_uint8_t oem_name[8]; + 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_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 -#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) +#ifdef MODE_EXFAT +struct grub_fat_dir_entry +{ + grub_uint8_t entry_type; + union + { + 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 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[11]; + grub_uint8_t reserved[8]; + } __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]; @@ -80,6 +169,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; @@ -90,8 +183,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; @@ -109,6 +204,7 @@ struct grub_fat_data static grub_dl_t my_mod; +#ifndef MODE_EXFAT static int fat_log2 (unsigned x) { @@ -125,11 +221,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; @@ -144,20 +241,35 @@ grub_fat_mount (grub_disk_t disk) if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb)) goto fail; +#ifdef MODE_EXFAT + if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ", + sizeof (bpb.oem_name)) != 0) + goto fail; +#else 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; +#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; @@ -167,18 +279,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; @@ -186,22 +308,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. */ @@ -243,6 +387,7 @@ grub_fat_mount (grub_disk_t disk) data->cluster_eof_mark = 0xfff8; } } +#endif /* More sanity checks. */ if (data->num_sectors <= data->fat_sector) @@ -274,17 +419,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; @@ -311,6 +464,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) @@ -324,13 +478,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) { @@ -422,13 +577,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; @@ -438,7 +696,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) { @@ -455,10 +713,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) { @@ -543,7 +802,6 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data, filep++; } *filep = '\0'; - if (hook (filename, &dir)) break; } @@ -553,7 +811,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. @@ -565,11 +823,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)); @@ -577,8 +836,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); @@ -586,9 +850,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) @@ -605,6 +874,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++; @@ -616,7 +889,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'; @@ -629,9 +902,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; } @@ -738,14 +1013,67 @@ 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 (11 * 4 + 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) { @@ -780,6 +1108,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) { @@ -791,9 +1121,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; @@ -807,7 +1140,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, @@ -815,18 +1152,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 f879885ac..275cb9e1b 100644 --- a/grub-core/fs/fshelp.c +++ b/grub-core/fs/fshelp.c @@ -61,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; @@ -197,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 cb7679ecb..6c5c4da3e 100644 --- a/grub-core/fs/hfs.c +++ b/grub-core/fs/hfs.c @@ -244,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; @@ -267,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) @@ -275,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; @@ -748,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; @@ -815,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) { @@ -921,7 +920,7 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path, 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; } diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c index 304b32126..7e859be41 100644 --- a/grub-core/fs/hfsplus.c +++ b/grub-core/fs/hfsplus.c @@ -181,7 +181,8 @@ enum grub_hfsplus_filetype struct grub_hfsplus_catkey_internal { grub_uint32_t parent; - char *name; + const grub_uint16_t *name; + grub_size_t namelen; }; /* Internal representation of an extent overflow key. */ @@ -214,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; @@ -236,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; }; @@ -245,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 @@ -263,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]; } @@ -272,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++) @@ -288,7 +288,7 @@ grub_hfsplus_find_block (struct grub_hfsplus_extent *extent, } *fileblock = blksleft; - return -1; + return 0xffffffffffffffffULL; } static grub_err_t @@ -296,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); @@ -307,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); @@ -325,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))); @@ -341,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, @@ -376,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, @@ -411,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) @@ -518,8 +519,6 @@ 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; /* Safe unsigned comparison */ @@ -529,29 +528,35 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya, 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]); + diff = grub_memcmp (catkey_a->name, catkey_b->name, + grub_min (grub_be_to_cpu16 (catkey_a->namelen), + catkey_b->namelen) + * 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 @@ -601,10 +606,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 (;;) { @@ -642,12 +647,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) @@ -660,7 +666,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); @@ -689,7 +696,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 @@ -701,10 +708,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; } } @@ -770,6 +777,11 @@ 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++) { @@ -780,18 +792,8 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir, 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++) @@ -801,22 +803,18 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir, 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); @@ -825,11 +823,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, @@ -894,7 +893,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) @@ -902,13 +900,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, @@ -963,13 +958,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 7d86b78bf..000000000 --- a/grub-core/fs/i386/pc/pxe.c +++ /dev/null @@ -1,653 +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 - -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_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_BAD_FS, "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_BAD_FS, "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_easily_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; - grub_uint64_t 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); - grub_env_export ("net_pxe_mac"); -} - -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); - grub_env_export (varname); -} - -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 - development 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_env_export ("pxe_default_server"); - grub_env_export ("pxe_default_gateway"); - grub_env_export ("net_pxe_ip"); - grub_env_export ("pxe_blksize"); - - 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 508cc5b71..fb5da2aa7 100644 --- a/grub-core/fs/iso9660.c +++ b/grub-core/fs/iso9660.c @@ -149,22 +149,29 @@ 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; - struct grub_iso9660_dir dirent; - 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; @@ -214,35 +221,77 @@ iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix) 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; @@ -259,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 ()) @@ -281,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; @@ -351,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. */ @@ -363,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: @@ -425,42 +502,125 @@ grub_iso9660_mount (grub_disk_t disk) static char * grub_iso9660_read_symlink (grub_fshelp_node_t node) { - 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) { @@ -469,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; } @@ -502,109 +662,13 @@ grub_iso9660_read_symlink (grub_fshelp_node_t node) return 0; } - sua_off = (sizeof (node->dirent) + node->dirent.namelen + 1 - - (node->dirent.namelen % 2) - + node->data->susp_skip); - sua_size = node->dirent.len - sua_off; + len = get_node_size (dir); - 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. */ @@ -629,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; @@ -676,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; } @@ -690,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) @@ -702,7 +759,64 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, filename_alloc = 1; } - node->dirent = dirent; + 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) @@ -712,8 +826,6 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir, if (filename_alloc) grub_free (filename); } - - offset += dirent.len; } return 0; @@ -741,7 +853,7 @@ 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->dirent.mtime, &info.mtime); + info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime); grub_free (node); return hook (filename, &info); @@ -754,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, @@ -795,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, @@ -806,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; @@ -831,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) @@ -847,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); @@ -864,8 +979,7 @@ 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) diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c index c131169d8..72d6fe4c1 100644 --- a/grub-core/fs/jfs.c +++ b/grub-core/fs/jfs.c @@ -52,9 +52,9 @@ struct grub_jfs_sblock grub_uint32_t blksz; grub_uint16_t log2_blksz; - grub_uint8_t unused[71]; + grub_uint8_t unused[79]; grub_uint8_t volname[11]; - grub_uint8_t unused2[32]; + grub_uint8_t unused2[24]; grub_uint8_t uuid[16]; }; @@ -205,7 +205,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)); @@ -238,7 +238,10 @@ struct grub_jfs_diropen 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)); @@ -253,11 +256,11 @@ static grub_int64_t grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, 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; @@ -269,7 +272,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)); @@ -288,7 +291,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)) @@ -479,7 +482,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); @@ -487,7 +490,7 @@ 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. */ @@ -558,10 +561,10 @@ 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), - grub_uint64_t pos, grub_size_t len, char *buf) + grub_off_t pos, grub_size_t len, char *buf) { - grub_uint64_t i; - grub_uint64_t blockcnt; + grub_off_t i; + grub_off_t blockcnt; blockcnt = (len + pos + grub_le_to_cpu32 (data->sblock.blksz) - 1) >> grub_le_to_cpu16 (data->sblock.log2_blksz); @@ -614,7 +617,8 @@ 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; @@ -623,7 +627,7 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path) 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. */ @@ -699,7 +703,7 @@ 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; } @@ -707,14 +711,14 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path) static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino) { - grub_uint64_t 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; @@ -724,11 +728,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t 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); @@ -750,7 +750,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); @@ -801,7 +801,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; @@ -891,6 +891,8 @@ grub_jfs_label (grub_device_t device, char **label) else *label = 0; + grub_free (data); + return grub_errno; } diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c index 64a64cca0..401883e36 100644 --- a/grub-core/fs/minix.c +++ b/grub-core/fs/minix.c @@ -63,7 +63,7 @@ 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])) @@ -76,11 +76,11 @@ typedef grub_uint16_t grub_minix_ino_t; #define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \ + grub_le_to_cpu16 (data->sblock.log2_zone_size)) #endif -#define GRUB_MINIX_ZONESZ (data->block_size \ - << grub_le_to_cpu16 (data->sblock.log2_zone_size)) +#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->block_size / GRUB_DISK_SECTOR_SIZE)) +#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 @@ -132,16 +132,15 @@ 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_uint16_t size; - grub_uint32_t ctime; + grub_uint32_t size; + grub_uint32_t mtime; grub_uint8_t gid; grub_uint8_t nlinks; grub_uint16_t dir_zones[7]; @@ -160,7 +159,7 @@ struct grub_minix_data int linknest; grub_disk_t disk; int filename_size; - grub_size_t block_size; + grub_size_t log_block_size; }; static grub_dl_t my_mod; @@ -168,15 +167,19 @@ 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) { - 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, @@ -192,25 +195,38 @@ grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk) /* Indirect block. */ blk -= GRUB_MINIX_INODE_DIR_BLOCKS; - if (blk < GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data)) + 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"); @@ -235,14 +251,15 @@ grub_minix_read_file (struct grub_minix_data *data, if (len + pos > GRUB_MINIX_INODE_SIZE (data)) len = GRUB_MINIX_INODE_SIZE (data) - pos; - blockcnt = grub_divmod64 ((len + pos + data->block_size - 1), - data->block_size, 0); - posblock = grub_divmod64 (pos, data->block_size, &blockoff); + 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 = posblock; i < blockcnt; i++) { grub_disk_addr_t blknr; - grub_uint64_t blockend = data->block_size; + grub_uint64_t blockend = 1 << data->log_block_size; grub_off_t skipfirst = 0; blknr = grub_minix_get_file_block (data, i); @@ -252,10 +269,10 @@ grub_minix_read_file (struct grub_minix_data *data, /* Last block. */ if (i == blockcnt - 1) { - grub_divmod64 (len + pos, data->block_size, &blockend); + blockend = (len + pos) & ((1 << data->log_block_size) - 1); if (!blockend) - blockend = data->block_size; + blockend = 1 << data->log_block_size; } /* First block. */ @@ -273,7 +290,7 @@ grub_minix_read_file (struct grub_minix_data *data, if (grub_errno) return -1; - buf += data->block_size - skipfirst; + buf += (1 << data->log_block_size) - skipfirst; } return len; @@ -424,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; } @@ -463,9 +480,14 @@ grub_minix_mount (grub_disk_t disk) data->disk = disk; data->linknest = 0; #ifdef MODE_MINIX3 - data->block_size = grub_le_to_cpu16 (data->sblock.block_size); + if ((grub_le_to_cpu16 (data->sblock.block_size) + & (grub_le_to_cpu16 (data->sblock.block_size) - 1)) + || grub_le_to_cpu16 (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->block_size = 1024U; + data->log_block_size = 10; #endif return data; @@ -536,11 +558,7 @@ grub_minix_dir (grub_device_t device, const char *path, info.dir = ((GRUB_MINIX_INODE_MODE (data) & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR); info.mtimeset = 1; -#ifndef MODE_MINIX2 - info.mtime = grub_le_to_cpu32 (data->inode.ctime); -#else info.mtime = grub_le_to_cpu32 (data->inode.mtime); -#endif if (hook (filename, &info) ? 1 : 0) break; 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 44fb213bd..0b001eb0e 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -58,6 +58,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); 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; @@ -207,6 +208,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 @@ -214,6 +216,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; @@ -296,17 +299,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_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 @@ -317,55 +320,58 @@ 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_uint64_t group_offset; @@ -373,10 +379,9 @@ grub_nilfs2_palloc_entry_offset (struct grub_nilfs2_data *data, group = grub_nilfs2_palloc_group (data, nr, &group_offset); return grub_nilfs2_palloc_bitmap_block_offset (data, group, - entry_size) + 1 + - grub_divmod64 (group_offset, grub_nilfs2_entries_per_block (data, - entry_size), - NULL); + 1 << log_entry_size) + 1 + + (group_offset >> grub_nilfs2_log_entries_per_block_log (data, + log_entry_size)); } @@ -395,9 +400,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 @@ -498,7 +503,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; @@ -582,12 +587,11 @@ grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key) 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) @@ -628,7 +632,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, @@ -652,8 +656,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) { @@ -686,12 +690,11 @@ grub_nilfs2_read_inode (struct grub_nilfs2_data *data, 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) { @@ -866,7 +869,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) @@ -1117,7 +1120,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], @@ -1150,7 +1153,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); @@ -1178,6 +1181,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 5d128bcc0..7dbe0e5e5 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 @@ -30,10 +32,30 @@ 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 (struct grub_ntfs_data *data, char *buf, int len, const char *magic) { int ss; char *pu; @@ -56,7 +78,8 @@ fixup (struct grub_ntfs_data *data, char *buf, int len, char *magic) 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--; } @@ -87,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; } @@ -103,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) @@ -114,14 +137,14 @@ 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; @@ -160,7 +183,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; @@ -170,7 +193,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; @@ -199,7 +222,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)) @@ -209,13 +232,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) { @@ -223,13 +249,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; } @@ -245,13 +271,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; @@ -296,7 +322,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, @@ -325,9 +351,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; } @@ -345,7 +371,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); } @@ -376,24 +402,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; @@ -408,17 +434,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; @@ -428,12 +454,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_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; @@ -445,12 +471,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; @@ -481,12 +507,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) { @@ -513,8 +539,8 @@ 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"); } @@ -526,7 +552,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; @@ -541,7 +567,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); @@ -550,7 +576,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 @@ -595,6 +621,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)) { @@ -602,9 +629,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) @@ -617,12 +648,18 @@ list_file (struct grub_ntfs_file *diro, char *pos, 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; @@ -639,6 +676,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 @@ -668,7 +801,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; @@ -694,7 +827,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; @@ -735,7 +868,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" */ @@ -743,7 +876,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)) @@ -756,7 +889,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; @@ -766,8 +899,8 @@ 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)) + (at, indx, i * (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), 0, 0)) || (fixup (mft->data, indx, mft->data->idx_size, "INDX"))) goto done; ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], hook); @@ -814,32 +947,32 @@ grub_ntfs_mount (grub_disk_t disk) 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 * (data->blocksize >> 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); @@ -847,10 +980,10 @@ grub_ntfs_mount (grub_disk_t disk) if (fixup (data, 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; @@ -901,7 +1034,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; @@ -939,7 +1072,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; @@ -1030,7 +1163,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; @@ -1039,7 +1172,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; @@ -1048,8 +1181,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; } @@ -1087,14 +1226,15 @@ grub_ntfs_uuid (grub_device_t device, char **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 d2893cb99..890faa3bf 100644 --- a/grub-core/fs/ntfscomp.c +++ b/grub-core/fs/ntfscomp.c @@ -21,7 +21,6 @@ #include #include #include -#include #include GRUB_MOD_LICENSE ("GPLv3+"); @@ -35,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])) @@ -47,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; @@ -87,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"); @@ -150,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"); } @@ -160,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)) @@ -179,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) { @@ -192,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)) @@ -200,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] = @@ -216,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 @@ -234,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--; } } @@ -259,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 >= @@ -276,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; } @@ -294,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; @@ -304,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; @@ -323,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); @@ -334,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 d5bc52d14..639de8d74 100644 --- a/grub-core/fs/reiserfs.c +++ b/grub-core/fs/reiserfs.c @@ -57,8 +57,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); #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 @@ -109,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 @@ -1323,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; } diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c index 07632e635..11c844e91 100644 --- a/grub-core/fs/romfs.c +++ b/grub-core/fs/romfs.c @@ -24,6 +24,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + struct grub_romfs_superblock { char magic[8]; @@ -110,7 +112,7 @@ grub_romfs_mount (grub_device_t dev) if (err) return NULL; for (ptr = sb.sb.label; (void *) ptr < (void *) (&sb + 1) - && ptr < sb.d + grub_be_to_cpu32 (sb.sb.total_size); ptr++) + && ptr - sb.d < (grub_ssize_t) grub_be_to_cpu32 (sb.sb.total_size); ptr++) if (!*ptr) break; if ((void *) ptr == &sb + 1) @@ -122,7 +124,7 @@ grub_romfs_mount (grub_device_t dev) if (err) return NULL; for (ptr = sb.d; (void *) ptr < (void *) (&sb + 1) - && ptr < sb.d + grub_be_to_cpu32 (sb.sb.total_size); ptr++) + && ptr - sb.d < (grub_ssize_t) grub_be_to_cpu32 (sb.sb.total_size); ptr++) if (!*ptr) break; } @@ -164,17 +166,18 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, { grub_disk_addr_t caddr; struct grub_romfs_file_header hdr; - grub_size_t a = 0; - char *name = NULL; 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; + struct grub_fshelp_node *node = NULL; grub_err_t err; err = grub_disk_read (dir->data->disk, caddr >> GRUB_DISK_SECTOR_BITS, @@ -187,9 +190,9 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, } for (nptr = 0; ; nptr++, naddr += 16) { - if (a >= nptr) + if (a <= nptr) { - char *on; + grub_properly_aligned_t *on; a = 2 * (nptr + 1); on = name; name = grub_realloc (name, a * 16); @@ -199,13 +202,14 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, 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 * nptr); + 16, name + (16 / sizeof (name[0])) * nptr); if (err) return 1; for (j = 0; j < 16; j++) - if (!name[16 * nptr + j]) + if (!((char *) name)[16 * nptr + j]) break; if (j != 16) break; @@ -290,7 +294,7 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, } } - if (hook (name, filetype, node)) + if (hook ((char *) name, filetype, node)) { grub_free (name); return 1; @@ -365,6 +369,7 @@ grub_romfs_open (struct grub_file *file, const char *name) file->size = grub_be_to_cpu32 (fdiro->file.size); file->data = fdiro; + return GRUB_ERR_NONE; fail: grub_free (data); @@ -394,7 +399,10 @@ grub_romfs_read (grub_file_t file, char *buf, grub_size_t len) static grub_err_t grub_romfs_close (grub_file_t file) { - grub_free (file->data); + struct grub_fshelp_node *data = file->data; + + grub_free (data->data); + grub_free (data); return GRUB_ERR_NONE; } @@ -429,6 +437,7 @@ grub_romfs_label (grub_device_t device, char **label) return err; } (*label)[data->first_file - sizeof (struct grub_romfs_superblock)] = 0; + grub_free (data); return GRUB_ERR_NONE; } diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c index 19ae90715..f1e09ccbd 100644 --- a/grub-core/fs/sfs.c +++ b/grub-core/fs/sfs.c @@ -250,7 +250,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, diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c index 4f1265582..e14df6dbf 100644 --- a/grub-core/fs/squash4.c +++ b/grub-core/fs/squash4.c @@ -42,7 +42,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); exttblptr RAW superblock UID/GID table is the array ot uint32_t - unk1 contains pointer to unk3 followed by some chunk. + unk1 contains pointer to fragment table followed by some chunk. unk2 containts one uint64_t */ @@ -52,13 +52,9 @@ struct grub_squash_super #define SQUASH_MAGIC 0x73717368 grub_uint32_t dummy1; grub_uint32_t creation_time; - grub_uint32_t dummy2; + grub_uint32_t block_size; grub_uint64_t dummy3; - grub_uint8_t flags; -#define SQUASH_FLAG_UNCOMPRESSED_INODES 1 -#define SQUASH_FLAG_UNCOMPRESSED_DATA 2 -#define SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS 8 - grub_uint8_t dummy4[7]; + grub_uint64_t dummy4; grub_uint16_t root_ino_offset; grub_uint32_t root_ino_chunk; grub_uint16_t dummy5; @@ -71,7 +67,6 @@ struct grub_squash_super grub_uint64_t unk2offset; } __attribute__ ((packed)); - /* Chunk-based */ struct grub_squash_inode { @@ -85,16 +80,30 @@ struct grub_squash_inode grub_uint32_t dummy; grub_uint32_t chunk; grub_uint32_t fragment; - grub_uint32_t offset; + grub_uint16_t offset; + grub_uint16_t dummy2; grub_uint32_t size; + grub_uint32_t block_size[0]; } __attribute__ ((packed)) file; + struct { + grub_uint32_t dummy; + grub_uint64_t chunk; + grub_uint64_t size; + grub_uint32_t dummy2[3]; + grub_uint32_t fragment; + grub_uint16_t offset; + grub_uint16_t dummy3; + grub_uint32_t dummy4; + grub_uint32_t block_size[0]; + } __attribute__ ((packed)) long_file; struct { grub_uint32_t dummy1; grub_uint32_t chunk; grub_uint32_t dummy2; grub_uint16_t size; - grub_uint32_t offset; + grub_uint16_t offset; grub_uint16_t dummy3; + grub_uint16_t dummy4; } __attribute__ ((packed)) dir; struct { grub_uint64_t dummy; @@ -104,12 +113,22 @@ struct grub_squash_inode } __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_uint64_t ino_chunk; + grub_uint32_t ino_chunk; + grub_uint32_t dummy; } __attribute__ ((packed)); struct grub_squash_dirent @@ -117,46 +136,62 @@ struct grub_squash_dirent grub_uint16_t ino_offset; grub_uint16_t dummy; grub_uint16_t type; -#define SQUASH_TYPE_DIR 1 -#define SQUASH_TYPE_REGULAR 2 -#define SQUASH_TYPE_SYMLINK 3 /* 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_REGULAR = 9, + }; + + struct grub_squash_frag_desc { grub_uint64_t offset; - grub_uint64_t dummy; + 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 + }; + #define SQUASH_CHUNK_SIZE 0x2000 -#define SQUASH_CHUNK_FLAGS 0x8000 -#define SQUASH_CHUNK_UNCOMPRESSED 0x8000 struct grub_squash_data { grub_disk_t disk; struct grub_squash_super sb; - struct grub_squash_inode ino; + struct grub_squash_cache_inode ino; grub_uint64_t fragments; + int log2_blksz; }; struct grub_fshelp_node { struct grub_squash_data *data; struct grub_squash_inode ino; - grub_uint32_t ino_chunk; + grub_disk_addr_t ino_chunk; grub_uint16_t ino_offset; }; static grub_err_t -read_chunk (grub_disk_t disk, void *buf, grub_size_t len, - grub_uint64_t chunk, grub_off_t offset) +read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + grub_uint64_t chunk_start, grub_off_t offset) { - grub_uint64_t chunk_start; - chunk_start = grub_le_to_cpu64 (chunk); while (len > 0) { grub_uint64_t csize; @@ -164,7 +199,8 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len, grub_err_t err; while (1) { - err = grub_disk_read (disk, chunk_start >> GRUB_DISK_SECTOR_BITS, + err = grub_disk_read (data->disk, + chunk_start >> GRUB_DISK_SECTOR_BITS, chunk_start & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (d), &d); if (err) @@ -182,7 +218,7 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len, if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED) { grub_disk_addr_t a = chunk_start + 2 + offset; - err = grub_disk_read (disk, (a >> GRUB_DISK_SECTOR_BITS), + err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS), a & (GRUB_DISK_SECTOR_SIZE - 1), csize, buf); if (err) @@ -197,7 +233,7 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len, if (!tmp) return grub_errno; /* FIXME: buffer uncompressed data. */ - err = grub_disk_read (disk, (a >> GRUB_DISK_SECTOR_BITS), + err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS), a & (GRUB_DISK_SECTOR_SIZE - 1), bsize, tmp); if (err) @@ -234,27 +270,35 @@ squash_mount (grub_disk_t disk) grub_error (GRUB_ERR_BAD_FS, "not a squash4"); if (err) return NULL; - if (grub_le_to_cpu32 (sb.magic) != SQUASH_MAGIC) + if (grub_le_to_cpu32 (sb.magic) != SQUASH_MAGIC + || grub_le_to_cpu32 (sb.block_size) == 0 + || ((grub_le_to_cpu32 (sb.block_size) - 1) + & grub_le_to_cpu32 (sb.block_size))) { grub_error (GRUB_ERR_BAD_FS, "not squash4"); return NULL; } - err = grub_disk_read (disk, grub_le_to_cpu32 (sb.unk1offset) + err = grub_disk_read (disk, + grub_le_to_cpu64 (sb.unk1offset) >> GRUB_DISK_SECTOR_BITS, - grub_le_to_cpu32 (sb.unk1offset) + 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_malloc (sizeof (*data)); + data = grub_zalloc (sizeof (*data)); if (!data) return NULL; data->sb = sb; data->disk = disk; - data->fragments = frag; + data->fragments = grub_le_to_cpu64 (frag); + + for (data->log2_blksz = 0; + (1U << data->log2_blksz) < grub_le_to_cpu32 (data->sb.block_size); + data->log2_blksz++); return data; } @@ -266,7 +310,7 @@ grub_squash_read_symlink (grub_fshelp_node_t node) grub_err_t err; ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1); - err = read_chunk (node->data->disk, ret, + 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, @@ -293,20 +337,20 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, unsigned i; /* FIXME: why - 3 ? */ - endoff = grub_le_to_cpu32 (dir->ino.dir.size) + off - 3; + endoff = grub_le_to_cpu16 (dir->ino.dir.size) + off - 3; while (off < endoff) { struct grub_squash_dirent_header dh; grub_err_t err; - err = read_chunk (dir->data->disk, &dh, sizeof (dh), + err = read_chunk (dir->data, &dh, sizeof (dh), grub_le_to_cpu64 (dir->data->sb.diroffset) + grub_le_to_cpu32 (dir->ino.dir.chunk), off); if (err) return 0; off += sizeof (dh); - for (i = 0; i < (unsigned) grub_le_to_cpu16 (dh.nelems) + 1; i++) + for (i = 0; i < (unsigned) grub_le_to_cpu32 (dh.nelems) + 1; i++) { char *buf; int r; @@ -315,14 +359,14 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, struct grub_squash_dirent di; struct grub_squash_inode ino; - err = read_chunk (dir->data->disk, &di, sizeof (di), + err = read_chunk (dir->data, &di, sizeof (di), grub_le_to_cpu64 (dir->data->sb.diroffset) + grub_le_to_cpu32 (dir->ino.dir.chunk), off); if (err) return 0; off += sizeof (di); - err = read_chunk (dir->data->disk, &ino, sizeof (ino), + 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)); @@ -332,7 +376,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2); if (!buf) return 0; - err = read_chunk (dir->data->disk, buf, + err = read_chunk (dir->data, buf, grub_le_to_cpu16 (di.namelen) + 1, grub_le_to_cpu64 (dir->data->sb.diroffset) + grub_le_to_cpu32 (dir->ino.dir.chunk), off); @@ -370,12 +414,21 @@ 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->disk, &root->ino, sizeof (root->ino), + return read_chunk (data, &root->ino, sizeof (root->ino), grub_le_to_cpu64 (data->sb.inodeoffset) + grub_le_to_cpu16 (data->sb.root_ino_chunk), grub_cpu_to_le16 (data->sb.root_ino_offset)); } +static void +squash_unmount (struct grub_squash_data *data) +{ + 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, @@ -394,6 +447,7 @@ grub_squash_dir (grub_device_t device, const char *path, 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); } @@ -415,7 +469,7 @@ grub_squash_dir (grub_device_t device, const char *path, if (!grub_errno) grub_squash_iterate_dir (fdiro, iterate); - grub_free (data); + squash_unmount (data); return grub_errno; } @@ -440,53 +494,173 @@ grub_squash_open (struct grub_file *file, const char *name) grub_squash_read_symlink, GRUB_FSHELP_REG); if (grub_errno) { - grub_free (data); + squash_unmount (data); return grub_errno; } file->data = data; - data->ino = fdiro->ino; - file->size = grub_le_to_cpu32 (fdiro->ino.file.size); + 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; + + if (fdiro->ino.type + == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR)) + file->size = grub_le_to_cpu64 (fdiro->ino.long_file.size); + else + file->size = grub_le_to_cpu32 (fdiro->ino.file.size); + + 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; + grub_size_t i; + grub_size_t origlen = len; + + if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR)) + a = grub_le_to_cpu64 (ino->ino.long_file.chunk); + else + a = grub_le_to_cpu32 (ino->ino.file.chunk); + + if (!ino->block_sizes) + { + grub_off_t total_size; + grub_size_t total_blocks; + grub_size_t block_offset; + if (ino->ino.type + == 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); + } + else + { + total_size = grub_le_to_cpu32 (ino->ino.file.size); + block_offset = ((char *) &ino->ino.file.block_size + - (char *) &ino->ino); + } + total_blocks = ((total_size + + grub_le_to_cpu32 (data->sb.block_size) - 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 = grub_le_to_cpu32 (data->sb.block_size) + * (grub_disk_addr_t) i; + while (cumulated_uncompressed_size < off + len) + { + grub_size_t boff, read; + boff = off - cumulated_uncompressed_size; + read = grub_le_to_cpu32 (data->sb.block_size) - boff; + if (read > len) + read = len; + if (!(ino->block_sizes[i] + & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED))) + err = grub_zlib_disk_read (data->disk, + ino->cumulated_block_sizes[i] + a, + boff, buf, read); + 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, - grub_disk_t disk, const struct grub_squash_inode *ino, + struct grub_squash_cache_inode *ino, grub_off_t off, char *buf, grub_size_t len) { grub_err_t err; grub_uint64_t a, b; + grub_uint32_t fragment; int compressed = 0; + struct grub_squash_frag_desc frag; - if (grub_le_to_cpu16 (ino->file.fragment) == 0xffff) + if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR)) { - if (grub_le_to_cpu32 (ino->file.chunk)) - a = grub_le_to_cpu32 (ino->file.chunk); - else - a = sizeof (struct grub_squash_super); - compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_DATA); + a = grub_le_to_cpu64 (ino->ino.long_file.chunk); + fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment); } else { - struct grub_squash_frag_desc frag; - err = read_chunk (disk, &frag, sizeof (frag), - data->fragments, sizeof (frag) - * grub_le_to_cpu16 (ino->file.fragment)); - if (err) - return -1; - a = grub_le_to_cpu64 (frag.offset) + grub_le_to_cpu32 (ino->file.chunk); - compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS); + a = grub_le_to_cpu32 (ino->ino.file.chunk); + fragment = grub_le_to_cpu32 (ino->ino.file.fragment); } - b = grub_le_to_cpu32 (data->ino.file.offset) + off; - + 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) - err = grub_zlib_disk_read (disk, a, b, buf, len); + err = grub_zlib_disk_read (data->disk, a, b, buf, len); else - err = grub_disk_read (disk, (a + b) >> GRUB_DISK_SECTOR_BITS, + 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; @@ -498,14 +672,14 @@ 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, file->device->disk, &data->ino, + return grub_squash_read_data (data, &data->ino, file->offset, buf, len); } static grub_err_t grub_squash_close (grub_file_t file) { - grub_free (file->data); + squash_unmount (file->data); return GRUB_ERR_NONE; } @@ -518,7 +692,7 @@ grub_squash_mtime (grub_device_t dev, grub_int32_t *tm) if (! data) return grub_errno; *tm = grub_le_to_cpu32 (data->sb.creation_time); - grub_free (data); + squash_unmount (data); return GRUB_ERR_NONE; } diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c index 48906f84f..537bb37f0 100644 --- a/grub-core/fs/udf.c +++ b/grub-core/fs/udf.c @@ -317,7 +317,7 @@ struct grub_udf_partmap grub_uint8_t ident[62]; } type2; }; -}; +} __attribute__ ((packed)); struct grub_udf_lvd { @@ -546,8 +546,7 @@ grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) } fail: - if (buf) - grub_free (buf); + grub_free (buf); return 0; } @@ -821,7 +820,7 @@ read_string (grub_uint8_t *raw, grub_size_t sz) for (i = 0; i < utf16len; i++) utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2]; } - ret = grub_malloc (utf16len * 3 + 1); + 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); diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c index 86fe8af65..cd2994895 100644 --- a/grub-core/fs/ufs.c +++ b/grub-core/fs/ufs.c @@ -50,6 +50,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); /* 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 @@ -214,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; @@ -285,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; @@ -312,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; @@ -391,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] == '/') @@ -514,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; } @@ -538,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; @@ -698,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) { @@ -719,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) @@ -757,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); @@ -783,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 1e466465b..fbadc8fa5 100644 --- a/grub-core/fs/xfs.c +++ b/grub-core/fs/xfs.c @@ -120,7 +120,9 @@ struct grub_xfs_inode 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]; @@ -154,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; }; @@ -168,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, @@ -250,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; @@ -273,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)) @@ -290,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) @@ -324,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); } @@ -337,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, @@ -405,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; @@ -543,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; } @@ -725,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; diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index 8d86cf9e5..534b7d224 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010 Free Software Foundation, Inc. + * 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 @@ -51,6 +51,8 @@ #include #include #include +#include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -75,14 +77,23 @@ static grub_dl_t my_mod; #endif #define P2PHASE(x, align) ((x) & ((align) - 1)) -#define DVA_OFFSET_TO_PHYS_SECTOR(offset) \ - ((offset + VDEV_LABEL_START_SIZE) >> SPA_MINBLOCKSHIFT) + +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 */ -#define ZAP_HASH_IDX(hash, n) (((n) == 0) ? 0 : ((hash) >> (64 - (n)))) +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 */ /* @@ -91,37 +102,60 @@ static grub_dl_t my_mod; */ #define ZAP_LEAF_ARRAY_BYTES (ZAP_LEAF_CHUNKSIZE - 3) -#define ZAP_LEAF_HASH_SHIFT(bs) (bs - 5) -#define ZAP_LEAF_HASH_NUMENTRIES(bs) (1 << ZAP_LEAF_HASH_SHIFT(bs)) -#define LEAF_HASH(bs, h) \ - ((ZAP_LEAF_HASH_NUMENTRIES(bs)-1) & \ - ((h) >> (64 - ZAP_LEAF_HASH_SHIFT(bs)-l->l_hdr.lh_prefix_len))) +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) */ -#define ZAP_LEAF_NUMCHUNKS(bs) \ - (((1<l_hash + ZAP_LEAF_HASH_NUMENTRIES(bs)))[idx] -#define ZAP_LEAF_ENTRY(l, bs, idx) (&ZAP_LEAF_CHUNK(l, bs, idx).l_entry) +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 */ -#ifndef NBBY -#define NBBY 8 -#endif extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t); @@ -129,16 +163,67 @@ 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 { - char *name; + 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; + + /* Valid only for non-leafs. */ + unsigned n_children; + struct grub_zfs_device_desc *children; + + /* Valid only for RAIDZ. */ + unsigned nparity; + unsigned ashift; + + /* 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 */ @@ -153,23 +238,90 @@ struct grub_zfs_data grub_uint64_t dnode_end; grub_zfs_endian_t dnode_endian; - uberblock_t current_uberblock; - grub_disk_t disk; - dnode_end_t mos; - dnode_end_t mdn; dnode_end_t dnode; + struct subvolume subvol; - grub_disk_addr_t vdev_phys_sector; + 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", NULL}, /* ZIO_COMPRESS_GZIP */ + {"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, @@ -214,6 +366,7 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { {fletcher_4, 1, 0, "fletcher4"}, {zio_checksum_SHA256, 1, 0, "SHA256"}, {NULL, 0, 0, "zilog2"}, + {zio_checksum_SHA256, 1, 0, "SHA256+MAC"}, }; /* @@ -224,7 +377,8 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { */ static grub_err_t zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, - grub_zfs_endian_t endian, char *buf, int size) + 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]; @@ -234,7 +388,7 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, { grub_dprintf ("zfs", "unknown checksum function %d\n", checksum); return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unknown checksum function %d", checksum); + "unknown checksum function %d", checksum); } if (ci->ci_eck) @@ -248,18 +402,16 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, else ci->ci_func (buf, size, endian, &actual_cksum); - if ((actual_cksum.zc_word[0] != zc.zc_word[0]) - || (actual_cksum.zc_word[1] != zc.zc_word[1]) - || (actual_cksum.zc_word[2] != zc.zc_word[2]) - || (actual_cksum.zc_word[3] != zc.zc_word[3])) + if (grub_memcmp (&actual_cksum, &zc, + checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20) != 0) { - grub_dprintf ("zfs", "checksum %d verification failed\n", checksum); - grub_dprintf ("zfs", "actual checksum %16llx %16llx %16llx %16llx\n", + 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 %16llx %16llx %16llx %16llx\n", + 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], @@ -284,14 +436,16 @@ 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, LITTLE_ENDIAN) == UBERBLOCK_MAGIC) - ub1_endian = LITTLE_ENDIAN; + if (grub_zfs_to_cpu64 (ub1->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC) + ub1_endian = GRUB_ZFS_LITTLE_ENDIAN; else - ub1_endian = BIG_ENDIAN; - if (grub_zfs_to_cpu64 (ub2->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC) - ub2_endian = LITTLE_ENDIAN; + 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 = BIG_ENDIAN; + 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)) @@ -319,24 +473,27 @@ vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2) * */ static grub_err_t -uberblock_verify (uberblock_phys_t * ub, int offset) +uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset) { uberblock_t *uber = &ub->ubp_uberblock; grub_err_t err; - grub_zfs_endian_t endian = UNKNOWN_ENDIAN; + grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN; zio_cksum_t zc; - if (grub_zfs_to_cpu64 (uber->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC - && grub_zfs_to_cpu64 (uber->ub_version, LITTLE_ENDIAN) > 0 - && grub_zfs_to_cpu64 (uber->ub_version, LITTLE_ENDIAN) <= SPA_VERSION) - endian = LITTLE_ENDIAN; + 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, BIG_ENDIAN) == UBERBLOCK_MAGIC - && grub_zfs_to_cpu64 (uber->ub_version, BIG_ENDIAN) > 0 - && grub_zfs_to_cpu64 (uber->ub_version, BIG_ENDIAN) <= SPA_VERSION) - endian = BIG_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 == UNKNOWN_ENDIAN) + if (endian == GRUB_ZFS_UNKNOWN_ENDIAN) return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic"); grub_memset (&zc, 0, sizeof (zc)); @@ -392,7 +549,7 @@ get_psize (blkptr_t * bp, grub_zfs_endian_t endian) } static grub_uint64_t -dva_get_offset (dva_t * dva, grub_zfs_endian_t endian) +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], @@ -401,6 +558,873 @@ dva_get_offset (dva_t * dva, grub_zfs_endian_t endian) 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) +{ + 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"); + } + + 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; + *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; + if (!grub_zfs_nvlist_lookup_uint64 (nvlist, "ashift", &par)) + { + grub_free (type); + return grub_error (GRUB_ERR_BAD_FS, "couldn't find raidz ashift"); + } + fill->ashift = 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); + + 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); + + 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); +} + +/* + * 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 : grub_disk_get_size (dev->disk) + - 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); + + ubbest = find_bestub (ub_array, desc.vdev_phys_sector); + 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)); + + err = check_pool_label (data, &desc, inserted); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } +#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, @@ -412,7 +1436,6 @@ 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; - grub_uint64_t offset, sector; unsigned i; grub_err_t err; zio_cksum_t zc; @@ -422,15 +1445,10 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, zio_gb = grub_malloc (SPA_GANGBLOCKSIZE); if (!zio_gb) return grub_errno; - grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" + grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); - offset = dva_get_offset (dva, endian); - sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); - grub_dprintf ("zfs", "offset=%llx\n", (unsigned long long) offset); - /* read in the gang block header */ - err = grub_disk_read (data->disk, sector, 0, SPA_GANGBLOCKSIZE, - (char *) zio_gb); + err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE); if (err) { grub_free (zio_gb); @@ -483,20 +1501,13 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, /* pick a good dva from the block pointer */ for (i = 0; i < SPA_DVAS_PER_BP; i++) { - grub_uint64_t offset, sector; - 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 - { - /* read in a data block */ - offset = dva_get_offset (&bp->blk_dva[i], endian); - sector = DVA_OFFSET_TO_PHYS_SECTOR (offset); - err = grub_disk_read (data->disk, sector, 0, psize, buf); - } + err = read_dva (&bp->blk_dva[i], endian, data, buf, psize); if (!err) return GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE; @@ -514,11 +1525,11 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, * and put the uncompressed data in buf. */ static grub_err_t -zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf, +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; + unsigned int comp, encrypted; char *compbuf = NULL; grub_err_t err; zio_cksum_t zc = bp->blk_cksum; @@ -527,7 +1538,8 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf, *buf = NULL; checksum = (grub_zfs_to_cpu64((bp)->blk_prop, endian) >> 40) & 0xff; - comp = (grub_zfs_to_cpu64((bp)->blk_prop, endian)>>32) & 0x7; + 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)); @@ -546,7 +1558,8 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf, if (comp != ZIO_COMPRESS_OFF) { - compbuf = grub_malloc (psize); + /* It's not really necessary to align to 16, just for safety. */ + compbuf = grub_malloc (ALIGN_UP (psize, 16)); if (! compbuf) return grub_errno; } @@ -561,8 +1574,10 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf, *buf = NULL; return err; } + grub_memset (compbuf, 0, ALIGN_UP (psize, 16) - psize); - err = zio_checksum_verify (zc, checksum, endian, compbuf, psize); + err = zio_checksum_verify (zc, checksum, endian, + compbuf, psize); if (err) { grub_dprintf ("zfs", "incorrect checksum\n"); @@ -571,6 +1586,51 @@ zio_read (blkptr_t * bp, grub_zfs_endian_t endian, void **buf, 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); @@ -602,7 +1662,8 @@ 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 idx, level; + 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; @@ -670,7 +1731,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, */ static grub_err_t mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, - int objsize, char *name, grub_uint64_t * value) + int objsize, const char *name, grub_uint64_t * value, + int case_insensitive) { int i, chunks; mzap_ent_phys_t *mzap_ent = zapobj->mz_chunk; @@ -678,7 +1740,8 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, chunks = objsize / MZAP_ENT_LEN - 1; for (i = 0; i < chunks; i++) { - if (grub_strcmp (mzap_ent[i].mze_name, name) == 0) + 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; @@ -711,7 +1774,8 @@ mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, } static grub_uint64_t -zap_hash (grub_uint64_t salt, const char *name) +zap_hash (grub_uint64_t salt, const char *name, + int case_insensitive) { static grub_uint64_t table[256]; const grub_uint8_t *cp; @@ -729,8 +1793,12 @@ zap_hash (grub_uint64_t salt, const char *name) } } - for (cp = (const grub_uint8_t *) name; (c = *cp) != '\0'; cp++) - crc = (crc >> 8) ^ table[(crc ^ c) & 0xFF]; + 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 @@ -748,22 +1816,47 @@ zap_hash (grub_uint64_t salt, const char *name) * 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, int array_len, const char *buf) + int blksft, int chunk, int array_len, const char *buf, + int case_insensitive) { int bseen = 0; while (bseen < array_len) { - struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk).l_array; + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array; int toread = MIN (array_len - bseen, ZAP_LEAF_ARRAY_BYTES); if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) return (0); - if (grub_memcmp (la->la_array, buf + bseen, toread) != 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; @@ -780,7 +1873,7 @@ zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, while (bseen < array_len) { - struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk).l_array; + struct zap_leaf_array *la = &ZAP_LEAF_CHUNK (l, blksft, chunk)->l_array; int toread = MIN (array_len - bseen, ZAP_LEAF_ARRAY_BYTES); if (chunk >= ZAP_LEAF_NUMCHUNKS (blksft)) @@ -804,7 +1897,8 @@ zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, 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) + const char *name, grub_uint64_t * value, + int case_insensitive) { grub_uint16_t chunk; struct zap_leaf_entry *le; @@ -815,8 +1909,8 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, 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)], endian); - chunk != CHAIN_END; chunk = le->le_next) + 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)) @@ -836,15 +1930,16 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, 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)) + name, case_insensitive)) { struct zap_leaf_array *la; - if (le->le_int_size != 8 || le->le_value_length != 1) + 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; + la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk)->l_array; *value = grub_be_to_cpu64 (la->la_array64); @@ -858,14 +1953,11 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, /* Verify if this is a fat zap header block */ static grub_err_t -zap_verify (zap_phys_t *zap) +zap_verify (zap_phys_t *zap, grub_zfs_endian_t endian) { - if (zap->zap_magic != (grub_uint64_t) ZAP_MAGIC) + 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_flags != 0) - return grub_error (GRUB_ERR_BAD_FS, "bad ZAP flags"); - if (zap->zap_salt == 0) return grub_error (GRUB_ERR_BAD_FS, "bad ZAP salt"); @@ -879,7 +1971,8 @@ zap_verify (zap_phys_t *zap) /* XXX */ static grub_err_t fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, - char *name, grub_uint64_t * value, struct grub_zfs_data *data) + const char *name, grub_uint64_t * value, + struct grub_zfs_data *data, int case_insensitive) { void *l; grub_uint64_t hash, idx, blkid; @@ -888,18 +1981,18 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, grub_err_t err; grub_zfs_endian_t leafendian; - err = zap_verify (zap); + err = zap_verify (zap, zap_dnode->endian); if (err) return err; - hash = zap_hash (zap->zap_salt, name); + 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_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))]; + 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)) @@ -908,7 +2001,8 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, if (err) return err; - err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value); + err = zap_leaf_lookup (l, leafendian, blksft, hash, name, value, + case_insensitive); grub_free (l); return err; } @@ -916,20 +2010,24 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, /* XXX */ static int fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, - int NESTED_FUNC_ATTR (*hook) (const char *name, - grub_uint64_t val), - struct grub_zfs_data *data) + 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, blkid; + 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)) + if (zap_verify (zap, zap_dnode->endian)) return 0; /* get block id from index */ @@ -945,9 +2043,17 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, grub_error (GRUB_ERR_BAD_FS, "ZAP leaf is too small"); return 0; } - for (idx = 0; idx < zap->zap_ptrtbl.zt_numblks; idx++) + for (idx = 0; idx < (1ULL << zap->zap_ptrtbl.zt_shift); idx++) { - blkid = ((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))]; + 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; @@ -972,49 +2078,64 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, for (chunk = 0; chunk < ZAP_LEAF_NUMCHUNKS (blksft); chunk++) { char *buf; - struct zap_leaf_array *la; struct zap_leaf_entry *le; - grub_uint64_t val; + 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) - + 1); - if (zap_leaf_array_get (l, endian, blksft, le->le_name_chunk, - le->le_name_length, buf)) + 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] = 0; + buf[le->le_name_length * name_elem_length] = 0; - if (le->le_int_size != 8 - || grub_zfs_to_cpu16 (le->le_value_length, endian) != 1) - continue; + 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; + } - /* get the uint64_t property value */ - la = &ZAP_LEAF_CHUNK (l, blksft, le->le_value_chunk).l_array; - val = grub_be_to_cpu64 (la->la_array64); - if (hook (buf, val)) - return 1; + 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, char *name, grub_uint64_t * val, - struct grub_zfs_data *data) +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; @@ -1037,7 +2158,8 @@ zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val, if (block_type == ZBT_MICRO) { grub_dprintf ("zfs", "micro zap\n"); - err = (mzap_lookup (zapbuf, endian, size, name, val)); + err = mzap_lookup (zapbuf, endian, size, name, val, + case_insensitive); grub_dprintf ("zfs", "returned %d\n", err); grub_free (zapbuf); return err; @@ -1046,7 +2168,8 @@ zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val, { grub_dprintf ("zfs", "fat zap\n"); /* this is a fat zap */ - err = (fzap_lookup (zap_dnode, zapbuf, name, val, data)); + err = fzap_lookup (zap_dnode, zapbuf, name, val, data, + case_insensitive); grub_dprintf ("zfs", "returned %d\n", err); grub_free (zapbuf); return err; @@ -1056,9 +2179,10 @@ zap_lookup (dnode_end_t * zap_dnode, char *name, grub_uint64_t * val, } static int -zap_iterate (dnode_end_t * zap_dnode, - int NESTED_FUNC_ATTR (*hook) (const char *name, grub_uint64_t val), - struct grub_zfs_data *data) +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; @@ -1067,6 +2191,23 @@ zap_iterate (dnode_end_t * zap_dnode, 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); @@ -1074,7 +2215,7 @@ zap_iterate (dnode_end_t * zap_dnode, return 0; block_type = grub_zfs_to_cpu64 (*((grub_uint64_t *) zapbuf), endian); - grub_dprintf ("zfs", "zap read\n"); + grub_dprintf ("zfs", "zap iterate\n"); if (block_type == ZBT_MICRO) { @@ -1087,7 +2228,48 @@ zap_iterate (dnode_end_t * zap_dnode, { grub_dprintf ("zfs", "fat zap\n"); /* this is a fat zap */ - ret = fzap_iterate (zap_dnode, zapbuf, hook, data); + 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; } @@ -1171,7 +2353,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, * */ static grub_err_t -dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, +dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, struct grub_zfs_data *data) { grub_uint64_t objnum, version; @@ -1191,7 +2373,7 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, dn_new->next = 0; dnode_path = root = dn_new; - err = dnode_get (mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, &(dnode_path->dn), data); if (err) { @@ -1199,26 +2381,37 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, return err; } - err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, data); - 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), ZFS_ROOT_OBJ, &objnum, data); + err = zap_lookup (&(dnode_path->dn), ZPL_VERSION_STR, &version, + data, 0); if (err) { grub_free (dn_new); return err; } - err = dnode_get (mdn, objnum, 0, &(dnode_path->dn), data); + 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); @@ -1272,7 +2465,8 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, grub_free (path_buf); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); } - err = zap_lookup (&(dnode_path->dn), cname, &objnum, data); + err = zap_lookup (&(dnode_path->dn), cname, &objnum, + data, subvol->case_insensitive); if (err) break; @@ -1286,27 +2480,59 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, dnode_path = dn_new; objnum = ZFS_DIRENT_OBJ (objnum); - err = dnode_get (mdn, objnum, 0, &(dnode_path->dn), data); + err = dnode_get (&subvol->mdn, objnum, 0, &(dnode_path->dn), data); if (err) break; *path = ch; -#if 0 - if (((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa && 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; - path = path_buf - = grub_malloc (sizeof (dnode_path->dn.dn.dn_bonus) - - sizeof (znode_phys_t) + grub_strlen (oldpath) + 1); + 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 = MIN (sym_sz - block * blksz, 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, - (char *) DN_BONUS(&dnode_path->dn.dn) + sizeof (znode_phys_t), - sizeof (dnode_path->dn.dn.dn_bonus) - sizeof (znode_phys_t)); - path [sizeof (dnode_path->dn.dn.dn_bonus) - sizeof (znode_phys_t)] = 0; + 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); @@ -1324,7 +2550,68 @@ dnode_get_path (dnode_end_t * mdn, const char *path_in, dnode_end_t * dn, grub_free (dn_new); } } -#endif + 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) @@ -1417,7 +2704,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, grub_dprintf ("zfs", "alive\n"); - err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data); + err = zap_lookup (mdn, DMU_POOL_ROOT_DATASET, &objnum, data, 0); if (err) return err; @@ -1452,7 +2739,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, if (err) return err; - err = zap_lookup (mdn, cname, &objnum, data); + err = zap_lookup (mdn, cname, &objnum, data, 0); if (err) return err; @@ -1493,14 +2780,65 @@ make_mdn (dnode_end_t * mdn, struct grub_zfs_data *data) } static grub_err_t -dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, - grub_uint64_t *mdnobj, dnode_end_t * dn, int *isfs, +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) @@ -1553,29 +2891,80 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, 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", mdn->endian); + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); - err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data); + 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", mdn->endian); + 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 (&mdn->dn))->ds_snapnames_zapobj, mdn->endian); + 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, mdn, data); + DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data); if (!err) - err = zap_lookup (mdn, snapname, &headobj, data); + err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0); if (!err) - err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, mdn, data); + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, + &subvol->mdn, data); if (err) { grub_free (fsname); @@ -1584,12 +2973,11 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, } } - if (mdnobj) - *mdnobj = headobj; + subvol->obj = headobj; - make_mdn (mdn, data); + make_mdn (&subvol->mdn, data); - grub_dprintf ("zfs", "endian = %d\n", mdn->endian); + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); if (*isfs) { @@ -1597,7 +2985,7 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, grub_free (snapname); return GRUB_ERR_NONE; } - err = dnode_get_path (mdn, filename, dn, data); + err = dnode_get_path (subvol, filename, dn, data); grub_free (fsname); grub_free (snapname); return err; @@ -1625,11 +3013,12 @@ dnode_get_fullpath (const char *fullpath, dnode_end_t * mdn, */ static int -nvlist_find_value (char *nvlist, char *name, int valtype, char **val, +nvlist_find_value (const char *nvlist, const char *name, + int valtype, char **val, grub_size_t *size_out, grub_size_t *nelm_out) { int name_len, type, encode_size; - char *nvpair, *nvp_name; + const char *nvpair, *nvp_name; /* Verify if the 1st and 2nd byte in the nvlist are valid. */ /* NOTE: independently of what endianness header announces all @@ -1648,22 +3037,22 @@ nvlist_find_value (char *nvlist, char *name, int valtype, char **val, * 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_uint32_t *) nvlist))) + while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist)))) { int nelm; nvpair = nvlist + 4 * 2; /* skip the encode/decode size */ - name_len = grub_be_to_cpu32 (*(grub_uint32_t *) nvpair); + name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); nvpair += 4; nvp_name = nvpair; nvpair = nvpair + ((name_len + 3) & ~3); /* align */ - type = grub_be_to_cpu32 (*(grub_uint32_t *) nvpair); + type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); nvpair += 4; - nelm = grub_be_to_cpu32 (*(grub_uint32_t *) nvpair); + nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); if (nelm < 1) return grub_error (GRUB_ERR_BAD_FS, "empty nvpair"); @@ -1671,7 +3060,7 @@ nvlist_find_value (char *nvlist, char *name, int valtype, char **val, if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype) { - *val = nvpair; + *val = (char *) nvpair; *size_out = encode_size; if (nelm_out) *nelm_out = nelm; @@ -1684,7 +3073,8 @@ nvlist_find_value (char *nvlist, char *name, int valtype, char **val, } int -grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name, grub_uint64_t * out) +grub_zfs_nvlist_lookup_uint64 (const char *nvlist, const char *name, + grub_uint64_t * out) { char *nvpair; grub_size_t size; @@ -1699,12 +3089,12 @@ grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name, grub_uint64_t * out) return 0; } - *out = grub_be_to_cpu64 (*(grub_uint64_t *) nvpair); + *out = grub_be_to_cpu64 (grub_get_unaligned64 (nvpair)); return 1; } char * -grub_zfs_nvlist_lookup_string (char *nvlist, char *name) +grub_zfs_nvlist_lookup_string (const char *nvlist, const char *name) { char *nvpair; char *ret; @@ -1720,7 +3110,7 @@ grub_zfs_nvlist_lookup_string (char *nvlist, char *name) grub_error (GRUB_ERR_BAD_FS, "invalid string"); return 0; } - slen = grub_be_to_cpu32 (*(grub_uint32_t *) nvpair); + slen = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair)); if (slen > size - 4) slen = size - 4; ret = grub_malloc (slen + 1); @@ -1732,7 +3122,7 @@ grub_zfs_nvlist_lookup_string (char *nvlist, char *name) } char * -grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name) +grub_zfs_nvlist_lookup_nvlist (const char *nvlist, const char *name) { char *nvpair; char *ret; @@ -1753,21 +3143,37 @@ grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name) } int -grub_zfs_nvlist_lookup_nvlist_array_get_nelm (char *nvlist, char *name) +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, &nvpair, + 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 (char *nvlist, char *name, +grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, grub_size_t index) { char *nvpair, *nvpairptr; @@ -1776,8 +3182,9 @@ grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name, grub_size_t size; unsigned i; grub_size_t nelm; + int elemsize = 0; - found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST, &nvpair, + found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, &size, &nelm); if (!found) return 0; @@ -1791,164 +3198,66 @@ grub_zfs_nvlist_lookup_nvlist_array (char *nvlist, char *name, for (i = 0; i < index; i++) { - grub_uint32_t encode_size; + int r; + r = get_nvlist_size (nvpairptr, nvpair + size); - /* skip the header, nvl_version, and nvl_nvflag */ - nvpairptr = nvpairptr + 4 * 2; - - while (nvpairptr < nvpair + size - && (encode_size = grub_be_to_cpu32 (*(grub_uint32_t *) nvpairptr))) - nvlist += encode_size; /* goto the next nvpair */ - - nvlist = nvlist + 4 * 2; /* skip the ending 2 zeros - 8 bytes */ + if (r < 0) + { + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); + return NULL; + } + nvpairptr += r; } - if (nvpairptr >= nvpair + size - || nvpairptr + grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2)) - >= nvpair + size) + elemsize = get_nvlist_size (nvpairptr, nvpair + size); + + if (elemsize < 0) { grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist array"); return 0; } - ret = grub_zalloc (grub_be_to_cpu32 (*(grub_uint32_t *) (nvpairptr + 4 * 2)) - + 3 * sizeof (grub_uint32_t)); + 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, size); + grub_memcpy (ret + sizeof (grub_uint32_t), nvpairptr, elemsize); return ret; } -static grub_err_t -zfs_fetch_nvlist (struct grub_zfs_data * data, char **nvlist) +static void +unmount_device (struct grub_zfs_device_desc *desc) { - grub_err_t err; - - *nvlist = grub_malloc (VDEV_PHYS_SIZE); - /* Read in the vdev name-value pair list (112K). */ - err = grub_disk_read (data->disk, data->vdev_phys_sector, 0, - VDEV_PHYS_SIZE, *nvlist); - if (err) + unsigned i; + switch (desc->type) { - grub_free (*nvlist); - *nvlist = 0; - return err; + 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; } - return GRUB_ERR_NONE; -} - -/* - * Check the disk label information and retrieve needed vdev name-value pairs. - * - */ -static grub_err_t -check_pool_label (struct grub_zfs_data *data) -{ - grub_uint64_t pool_state, txg = 0; - char *nvlist; -#if 0 - char *nv; -#endif - grub_uint64_t diskguid; - grub_uint64_t version; - int found; - grub_err_t err; - - err = zfs_fetch_nvlist (data, &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"); -#if 0 - if (nvlist_lookup_value (nvlist, ZPOOL_CONFIG_VDEV_TREE, &nv, - DATA_TYPE_NVLIST, NULL)) - { - grub_free (vdev); - return (GRUB_ERR_BAD_FS); - } - grub_dprintf ("zfs", "check 10 passed\n"); -#endif - - found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID, &diskguid); - if (! found) - { - grub_free (nvlist); - if (! grub_errno) - grub_error (GRUB_ERR_BAD_FS, ZPOOL_CONFIG_GUID " not found"); - return grub_errno; - } - grub_dprintf ("zfs", "check 11 passed\n"); - - grub_free (nvlist); - - return GRUB_ERR_NONE; } 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); } @@ -1961,13 +3270,12 @@ static struct grub_zfs_data * zfs_mount (grub_device_t dev) { struct grub_zfs_data *data = 0; - int label = 0; - uberblock_phys_t *ub_array, *ubbest = NULL; - vdev_boot_header_t *bh; + grub_err_t err; void *osp = 0; grub_size_t ospsize; - grub_err_t err; - int vdevnum; + grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; + uberblock_t *ub; + int inserted; if (! dev->disk) { @@ -1975,119 +3283,57 @@ zfs_mount (grub_device_t dev) return 0; } - data = grub_malloc (sizeof (*data)); + data = grub_zalloc (sizeof (*data)); if (!data) return 0; - grub_memset (data, 0, sizeof (*data)); #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->disk = dev->disk; - - ub_array = grub_malloc (VDEV_UBERBLOCK_RING); - if (!ub_array) + 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 0; + return NULL; } - bh = grub_malloc (VDEV_BOOT_HEADER_SIZE); - if (!bh) + 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); - grub_free (ub_array); - return 0; + return NULL; } - vdevnum = VDEV_LABELS; - - /* 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++) + if (ospsize < OBJSET_PHYS_SIZE_V14) { - grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN; - grub_dprintf ("zfs", "label %d\n", label); - - data->vdev_phys_sector - = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) - + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) - + (label < VDEV_LABELS / 2 ? 0 : grub_disk_get_size (dev->disk) - - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); - - /* Read in the uberblock ring (128K). */ - err = grub_disk_read (data->disk, data->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); - - ubbest = find_bestub (ub_array, data->vdev_phys_sector); - if (!ubbest) - { - grub_dprintf ("zfs", "No uberblock found\n"); - grub_errno = GRUB_ERR_NONE; - continue; - } - ub_endian = (grub_zfs_to_cpu64 (ubbest->ubp_uberblock.ub_magic, - LITTLE_ENDIAN) == UBERBLOCK_MAGIC - ? LITTLE_ENDIAN : BIG_ENDIAN); - err = zio_read (&ubbest->ubp_uberblock.ub_rootbp, - ub_endian, - &osp, &ospsize, data); - if (err) - { - grub_dprintf ("zfs", "couldn't zio_read\n"); - grub_errno = GRUB_ERR_NONE; - continue; - } - - if (ospsize < OBJSET_PHYS_SIZE_V14) - { - grub_dprintf ("zfs", "osp too small\n"); - grub_free (osp); - continue; - } - grub_dprintf ("zfs", "ubbest %p\n", ubbest); - - err = check_pool_label (data); - if (err) - { - grub_errno = GRUB_ERR_NONE; - continue; - } -#if 0 - if (find_best_root && - vdev_uberblock_compare (&ubbest->ubp_uberblock, - &(current_uberblock)) <= 0) - continue; -#endif - /* 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 (ubbest->ubp_uberblock.ub_rootbp.blk_prop, ub_endian) >> 63) & 1; - grub_memmove (&(data->current_uberblock), - &ubbest->ubp_uberblock, sizeof (uberblock_t)); - grub_free (ub_array); - grub_free (bh); + grub_error (GRUB_ERR_BAD_FS, "OSP too small"); grub_free (osp); - return data; + zfs_unmount (data); + return NULL; } - grub_error (GRUB_ERR_BAD_FS, "couldn't find a valid label"); - zfs_unmount (data); - grub_free (ub_array); - grub_free (bh); + + /* 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); - return 0; + data->mounted = 1; + + return data; } grub_err_t @@ -2099,7 +3345,7 @@ grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist) zfs = zfs_mount (dev); if (!zfs) return grub_errno; - err = zfs_fetch_nvlist (zfs, nvlist); + err = zfs_fetch_nvlist (zfs->device_original, nvlist); zfs_unmount (zfs); return err; } @@ -2115,7 +3361,7 @@ zfs_label (grub_device_t device, char **label) if (! data) return grub_errno; - err = zfs_fetch_nvlist (data, &nvlist); + err = zfs_fetch_nvlist (data->device_original, &nvlist); if (err) { zfs_unmount (data); @@ -2131,11 +3377,7 @@ zfs_label (grub_device_t device, char **label) static grub_err_t zfs_uuid (grub_device_t device, char **uuid) { - char *nvlist; - int found; struct grub_zfs_data *data; - grub_uint64_t guid; - grub_err_t err; *uuid = 0; @@ -2143,24 +3385,36 @@ zfs_uuid (grub_device_t device, char **uuid) if (! data) return grub_errno; - err = zfs_fetch_nvlist (data, &nvlist); - if (err) - { - zfs_unmount (data); - return err; - } - - found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid); - if (! found) - return grub_errno; - grub_free (nvlist); - *uuid = grub_xasprintf ("%016llx", (long long unsigned) guid); + *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. @@ -2176,7 +3430,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) if (! data) return grub_errno; - err = dnode_get_fullpath (fsfilename, &(data->mdn), 0, + err = dnode_get_fullpath (fsfilename, &(data->subvol), &(data->dnode), &isfs, data); if (err) { @@ -2227,12 +3481,14 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) } hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp)); - file->size = *(grub_uint64_t *) ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET); + file->size = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_SIZE_OFFSET), data->dnode.endian); } - else + 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; @@ -2248,7 +3504,7 @@ 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; - int blksz, movesize; + grub_size_t blksz, movesize; grub_size_t length; grub_size_t read; grub_err_t err; @@ -2302,7 +3558,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) data->file_start = blkid * blksz; data->file_end = data->file_start + blksz; - movesize = MIN (length, data->file_end - (int) file->offset - read); + movesize = MIN (length, data->file_end - file->offset - read); grub_memmove (buf, data->file_buf + file->offset + read - data->file_start, movesize); @@ -2338,8 +3594,9 @@ grub_zfs_getmdnobj (grub_device_t dev, const char *fsfilename, if (! data) return grub_errno; - err = dnode_get_fullpath (fsfilename, &(data->mdn), mdnobj, + err = dnode_get_fullpath (fsfilename, &(data->subvol), &(data->dnode), &isfs, data); + *mdnobj = data->subvol.obj; zfs_unmount (data); return err; } @@ -2377,7 +3634,7 @@ fill_fs_info (struct grub_dirhook_info *info, return; } - err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data); + err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0); if (err) { grub_dprintf ("zfs", "failed here\n"); @@ -2391,8 +3648,39 @@ fill_fs_info (struct grub_dirhook_info *info, return; } - info->mtimeset = 1; - info->mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], dn.endian); + 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; } @@ -2415,11 +3703,49 @@ grub_zfs_dir (grub_device_t device, const char *path, dnode_end_t dn; grub_memset (&info, 0, sizeof (info)); - dnode_get (&(data->mdn), val, 0, &dn, data); - 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", + 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); } @@ -2464,7 +3790,7 @@ grub_zfs_dir (grub_device_t device, const char *path, data = zfs_mount (device); if (! data) return grub_errno; - err = dnode_get_fullpath (path, &(data->mdn), 0, &(data->dnode), &isfs, data); + err = dnode_get_fullpath (path, &(data->subvol), &(data->dnode), &isfs, data); if (err) { zfs_unmount (data); @@ -2490,7 +3816,7 @@ grub_zfs_dir (grub_device_t device, const char *path, return err; } - zap_iterate (&dn, iterate_zap_fs, data); + zap_iterate_u64 (&dn, iterate_zap_fs, data); err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data); if (err) @@ -2509,7 +3835,7 @@ grub_zfs_dir (grub_device_t device, const char *path, return err; } - zap_iterate (&dn, iterate_zap_snap, data); + zap_iterate_u64 (&dn, iterate_zap_snap, data); } else { @@ -2518,12 +3844,41 @@ grub_zfs_dir (grub_device_t device, const char *path, zfs_unmount (data); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); } - zap_iterate (&(data->dnode), iterate_zap, data); + 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, @@ -2532,12 +3887,17 @@ static struct grub_fs grub_zfs_fs = { .close = grub_zfs_close, .label = zfs_label, .uuid = zfs_uuid, - .mtime = 0, + .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; 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 index 1968ed554..94f2a1ac8 100644 --- a/grub-core/fs/zfs/zfsinfo.c +++ b/grub-core/fs/zfs/zfsinfo.c @@ -25,6 +25,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -44,32 +45,32 @@ print_state (char *nvlist, int tab) int isok = 1; print_tabs (tab); - grub_printf ("State: "); + grub_xputs (_("State: ")); if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_REMOVED, &ival)) { - grub_printf ("removed "); + grub_xputs (_("removed ")); isok = 0; } if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival)) { - grub_printf ("faulted "); + grub_xputs (_("faulted ")); isok = 0; } if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_OFFLINE, &ival)) { - grub_printf ("offline "); + grub_xputs (_("offline ")); isok = 0; } if (grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_FAULTED, &ival)) - grub_printf ("degraded "); + grub_xputs (_("degraded ")); if (isok) - grub_printf ("online"); - grub_printf ("\n"); + grub_xputs (_("online")); + grub_xputs ("\n"); return GRUB_ERR_NONE; } @@ -84,7 +85,7 @@ print_vdev_info (char *nvlist, int tab) if (!type) { print_tabs (tab); - grub_printf ("Incorrect VDEV: no type available\n"); + grub_puts_ (N_("Incorrect VDEV: no type available")); return grub_errno; } @@ -95,7 +96,7 @@ print_vdev_info (char *nvlist, int tab) char *devid = 0; print_tabs (tab); - grub_printf ("Leaf VDEV\n"); + grub_puts_ (N_("Leaf VDEV")); print_state (nvlist, tab); @@ -103,23 +104,23 @@ print_vdev_info (char *nvlist, int tab) grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_PHYS_PATH); print_tabs (tab); if (!bootpath) - grub_printf ("Bootpath: unavailable\n"); + grub_puts_ (N_("Bootpath: unavailable\n")); else - grub_printf ("Bootpath: %s\n", bootpath); + grub_printf_ (N_("Bootpath: %s\n"), bootpath); path = grub_zfs_nvlist_lookup_string (nvlist, "path"); print_tabs (tab); if (!path) - grub_printf ("Path: unavailable\n"); + grub_puts_ (N_("Path: unavailable")); else - grub_printf ("Path: %s\n", path); + grub_printf_ (N_("Path: %s\n"), path); devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID); print_tabs (tab); if (!devid) - grub_printf ("Devid: unavailable\n"); + grub_puts_ (N_("Devid: unavailable")); else - grub_printf ("Devid: %s\n", devid); + grub_printf_ (N_("Devid: %s\n"), devid); grub_free (bootpath); grub_free (devid); grub_free (path); @@ -136,12 +137,11 @@ print_vdev_info (char *nvlist, int tab) print_tabs (tab); if (nelm <= 0) { - grub_printf ("Incorrect mirror VDEV\n"); + grub_puts_ (N_("Incorrect mirror VDEV")); return GRUB_ERR_NONE; } - grub_printf ("Mirror VDEV with %d children\n", nelm); + grub_printf_ (N_("Mirror VDEV with %d children\n"), nelm); print_state (nvlist, tab); - for (i = 0; i < nelm; i++) { char *child; @@ -152,19 +152,20 @@ print_vdev_info (char *nvlist, int tab) print_tabs (tab); if (!child) { - grub_printf ("Mirror VDEV element %d isn't correct\n", i); + grub_printf_ (N_("Mirror VDEV element %d isn't correct\n"), i); continue; } - grub_printf ("Mirror VDEV element %d:\n", i); + 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 ("Unknown VDEV type: %s\n", type); + grub_printf_ (N_("Unknown VDEV type: %s\n"), type); return GRUB_ERR_NONE; } @@ -221,15 +222,15 @@ get_bootpath (char *nvlist, char **bootpath, char **devid) return GRUB_ERR_NONE; } -static char *poolstates[] = { - [POOL_STATE_ACTIVE] = "active", - [POOL_STATE_EXPORTED] = "exported", - [POOL_STATE_DESTROYED] = "destroyed", - [POOL_STATE_SPARE] = "reserved for hot spare", - [POOL_STATE_L2CACHE] = "level 2 ARC device", - [POOL_STATE_UNINITIALIZED] = "uninitialized", - [POOL_STATE_UNAVAIL] = "unavailable", - [POOL_STATE_POTENTIALLY_ACTIVE] = "potentially active" +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 @@ -274,30 +275,30 @@ grub_cmd_zfsinfo (grub_command_t cmd __attribute__ ((unused)), int argc, poolname = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_POOL_NAME); if (!poolname) - grub_printf ("Pool name: unavailable\n"); + grub_puts_ (N_("Pool name: unavailable")); else - grub_printf ("Pool name: %s\n", poolname); + grub_printf_ (N_("Pool name: %s\n"), poolname); found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_GUID, &guid); if (!found) - grub_printf ("Pool GUID: unavailable\n"); + grub_puts_ (N_("Pool GUID: unavailable")); else - grub_printf ("Pool GUID: %016llx\n", (long long unsigned) guid); + 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_printf ("Unable to retrieve pool state\n"); + grub_puts_ (N_("Unable to retrieve pool state")); else if (pool_state >= ARRAY_SIZE (poolstates)) - grub_printf ("Unrecognized pool state\n"); + grub_puts_ (N_("Unrecognized pool state")); else - grub_printf ("Pool state: %s\n", poolstates[pool_state]); + grub_puts_ (poolstates[pool_state]); nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE); if (!nv) - grub_printf ("No vdev tree available\n"); + grub_puts_ (N_("No vdev tree available")); else print_vdev_info (nv, 1); @@ -395,11 +396,11 @@ static grub_command_t cmd_info, cmd_bootfs; GRUB_MOD_INIT (zfsinfo) { cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo, - "zfsinfo DEVICE", - "Print ZFS info about DEVICE."); + N_("DEVICE"), + N_("Print ZFS info about DEVICE.")); cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs, - "zfs-bootfs FILESYSTEM [VARIABLE]", - "Print ZFS-BOOTFSOBJ or set it to VARIABLE"); + N_("FILESYSTEM [VARIABLE]"), + N_("Print ZFS-BOOTFSOBJ or set it to VARIABLE")); } GRUB_MOD_FINI (zfsinfo) 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/gettext/gettext.c b/grub-core/gettext/gettext.c index cca8b901f..682754421 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c @@ -294,7 +294,10 @@ grub_mofile_open_lang (const char *locale_dir, const char *locale) static void grub_gettext_init_ext (const char *locale) { - char *locale_dir; + const char *locale_dir; + + if (!locale) + return; locale_dir = grub_env_get ("locale_dir"); if (locale_dir == NULL) @@ -370,8 +373,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/gui_label.c b/grub-core/gfxmenu/gui_label.c index a7dc95afc..688bea077 100644 --- a/grub-core/gfxmenu/gui_label.c +++ b/grub-core/gfxmenu/gui_label.c @@ -94,15 +94,17 @@ 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, diff --git a/grub-core/gfxmenu/gui_list.c b/grub-core/gfxmenu/gui_list.c index 2ff6e0f97..1982d9a40 100644 --- a/grub-core/gfxmenu/gui_list.c +++ b/grub-core/gfxmenu/gui_list.c @@ -245,6 +245,7 @@ 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) { @@ -256,8 +257,8 @@ draw_menu (list_impl_t self, int num_shown_items) 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, diff --git a/grub-core/gfxmenu/view.c b/grub-core/gfxmenu/view.c index 836a9884d..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); @@ -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; diff --git a/grub-core/gfxmenu/widget-box.c b/grub-core/gfxmenu/widget-box.c index 41ca7f536..8c9131a24 100644 --- a/grub-core/gfxmenu/widget-box.c +++ b/grub-core/gfxmenu/widget-box.c @@ -188,25 +188,65 @@ get_border_width (grub_gfxmenu_box_t self) 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 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/regcomp.c b/grub-core/gnulib/regcomp.c index 86ca02b0c..23f3afa01 100644 --- a/grub-core/gnulib/regcomp.c +++ b/grub-core/gnulib/regcomp.c @@ -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)); diff --git a/grub-core/hook/datehook.c b/grub-core/hook/datehook.c index f64fac074..ac75908ef 100644 --- a/grub-core/hook/datehook.c +++ b/grub-core/hook/datehook.c @@ -26,7 +26,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); -static char *grub_datetime_names[] = +static const char *grub_datetime_names[] = { "YEAR", "MONTH", @@ -37,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))) { @@ -50,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; diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index adb38af56..0d01e62f9 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -35,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; @@ -70,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; @@ -104,83 +106,87 @@ 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_bufio_t bufio = file->data; - grub_uint64_t pos; - 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; + } + if (! len) + return res; + + /* Need to read some more. */ + bufio->buffer_at = grub_divmod64 (file->offset + res + len, bufio->block_size, + 0) * bufio->block_size; + + /* Now read between file->offset + res and bufio->buffer_at. */ + if (file->offset + res < bufio->buffer_at) + { + grub_size_t read_now; + grub_ssize_t really_read; + read_now = bufio->buffer_at - (file->offset + res); + grub_file_seek (bufio->file, file->offset + res); + really_read = grub_file_read (bufio->file, buf, read_now); + if (grub_errno) + 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; + } + } + + /* Read into buffer. */ + grub_file_seek (bufio->file, bufio->buffer_at); + bufio->buffer_len = grub_file_read (bufio->file, bufio->buffer, + bufio->block_size); + if (grub_errno) + return -1; + if (file->size == GRUB_FILE_SIZE_UNKNOWN) + file->size = bufio->file->size; + + if (len < bufio->buffer_len) + { + grub_memcpy (buf, &bufio->buffer[0], len); + res += len; } else { - bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size, - &pos); - bufio->file->offset *= bufio->block_size; + grub_memcpy (buf, &bufio->buffer[0], bufio->buffer_len); + res += bufio->buffer_len; } - 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) - return -1; - - grub_memcpy (buf, &bufio->buffer[pos], len); - return res; } diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 5d3e5332e..7380221aa 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -1179,12 +1179,9 @@ grub_gzio_open (grub_file_t io) 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; diff --git a/grub-core/io/lzopio.c b/grub-core/io/lzopio.c new file mode 100644 index 000000000..bd6f8e738 --- /dev/null +++ b/grub-core/io/lzopio.c @@ -0,0 +1,564 @@ +/* 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->ccheck_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) + { + long to_copy; + + /* Block not decompressed yet. */ + if (!lzopio->block.udata && uncompress_block (lzopio) < 0) + goto CORRUPTED; + + /* Copy requested data into buffer. */ + to_copy = grub_min (lzopio->block.usize - off, 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 1f42cd242..1575ca236 100644 --- a/grub-core/io/xzio.c +++ b/grub-core/io/xzio.c @@ -48,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; @@ -71,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; @@ -92,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); @@ -101,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) { @@ -132,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; @@ -150,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) 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..460d8778f 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 @@ -207,10 +203,12 @@ int grub_disk_dev_iterate (int (*hook) (const char *name)) { grub_disk_dev_t p; + grub_disk_pull_t pull; - for (p = grub_disk_dev_list; p; p = p->next) - if (p->iterate && (p->iterate) (hook)) - return 1; + 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; } @@ -247,6 +245,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 +265,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 +280,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 +379,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 +497,125 @@ 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) + { + (disk->read_hook) (s, o, + ((l > GRUB_DISK_SECTOR_SIZE) + ? GRUB_DISK_SECTOR_SIZE + : l)); + s++; + l -= GRUB_DISK_SECTOR_SIZE - o; + o = 0; + } + } return grub_errno; } @@ -528,25 +625,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 +657,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 +668,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 +678,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 +702,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 5f214e378..aaeb01f00 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -233,7 +233,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) unsigned i; Elf_Shdr *s; grub_size_t tsize = 0, talign = 1; -#ifdef __ia64__ +#if defined (__ia64__) || defined (__powerpc__) grub_size_t tramp; grub_size_t got; #endif @@ -243,14 +243,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) i < e->e_shnum; i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) { - tsize += ALIGN_UP (s->sh_size, s->sh_addralign); + tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; if (talign < s->sh_addralign) talign = s->sh_addralign; } -#ifdef __ia64__ +#if defined (__ia64__) || defined (__powerpc__) grub_arch_dl_get_tramp_got_size (e, &tramp, &got); - tramp *= GRUB_IA64_DL_TRAMP_SIZE; + 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) @@ -269,6 +269,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) mod->base = grub_memalign (talign, tsize); if (!mod->base) return grub_errno; + mod->sz = tsize; ptr = mod->base; #ifdef GRUB_MACHINE_EMU @@ -316,7 +317,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) mod->segment = seg; } } -#ifdef __ia64__ +#if defined (__ia64__) || defined (__powerpc__) ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN); mod->tramp = ptr; ptr += tramp; @@ -575,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. */ @@ -688,11 +683,9 @@ 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--; return mod; @@ -704,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) @@ -736,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; @@ -756,13 +748,7 @@ grub_dl_unload (grub_dl_t 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 c95058733..9a2c5e64d 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -163,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, @@ -218,7 +206,7 @@ grub_get_rtc (void) /* 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; @@ -746,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/emu/hostdisk.c b/grub-core/kern/emu/hostdisk.c index 8f30c8a09..d9cf07cf4 100644 --- a/grub-core/kern/emu/hostdisk.c +++ b/grub-core/kern/emu/hostdisk.c @@ -43,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. */ @@ -93,10 +94,16 @@ struct hd_geometry # 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 @@ -105,9 +112,7 @@ struct hd_geometry # include #endif -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include -#elif defined(__NetBSD__) +#if defined(__NetBSD__) # define HAVE_DIOCGDINFO # include # include /* struct disklabel */ @@ -187,6 +192,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) { @@ -195,7 +221,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; } @@ -215,10 +241,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; @@ -226,6 +256,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) { @@ -254,7 +376,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; @@ -262,77 +384,30 @@ 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; - } - data->is_disk = 1; - -# 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; } int @@ -353,11 +428,13 @@ grub_util_device_is_mapped (const char *dev) #endif /* HAVE_DEVICE_MAPPER */ } + #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) + /* FIXME: geom actually gives us the whole container hierarchy. It can be used more efficiently than this. */ -static void -follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out) +void +grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out) { struct gmesh mesh; struct gclass *class; @@ -368,13 +445,13 @@ follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out) error = geom_gettree (&mesh); if (error != 0) - grub_util_error ("couldn't open geom"); + 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"); + grub_util_error (_("couldn't open geom part")); LIST_FOREACH (geom, &class->lg_geom, lg_geom) { @@ -387,7 +464,7 @@ follow_geom_up (const char *name, grub_disk_addr_t *off_out, char **name_out) struct gconfig *config; grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name); - follow_geom_up (name_tmp, &off, name_out); + 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) @@ -410,16 +487,19 @@ find_partition_start (const char *dev) grub_disk_addr_t out; if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0) return 0; - follow_geom_up (dev + sizeof ("/dev/") - 1, &out, NULL); + grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL); return out; } -#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) + +#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__) static grub_disk_addr_t 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; @@ -506,7 +586,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__) @@ -527,7 +609,9 @@ 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) */ if (dev[0]) @@ -567,6 +651,7 @@ linux_find_partition (char *dev, grub_disk_addr_t sector) int i; char real_dev[PATH_MAX]; struct linux_partition_cache *cache; + int missing = 0; strcpy(real_dev, dev); @@ -575,6 +660,12 @@ linux_find_partition (char *dev, grub_disk_addr_t 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; @@ -605,7 +696,13 @@ linux_find_partition (char *dev, grub_disk_addr_t sector) fd = open (real_dev, O_RDONLY); if (fd == -1) - continue; + { + if (missing++ < 10) + continue; + else + return 0; + } + missing = 0; close (fd); start = find_partition_start (real_dev); @@ -632,6 +729,37 @@ linux_find_partition (char *dev, grub_disk_addr_t 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 + static int open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags) { @@ -784,44 +912,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; @@ -904,19 +1008,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); 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; @@ -949,8 +1054,8 @@ 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 (nwrite (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; @@ -1048,18 +1153,18 @@ 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')); @@ -1072,7 +1177,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; @@ -1101,7 +1206,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 @@ -1142,25 +1247,28 @@ grub_util_biosdisk_fini (void) static char * make_device_name (int drive, int dos_part, int bsd_part) { - char *ret; - char *dos_part_str = NULL; - char *bsd_part_str = NULL; + char *ret, *ptr, *end; + const char *iptr; + ret = xmalloc (strlen (map[drive].drive) * 2 + + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX" + ",XXXXXXXXXXXXXXXXXXXXXXXXXX")); + end = (ret + strlen (map[drive].drive) * 2 + + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX" + ",XXXXXXXXXXXXXXXXXXXXXXXXXX")); + ptr = ret; + for (iptr = map[drive].drive; *iptr; iptr++) + { + if (*iptr == ',') + *ptr++ = '\\'; + *ptr++ = *iptr; + } + *ptr = 0; if (dos_part >= 0) - dos_part_str = xasprintf (",%d", dos_part + 1); - + snprintf (ptr, end - ptr, ",%d", dos_part + 1); + ptr += strlen (ptr); 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); + snprintf (ptr, end - ptr, ",%d", bsd_part + 1); return ret; } @@ -1418,7 +1526,8 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) if (tree) dm_tree_free (tree); free (path); - char *ret = grub_find_device (NULL, (major << 8) | minor); + char *ret = grub_find_device ("/dev", + (major << 8) | minor); return ret; } @@ -1496,7 +1605,7 @@ devmapper_out: char *out, *out2; if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0) return xstrdup (os_dev); - follow_geom_up (os_dev + sizeof ("/dev/") - 1, NULL, &out); + grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out); out2 = xasprintf ("/dev/%s", out); free (out); @@ -1545,12 +1654,37 @@ devmapper_out: } 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 } +#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) @@ -1627,7 +1761,10 @@ find_system_device (const char *os_dev, struct stat *st, int convert, int add) } if (!add) - return -1; + { + free (os_disk); + return -1; + } if (i == ARRAY_SIZE (map)) grub_util_error (_("device count exceeds limit")); @@ -1657,6 +1794,9 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) { struct stat st; int drive; + char *sys_disk; + + grub_util_info ("Looking for %s", os_dev); if (stat (os_dev, &st) < 0) { @@ -1674,18 +1814,22 @@ grub_util_biosdisk_get_grub_dev (const char *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); + 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__) +#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__) +#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. @@ -1725,7 +1869,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) name = make_device_name (drive, -1, -1); -# if !defined(HAVE_DIOCGDINFO) +# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__) if (MAJOR (st.st_rdev) == FLOPPY_MAJOR) return name; # else /* defined(HAVE_DIOCGDINFO) */ @@ -1788,6 +1932,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) 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; @@ -1851,6 +1996,9 @@ grub_util_biosdisk_is_floppy (grub_disk_t disk) struct stat st; int fd; + if (disk->dev != &grub_util_biosdisk_dev) + return 0; + fd = open (map[disk->id].device, O_RDONLY); /* Shouldn't happen. */ if (fd == -1) @@ -1858,7 +2006,12 @@ grub_util_biosdisk_is_floppy (grub_disk_t disk) /* Shouldn't happen either. */ if (fstat (fd, &st) < 0) - return 0; + { + close (fd); + return 0; + } + + close (fd); #if defined(__NetBSD__) if (major(st.st_rdev) == RAW_FLOPPY_MAJOR) 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 44c40b010..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,265 +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); -#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 defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) - if (poolfs) - return xasprintf ("/%s/@", poolfs); -#endif - 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 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 8f843a872..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; diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index 9d5a51c48..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]; @@ -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 d8c337bde..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,6 +150,9 @@ compact_mem_regions (void) } } +grub_addr_t grub_modbase; +extern grub_uint8_t _start[], _edata[]; + void grub_machine_init (void) { @@ -148,6 +161,8 @@ grub_machine_init (void) int grub_lower_mem; #endif + grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); + /* Initialize the console as early as possible. */ grub_console_init (); @@ -211,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/startup.S b/grub-core/kern/i386/pc/startup.S index e78a0aa9a..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,211 +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 - 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 - jmp LOCAL (codestart) - -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 @@ -263,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 @@ -288,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() @@ -472,403 +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 0x011b, 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 - pushl %edi - - 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 - cmpl $0x20, %eax - jae 2f - movl %edx, %eax - leal LOCAL(bypass_table), %edi - movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) >> 1), %ecx - repne scasw - jz 3f - - andl $0xff, %eax - 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 %edi - 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 - - cmp %cl, %ch - jb 3f - movw $0x0d0e, %cx -3: - 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); */ @@ -887,7 +152,7 @@ FUNCTION(grub_pxe_call) shll $16, %edx addl %eax, %edx - call prot_to_real + PROT_TO_REAL .code16 pushl %ebx @@ -899,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 @@ -910,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 index 3904f73b7..31b5f94cf 100644 --- a/grub-core/kern/ia64/dl.c +++ b/grub-core/kern/ia64/dl.c @@ -104,13 +104,13 @@ add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value) } } -static grub_uint8_t nopm[5] = +static const grub_uint8_t nopm[5] = { /* [MLX] nop.m 0x0 */ 0x05, 0x00, 0x00, 0x00, 0x01 }; -static grub_uint8_t jump[0x20] = +static const grub_uint8_t jump[0x20] = { /* ld8 r16=[r15],8 */ 0x02, 0x80, 0x20, 0x1e, 0x18, 0x14, diff --git a/grub-core/kern/ia64/dl_helper.c b/grub-core/kern/ia64/dl_helper.c index 91f28026e..958cdb25e 100644 --- a/grub-core/kern/ia64/dl_helper.c +++ b/grub-core/kern/ia64/dl_helper.c @@ -30,7 +30,6 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, const Elf64_Ehdr *e = ehdr; grub_size_t cntt = 0, cntg = 0;; const Elf64_Shdr *s; - Elf64_Word entsize; unsigned i; /* Find a symbol table. */ @@ -43,8 +42,6 @@ grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, if (i == grub_le_to_cpu16 (e->e_shnum)) return; - entsize = s->sh_entsize; - 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))) diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c index 6bb4219ac..e2fa58090 100644 --- a/grub-core/kern/ia64/efi/init.c +++ b/grub-core/kern/ia64/efi/init.c @@ -40,12 +40,6 @@ grub_machine_fini (void) grub_efi_fini (); } -void -grub_machine_set_prefix (void) -{ - grub_efi_set_prefix (); -} - void grub_arch_sync_caches (void *address, grub_size_t len) { diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S index b5e26a204..d75c6d7cc 100644 --- a/grub-core/kern/ia64/efi/startup.S +++ b/grub-core/kern/ia64/efi/startup.S @@ -42,13 +42,3 @@ _start: br.ret.sptk.few rp .endp _start - - . = _start + GRUB_KERNEL_MACHINE_PREFIX -VARIABLE(grub_prefix) - .byte 0 - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - . = _start + GRUB_KERNEL_MACHINE_PREFIX_END diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c index 2fbe809b2..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); diff --git a/grub-core/kern/ieee1275/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c index 9e2919172..b20f64d68 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 { @@ -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/openfw.c b/grub-core/kern/ieee1275/openfw.c index f5dc8efb1..ee81b4ef9 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; @@ -317,14 +320,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 +337,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 +446,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 ("%s,%d", device, partno); } else - encoding = grub_xasprintf ("(%s)", device); + encoding = grub_strdup (device); grub_free (partition); grub_free (device); @@ -414,16 +457,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 +500,4 @@ grub_ieee1275_canonicalise_devname (const char *path) grub_free (buf); return NULL; } + diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c index cc9758988..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 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,7 @@ 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"); diff --git a/grub-core/kern/mips/arc/init.c b/grub-core/kern/mips/arc/init.c index 514b481f6..41545b11f 100644 --- a/grub-core/kern/mips/arc/init.c +++ b/grub-core/kern/mips/arc/init.c @@ -33,6 +33,7 @@ #include #include #include +#include const char *type_names[] = { #ifdef GRUB_CPU_WORDS_BIGENDIAN @@ -125,12 +126,14 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) } extern grub_uint32_t grub_total_modules_size; +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. */ @@ -164,12 +167,6 @@ grub_machine_init (void) grub_arcdisk_init (); } -grub_addr_t -grub_arch_modules_addr (void) -{ - return GRUB_KERNEL_MIPS_ARC_LINK_ADDR - grub_total_modules_size; -} - void grub_machine_fini (void) { @@ -182,7 +179,7 @@ grub_halt (void) grub_millisleep (1500); - grub_printf ("Shutdown failed\n"); + grub_puts_ (N_("Shutdown failed")); grub_refresh (); while (1); } @@ -194,19 +191,7 @@ grub_exit (void) grub_millisleep (1500); - grub_printf ("Exit failed\n"); - grub_refresh (); - while (1); -} - -void -grub_reboot (void) -{ - GRUB_ARC_FIRMWARE_VECTOR->restart (); - - grub_millisleep (1500); - - grub_printf ("Reboot failed\n"); + grub_puts_ (N_("Exit failed")); grub_refresh (); while (1); } diff --git a/grub-core/kern/mips/cache_flush.S b/grub-core/kern/mips/cache_flush.S index a352fd8ba..c03c337b5 100644 --- a/grub-core/kern/mips/cache_flush.S +++ b/grub-core/kern/mips/cache_flush.S @@ -9,6 +9,13 @@ subu $t1, $t3, $t2 1: cache 1, 0($t0) + /* 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, 0x4 diff --git a/grub-core/kern/mips/init.c b/grub-core/kern/mips/init.c index bfa08f56a..353f679e6 100644 --- a/grub-core/kern/mips/init.c +++ b/grub-core/kern/mips/init.c @@ -38,7 +38,7 @@ grub_get_rtc (void) } void -grub_machine_set_prefix (void) +grub_machine_get_bootlocation (char **device __attribute__ ((unused)), + char **path __attribute__ ((unused))) { - grub_env_set ("prefix", grub_prefix); } diff --git a/grub-core/kern/mips/loongson/init.c b/grub-core/kern/mips/loongson/init.c index bcef391b9..3b282e1e0 100644 --- a/grub-core/kern/mips/loongson/init.c +++ b/grub-core/kern/mips/loongson/init.c @@ -30,11 +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); @@ -123,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) @@ -170,7 +188,7 @@ grub_machine_init (void) } else { - grub_arch_memsize = (totalmem >> 20); + grub_arch_memsize = totalmem; grub_arch_highmemsize = 0; } @@ -189,6 +207,7 @@ grub_machine_init (void) 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 (); @@ -213,7 +232,9 @@ grub_halt (void) { switch (grub_arch_machine) { - case GRUB_ARCH_MACHINE_FULOONG: + case GRUB_ARCH_MACHINE_FULOONG2E: + break; + case GRUB_ARCH_MACHINE_FULOONG2F: { grub_pci_device_t dev; grub_port_t p; @@ -234,7 +255,7 @@ grub_halt (void) break; } - grub_printf ("Shutdown failed\n"); + grub_puts_ (N_("Shutdown failed")); grub_refresh (); while (1); } @@ -245,22 +266,6 @@ grub_exit (void) grub_halt (); } -void -grub_reboot (void) -{ - grub_write_ec (GRUB_MACHINE_EC_COMMAND_REBOOT); - - grub_millisleep (1500); - - grub_printf ("Reboot failed\n"); - grub_refresh (); - while (1); -} - extern char _end[]; +grub_addr_t grub_modbase = (grub_addr_t) _end; -grub_addr_t -grub_arch_modules_addr (void) -{ - return (grub_addr_t) _end; -} diff --git a/grub-core/kern/mips/qemu_mips/init.c b/grub-core/kern/mips/qemu_mips/init.c index 2180b347a..120b450f5 100644 --- a/grub-core/kern/mips/qemu_mips/init.c +++ b/grub-core/kern/mips/qemu_mips/init.c @@ -7,17 +7,51 @@ #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; @@ -27,8 +61,22 @@ grub_machine_init (void) 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 @@ -48,12 +96,6 @@ grub_halt (void) while (1); } -void -grub_reboot (void) -{ - while (1); -} - grub_err_t grub_machine_mmap_iterate (grub_memory_hook_t hook) { @@ -62,9 +104,5 @@ grub_machine_mmap_iterate (grub_memory_hook_t hook) } extern char _end[]; +grub_addr_t grub_modbase = (grub_addr_t) _end; -grub_addr_t -grub_arch_modules_addr (void) -{ - return (grub_addr_t) _end; -} diff --git a/grub-core/kern/mips/startup.S b/grub-core/kern/mips/startup.S index 6220a8c33..2476038bc 100644 --- a/grub-core/kern/mips/startup.S +++ b/grub-core/kern/mips/startup.S @@ -40,17 +40,6 @@ start: 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 VARIABLE (grub_arch_busclock) .long 0 VARIABLE (grub_arch_cpuclock) @@ -61,7 +50,7 @@ VARIABLE (grub_arch_highmemsize) .long 0 #ifdef GRUB_MACHINE_MIPS_LOONGSON VARIABLE (grub_arch_machine) - .long GRUB_ARCH_MACHINE_FULOONG + .long GRUB_ARCH_MACHINE_FULOONG2F #endif cont: /* Save our base. */ diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c index a3dfabf82..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) { @@ -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 d54f3f240..ee4d58d81 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -515,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); @@ -528,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); @@ -547,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); @@ -561,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..cd9e8ae0f 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); diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c index ad19e5600..34e780a45 100644 --- a/grub-core/kern/powerpc/dl.c +++ b/grub-core/kern/powerpc/dl.c @@ -37,6 +37,65 @@ 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; + Elf_Word entsize; + 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; + + entsize = s->sh_entsize; + + 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 +105,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 +166,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 aae267872..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), ... @@ -95,6 +94,20 @@ FUNCTION(efi_wrap_6) 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 $96, %rsp mov 96+40(%rsp), %rax 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/cmos_datetime.c b/grub-core/lib/cmos_datetime.c index 73c5a03c0..86cd91180 100644 --- a/grub-core/lib/cmos_datetime.c +++ b/grub-core/lib/cmos_datetime.c @@ -23,30 +23,44 @@ 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); @@ -54,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); @@ -71,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); @@ -87,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); @@ -102,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; @@ -138,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/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 ad1bfc4d3..48d860335 100644 --- a/grub-core/lib/crypto.c +++ b/grub-core/lib/crypto.c @@ -23,6 +23,13 @@ #include #include +#ifdef GRUB_UTIL +#include +#include +#include +#include +#endif + GRUB_MOD_LICENSE ("GPLv3+"); struct grub_crypto_hmac_handle @@ -162,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) @@ -202,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) @@ -242,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; @@ -336,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); @@ -378,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; @@ -414,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; @@ -452,5 +474,5 @@ grub_password_get (char buf[], unsigned buf_size) grub_refresh (); return (key != '\e'); -} #endif +} diff --git a/grub-core/lib/efi/reboot.c b/grub-core/lib/efi/reboot.c new file mode 100644 index 000000000..9382370f7 --- /dev/null +++ b/grub-core/lib/efi/reboot.c @@ -0,0 +1,32 @@ +/* + * 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_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/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 12771085a..0f0e743c4 100644 --- a/grub-core/lib/i386/pc/biosnum.c +++ b/grub-core/lib/i386/pc/biosnum.c @@ -24,7 +24,7 @@ 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 2f10feb5e..1f0aa0dd1 100644 --- a/grub-core/lib/i386/relocator.c +++ b/grub-core/lib/i386/relocator.c @@ -51,6 +51,9 @@ 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; @@ -195,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); @@ -215,6 +219,9 @@ grub_relocator16_boot (struct grub_relocator *rel, 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 d6673fade..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 */ @@ -132,6 +211,12 @@ VARIABLE(grub_relocator16_sp) .word 0 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) diff --git a/grub-core/lib/ia64/setjmp.S b/grub-core/lib/ia64/setjmp.S index 0851885c5..190623d35 100644 --- a/grub-core/lib/ia64/setjmp.S +++ b/grub-core/lib/ia64/setjmp.S @@ -64,6 +64,12 @@ 0x1b0 f30 0x1c0 f31 */ +#include +#include + + .file "setjmp.S" + +GRUB_MOD_LICENSE ("GPLv2+") /* The following two entry points are the traditional entry points: */ 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 4105c639b..1947135fe 100644 --- a/grub-core/lib/ieee1275/datetime.c +++ b/grub-core/lib/ieee1275/datetime.c @@ -21,10 +21,14 @@ #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) @@ -42,6 +46,8 @@ find_rtc (void) } grub_ieee1275_devices_iterate (hook); + if (!rtc) + no_ieee1275_rtc = 1; } grub_err_t @@ -64,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) @@ -114,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 659fa7061..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; }; +/* 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 @@ static 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, @@ -399,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; @@ -411,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: @@ -662,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: @@ -756,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 59febaeb5..0141400fc 100644 --- a/grub-core/lib/libgcrypt_wrap/cipher_wrap.h +++ b/grub-core/lib/libgcrypt_wrap/cipher_wrap.h @@ -87,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/include/grub/i386/pc/loader.h b/grub-core/lib/mips/arc/reboot.c similarity index 65% rename from include/grub/i386/pc/loader.h rename to grub-core/lib/mips/arc/reboot.c index bfbcaac5a..ecf12a7ed 100644 --- a/include/grub/i386/pc/loader.h +++ b/grub-core/lib/mips/arc/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,20 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 +#include +#include +#include +#include +#include -#include +void +grub_reboot (void) +{ + GRUB_ARC_FIRMWARE_VECTOR->restart (); -/* This is an asm part of the chainloader. */ -void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); + grub_millisleep (1500); -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ + 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/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/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..fe8523e68 100644 --- a/grub-core/lib/posix_wrap/limits.h +++ b/grub-core/lib/posix_wrap/limits.h @@ -0,0 +1,31 @@ +/* + * 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 CHAR_BIT 8 + +#endif diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h index 4c725f6e2..b35e21bb8 100644 --- a/grub-core/lib/posix_wrap/stdlib.h +++ b/grub-core/lib/posix_wrap/stdlib.h @@ -46,7 +46,7 @@ realloc (void *ptr, grub_size_t size) return grub_realloc (ptr, size); } -static inline void +static inline void __attribute__ ((noreturn)) abort (void) { grub_abort (); diff --git a/grub-core/lib/posix_wrap/string.h b/grub-core/lib/posix_wrap/string.h index 4224836e2..f38c97ba4 100644 --- a/grub-core/lib/posix_wrap/string.h +++ b/grub-core/lib/posix_wrap/string.h @@ -39,4 +39,12 @@ 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); +} +#endif + #endif diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h index 69e49509e..0c58d6c44 100644 --- a/grub-core/lib/posix_wrap/sys/types.h +++ b/grub-core/lib/posix_wrap/sys/types.h @@ -24,9 +24,6 @@ typedef grub_size_t size_t; typedef enum { false = 0, true = 1 } bool; -#define ULONG_MAX GRUB_ULONG_MAX -#define UCHAR_MAX 0xff - typedef grub_uint8_t uint8_t; typedef grub_uint16_t uint16_t; typedef grub_uint32_t uint32_t; diff --git a/grub-core/lib/posix_wrap/wchar.h b/grub-core/lib/posix_wrap/wchar.h index fd56fd332..a696643de 100644 --- a/grub-core/lib/posix_wrap/wchar.h +++ b/grub-core/lib/posix_wrap/wchar.h @@ -19,7 +19,92 @@ #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 + }; + +#define MB_LEN_MAX 4 + +/* UCS-4. */ +typedef grub_int32_t wchar_t; + +typedef struct mbstate { + grub_uint32_t code; + int count; +} mbstate_t; + +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..b2b33ab08 100644 --- a/grub-core/lib/posix_wrap/wctype.h +++ b/grub-core/lib/posix_wrap/wctype.h @@ -0,0 +1,106 @@ +/* + * 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; + +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/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 e500ba32d..0257342d0 100644 --- a/grub-core/lib/reed_solomon.c +++ b/grub-core/lib/reed_solomon.c @@ -25,11 +25,14 @@ #define grub_memcpy memcpy #endif +#ifndef STANDALONE +#include +#endif + #ifndef STANDALONE #ifdef TEST typedef unsigned int grub_size_t; typedef unsigned char grub_uint8_t; -typedef unsigned short grub_uint16_t; #else #include #include @@ -42,7 +45,6 @@ typedef unsigned short grub_uint16_t; #ifdef TEST typedef unsigned int grub_size_t; typedef unsigned char grub_uint8_t; -typedef unsigned short grub_uint16_t; #else #include #include @@ -53,65 +55,73 @@ 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 char *scratch __attribute__ ((section(".text"))) = (void *) 0x100300; #else #if defined (STANDALONE) static char *scratch; #endif -static grub_uint8_t gf_invert[256]; +static gf_single_t gf_powx[255 * 2]; +static gf_single_t gf_powx_inv[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) { int i; - gf_single_t xn = 1, s = 0; + gf_single_t s = 0; + int log_xn = 0, log_x; + if (x == 0) + return pol[0]; + log_x = gf_powx_inv[x]; 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; } @@ -120,7 +130,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)); @@ -132,16 +142,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]) @@ -162,7 +170,8 @@ syndroms (gf_single_t *m, grub_size_t s, grub_size_t rs, { gf_single_t xn = 1; unsigned i; - for (i = 0; i < rs; i++) + sy[0] = pol_evaluate (m, s + rs - 1, xn); + for (i = 1; i < rs; i++) { if (xn & (1 << (GF_SIZE - 1))) { @@ -190,7 +199,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++) @@ -265,6 +274,27 @@ rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) syndroms (m, s, rs, sy); + for (i = 0; i < (int) rs; i++) + if (sy[i] != 0) + break; + + /* No error detected. */ + if (i == (int) rs) + { +#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 + return; + } + { gf_single_t *eq; @@ -275,14 +305,6 @@ rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) 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]; @@ -328,7 +350,7 @@ rs_recover (gf_single_t *m, grub_size_t s, grub_size_t rs) #endif for (j = 0; j < errnum; j++) - eq[j] = errpot[j]; + eq[j] = 1; eq[errnum] = sy[0]; for (i = 1; i < (int) rs; i++) { @@ -372,12 +394,19 @@ 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]; + gf_single_t *m; /* Nothing to do. */ if (!ds || !rr) continue; +#ifndef STANDALONE + m = xmalloc (ds + rr); +#else + m = (gf_single_t *) scratch; + scratch += ds + rr; +#endif + for (j = 0; j < (int) ds; j++) m[j] = ptr[SECTOR_SIZE * j + i]; for (j = 0; j < (int) rr; j++) @@ -387,6 +416,12 @@ decode_block (gf_single_t *ptr, grub_size_t s, for (j = 0; j < (int) ds; j++) ptr[SECTOR_SIZE * j + i] = m[j]; + +#ifndef STANDALONE + free (m); +#else + scratch -= ds + rr; +#endif } } @@ -400,12 +435,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 @@ -419,11 +460,17 @@ 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) { grub_size_t tt; @@ -442,6 +489,9 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size, s -= cs; rs -= crs; } + + assert (grub_memcmp (tmp, buffer, data_size) == 0); + free (tmp); } #endif @@ -455,9 +505,7 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs) if (!rs) return; -#if defined (STANDALONE) - init_inverts (); -#endif + init_powx (); while (s > 0) { @@ -487,12 +535,15 @@ main (int argc, char **argv) grub_size_t s, rs; char *buf; + grub_memset (gf_powx, 0xee, sizeof (gf_powx)); + grub_memset (gf_powx_inv, 0xdd, sizeof (gf_powx_inv)); + #ifdef STANDALONE scratch = xmalloc (1048576); #endif #ifndef STANDALONE - init_inverts (); + init_powx (); #endif in = fopen ("tst.bin", "rb"); @@ -501,17 +552,19 @@ main (int argc, char **argv) fseek (in, 0, SEEK_END); s = ftell (in); fseek (in, 0, SEEK_SET); - rs = s / 3; + rs = 0x7007; buf = xmalloc (s + rs + SECTOR_SIZE); fread (buf, 1, s, in); + fclose (in); grub_reed_solomon_add_redundancy (buf, s, rs); out = fopen ("tst_rs.bin", "wb"); fwrite (buf, 1, s + rs, out); fclose (out); - +#if 1 grub_memset (buf + 512 * 15, 0, 512); +#endif out = fopen ("tst_dam.bin", "wb"); fwrite (buf, 1, s + rs, out); diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index 6eb20b865..aa404731f 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -764,6 +764,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++) @@ -855,7 +858,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, @@ -910,6 +913,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: @@ -1009,7 +1013,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; @@ -1021,7 +1026,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; @@ -1081,10 +1085,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; @@ -1092,7 +1094,6 @@ malloc_in_range (struct grub_relocator *rel, } #endif -#endif if (!oom) cural++; else diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S index b04fd7439..fb7f94767 100644 --- a/grub-core/lib/setjmp.S +++ b/grub-core/lib/setjmp.S @@ -10,6 +10,7 @@ #include "./powerpc/setjmp.S" #elif defined(__ia64__) #include "./ia64/setjmp.S" +#include "./ia64/longjmp.S" #else #error "Unknown target cpu type" #endif diff --git a/grub-core/lib/xzembed/xz_dec_stream.c b/grub-core/lib/xzembed/xz_dec_stream.c index 3bf201d50..09e5e513a 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,102 @@ 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]; + 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 + HEADER_MAGIC_SIZE, 2); - GRUB_MD_CRC32->final(crc32_context); + s->crc32->init(hash_context); + s->crc32->write(hash_context,s->temp.buf + HEADER_MAGIC_SIZE, 2); + 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 + HEADER_MAGIC_SIZE + 2); + 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(resultcrc != readcrc) - return XZ_DATA_ERROR; + 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 +552,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 +584,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 +607,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 +808,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 +838,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,46 +956,12 @@ struct xz_dec * xz_dec_init(uint32_t dict_max) return NULL; #endif + memset (s, 0, sizeof (*s)); + #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); + s->crc32 = grub_crypto_lookup_md_by_name ("CRC32"); #endif - s->crc32_temp = 0; - s->single_call = dict_max == 0; #ifdef XZ_DEC_BCJ @@ -876,28 +996,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 +1028,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/efi/appleloader.c b/grub-core/loader/efi/appleloader.c index db57a573c..d0211a80f 100644 --- a/grub-core/loader/efi/appleloader.c +++ b/grub-core/loader/efi/appleloader.c @@ -126,7 +126,7 @@ static struct piwg_full_device_path devpath_6 = MAKE_PIWG_PATH (0xffcc4000, struct devdata { - char *model; + const char *model; grub_efi_device_path_t *devpath; }; diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c index 5dd5adab2..3ecdca534 100644 --- a/grub-core/loader/efi/chainloader.c +++ b/grub-core/loader/efi/chainloader.c @@ -329,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 6487dc3df..f9bab21e6 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -204,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; @@ -381,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++; @@ -448,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) { @@ -513,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, @@ -946,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) { @@ -966,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; } @@ -1322,6 +1409,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) @@ -1343,7 +1435,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; } @@ -1602,6 +1694,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); } @@ -1713,7 +1807,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; @@ -1970,7 +2064,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 92d267534..7cec7a8ef 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -244,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; 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 9e3d482ab..80ad542e3 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -45,15 +45,18 @@ GRUB_MOD_LICENSE ("GPLv3+"); #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 @@ -127,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; @@ -195,6 +201,8 @@ allocate_pages (grub_size_t prot_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", @@ -288,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) @@ -296,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)) @@ -308,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 @@ -317,7 +329,7 @@ grub_linux_setup_video (struct linux_kernel_params *params) void *framebuffer; grub_err_t err; grub_video_driver_id_t driver_id; - char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb"); + const char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb"); driver_id = grub_video_get_driver_id (); @@ -371,6 +383,7 @@ grub_linux_setup_video (struct linux_kernel_params *params) 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: @@ -414,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"); @@ -441,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_BADRAM: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_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"); @@ -483,16 +498,26 @@ 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; } @@ -768,7 +793,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), 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. */ @@ -784,9 +809,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; @@ -794,9 +819,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: @@ -805,9 +830,9 @@ 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; } @@ -822,9 +847,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); diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index bef534296..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 @@ -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. */ @@ -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; diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c index 8d6ec8f20..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 @@ -39,12 +38,14 @@ #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 { @@ -55,16 +56,29 @@ typedef enum 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; } @@ -133,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); @@ -142,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) @@ -153,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)) { @@ -177,10 +213,9 @@ 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; } } @@ -247,7 +282,7 @@ static grub_command_t cmd; GRUB_MOD_INIT(chainloader) { cmd = grub_register_command ("chainloader", grub_cmd_chainloader, - "[--force|--bpb] FILE", + 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 index 0ae815490..1f088e2b5 100644 --- a/grub-core/loader/i386/pc/freedos.c +++ b/grub-core/loader/i386/pc/freedos.c @@ -33,6 +33,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; static struct grub_relocator *rel; static grub_uint32_t ebx = 0xffffffff; @@ -54,7 +56,8 @@ grub_freedos_boot (void) .ss = GRUB_FREEDOS_STACK_SEGMENT, .sp = GRUB_FREEDOS_STACK_POINTER, .ebx = ebx, - .edx = 0 + .edx = 0, + .a20 = 1 }; grub_video_set_mode ("text", 0, 0); diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index adc6e8b99..c7c099174 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 @@ -61,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); diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c index b2909c191..153b605ed 100644 --- a/grub-core/loader/i386/pc/ntldr.c +++ b/grub-core/loader/i386/pc/ntldr.c @@ -54,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); diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c new file mode 100644 index 000000000..5528b2c9f --- /dev/null +++ b/grub-core/loader/i386/pc/plan9.c @@ -0,0 +1,515 @@ +/* + * 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_PXE_ID: + 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 b877b0ea5..98b635911 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -46,7 +46,7 @@ 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; }; static struct tbl_alias table_aliases[] = @@ -226,7 +226,7 @@ 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; @@ -452,11 +452,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 +700,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 +734,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 +786,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 +821,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 +939,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; @@ -1018,7 +1018,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; @@ -1057,7 +1057,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) @@ -1077,11 +1077,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; diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c index b018e4549..247eebae5 100644 --- a/grub-core/loader/ia64/efi/linux.c +++ b/grub-core/loader/ia64/efi/linux.c @@ -31,6 +31,8 @@ #include #include +GRUB_MOD_LICENSE ("GPLv3+"); + #define ALIGN_MIN (256*1024*1024) #define GRUB_ELF_SEARCH 1024 diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 64c4a0531..17c2656e2 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -41,7 +41,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); const char loongson_machtypes[][60] = { [GRUB_ARCH_MACHINE_YEELOONG] = "machtype=lemote-yeeloong-2f-8.9inches", - [GRUB_ARCH_MACHINE_FULOONG] = "machtype=lemote-fuloong-2f-unknown" + [GRUB_ARCH_MACHINE_FULOONG2F] = "machtype=lemote-fuloong-2f-box", + [GRUB_ARCH_MACHINE_FULOONG2E] = "machtype=lemote-fuloong-2e-unknown" }; #endif diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index d9e74b3c7..f76123e67 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -182,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; @@ -309,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); 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 05f581bb6..9a81afe8e 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -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/xnu.c b/grub-core/loader/xnu.c index a98d60c20..f96bc2b75 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -50,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) @@ -103,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; @@ -134,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; @@ -249,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) @@ -259,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); @@ -285,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); @@ -562,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; @@ -918,7 +920,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; @@ -1033,7 +1036,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; @@ -1099,7 +1102,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; diff --git a/grub-core/mmap/efi/mmap.c b/grub-core/mmap/efi/mmap.c index 8e5cce0d0..b34a3ba30 100644 --- a/grub-core/mmap/efi/mmap.c +++ b/grub-core/mmap/efi/mmap.c @@ -272,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/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..3343533ef --- /dev/null +++ b/grub-core/net/drivers/i386/pc/pxe.c @@ -0,0 +1,370 @@ +/* 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); + if (isr->status || isr->func_flag != GRUB_PXE_ISR_OUT_OURS) + { + 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..347a95afd --- /dev/null +++ b/grub-core/net/net.c @@ -0,0 +1,1535 @@ +/* + * 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; + 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_P (&grub_net_cards), + 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_P (&grub_net_routes), + 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..1201220b5 --- /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 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; + + 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; + + 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_P (&tcp_listens), + 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_P (&tcp_sockets), + 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_P (&tcp_sockets), + 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..c05ef24d4 --- /dev/null +++ b/grub-core/net/tftp.c @@ -0,0 +1,435 @@ +/* + * 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, + TFTP_MAX_PACKET = 1432 + }; + +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[TFTP_MAX_PACKET]; + } 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..8ca8ebb0a --- /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; + + 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_P (&udp_sockets), + 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/charset.c b/grub-core/normal/charset.c index 85ead53c4..ee4a7ef5f 100644 --- a/grub-core/normal/charset.c +++ b/grub-core/normal/charset.c @@ -60,6 +60,51 @@ #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) + { + /* 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; +} + 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,64 +119,27 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, while (srcsize && destsize) { - grub_uint32_t c = *src++; + grub_uint8_t c = *src++; if (srcsize != (grub_size_t)-1) srcsize--; - if (count) + if (!grub_utf8_process (c, &code, &count)) + return -1; + if (count != 0) + continue; + if (code == 0) + break; + if (destsize < 2 && code >= GRUB_UCS2_LIMIT) + break; + if (code >= GRUB_UCS2_LIMIT) { - if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) - { - /* invalid */ - return -1; - } - else - { - code <<= 6; - code |= (c & GRUB_UINT8_6_TRAILINGBITS); - count--; - } + *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 - 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--; } } @@ -140,9 +148,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. */ @@ -151,49 +206,27 @@ 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 (code < 0x10000) - { - if (dest + 2 >= destend) - break; - *dest++ = (code >> 12) | 0xE0; - *dest++ = ((code >> 6) & 0x3F) | 0x80; - *dest++ = (code & 0x3F) | 0x80; - } - else - { - if (dest + 3 >= destend) - break; - *dest++ = (code >> 18) | 0xF0; - *dest++ = ((code >> 12) & 0x3F) | 0x80; - *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; diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c index 09f2271ea..ea06b4cc7 100644 --- a/grub-core/normal/cmdline.c +++ b/grub-core/normal/cmdline.c @@ -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..8568cd892 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -28,7 +28,7 @@ #include /* The current word. */ -static char *current_word; +static const char *current_word; /* The matched string. */ static char *match; 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 2527d8fe9..21fcdf56f 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -274,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) diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index 5844cb2f0..ae8e3e681 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -79,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"); @@ -124,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; @@ -232,7 +232,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) grub_env_export ("chosen"); grub_free (buf); } - for (ptr = def; *ptr; ptr++) + + for (ptr = def; ptr && *ptr; ptr++) { if (ptr[0] == '>' && ptr[1] == '>') { @@ -242,10 +243,12 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) if (ptr[0] == '>') break; } - if (ptr[0] && ptr[1]) + + 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) @@ -663,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. */ diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c index dc5ab528f..7af093fd8 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c @@ -317,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; @@ -397,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]; diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c index a8b9e6683..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) diff --git a/grub-core/partmap/acorn.c b/grub-core/partmap/acorn.c index 9a68ddd92..341b8ac5f 100644 --- a/grub-core/partmap/acorn.c +++ b/grub-core/partmap/acorn.c @@ -34,11 +34,18 @@ GRUB_MOD_LICENSE ("GPLv3+"); 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 @@ -71,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/bsdlabel.c b/grub-core/partmap/bsdlabel.c index 888100aa2..490fbdd7b 100644 --- a/grub-core/partmap/bsdlabel.c +++ b/grub-core/partmap/bsdlabel.c @@ -24,6 +24,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -105,7 +106,7 @@ iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd, /* disk->partition != NULL as 0 < delta */ partname = disk->partition ? grub_partition_get_name (disk->partition) : ""; - 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, p.partmap->name, p.number + 1); grub_free (partname); #endif diff --git a/grub-core/partmap/dvh.c b/grub-core/partmap/dvh.c index 118401612..c8f467eb5 100644 --- a/grub-core/partmap/dvh.c +++ b/grub-core/partmap/dvh.c @@ -49,13 +49,13 @@ static struct grub_partition_map grub_dvh_partition_map; /* Verify checksum (true=ok). */ static int -grub_dvh_is_valid (struct grub_dvh_block *label) +grub_dvh_is_valid (grub_uint32_t *label) { grub_uint32_t *pos; grub_uint32_t sum = 0; - for (pos = (grub_uint32_t *) label; - pos < (grub_uint32_t *) (label + 1); + for (pos = label; + pos < (label + sizeof (struct grub_dvh_block) / 4); pos++) sum += *pos; @@ -68,7 +68,11 @@ dvh_partition_map_iterate (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition p; - struct grub_dvh_block block; + union + { + struct grub_dvh_block dvh; + grub_uint32_t raw[0]; + } block; unsigned partnum; grub_err_t err; @@ -78,24 +82,24 @@ dvh_partition_map_iterate (grub_disk_t disk, if (err) return err; - if (DVH_MAGIC != grub_be_to_cpu32 (block.magic)) + 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)) + 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.parts); partnum++) + for (partnum = 0; partnum < ARRAY_SIZE (block.dvh.parts); partnum++) { - if (block.parts[partnum].length == 0) + if (block.dvh.parts[partnum].length == 0) continue; if (partnum == 10) continue; - p.start = grub_be_to_cpu32 (block.parts[partnum].start); - p.len = grub_be_to_cpu32 (block.parts[partnum].length); + 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; diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c index 73a1c3b19..049fda850 100644 --- a/grub-core/partmap/gpt.c +++ b/grub-core/partmap/gpt.c @@ -140,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)) @@ -159,7 +165,7 @@ 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); if (err) diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c index 1b71c69ab..c8ab6acab 100644 --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -92,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", @@ -128,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; @@ -206,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) @@ -221,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; 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 c7ef681c4..dfe51f35d 100644 --- a/grub-core/partmap/sun.c +++ b/grub-core/partmap/sun.c @@ -71,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; @@ -90,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; @@ -100,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 @@ -112,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 28dc4f5be..1c1fdced0 100644 --- a/grub-core/partmap/sunpc.c +++ b/grub-core/partmap/sunpc.c @@ -53,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; @@ -72,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; @@ -88,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"); @@ -107,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 ecaca140a..3377a2ccc 100644 --- a/grub-core/parttool/msdospart.c +++ b/grub-core/parttool/msdospart.c @@ -27,6 +27,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv2+"); @@ -35,7 +36,7 @@ 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} }; @@ -65,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. */ @@ -83,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} }; @@ -129,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 856828d7b..b58d3e658 100644 --- a/grub-core/script/argv.c +++ b/grub-core/script/argv.c @@ -66,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; @@ -99,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; @@ -123,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) @@ -138,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 72d199760..1fb5de6a3 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -193,7 +193,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 +202,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 +231,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 +252,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 +272,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 +313,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 +323,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 +348,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,16 +364,18 @@ 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; @@ -680,7 +687,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/lexer.c b/grub-core/script/lexer.c index 98279079f..53697c734 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" diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y index 683b3ac4b..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" @@ -147,7 +146,6 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | "until" { $$ = grub_script_add_arglist (state, 0, $1); } | "while" { $$ = grub_script_add_arglist (state, 0, $1); } | "function" { $$ = grub_script_add_arglist (state, 0, $1); } - | "time" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; diff --git a/grub-core/script/yylex.l b/grub-core/script/yylex.l index 53ae4c54f..012d88dbc 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; } @@ -355,8 +357,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/at_keyboard.c b/grub-core/term/at_keyboard.c index e86df6f35..bcd20d3ff 100644 --- a/grub-core/term/at_keyboard.c +++ b/grub-core/term/at_keyboard.c @@ -259,7 +259,7 @@ grub_keyboard_controller_write (grub_uint8_t c) grub_outb (c, KEYBOARD_REG_DATA); } -#if !defined (GRUB_MACHINE_MIPS_LOONGSON) && !defined (GRUB_MACHINE_QEMU) +#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) @@ -332,10 +332,10 @@ set_scancodes (void) return; } -#if !(defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_QEMU)) +#if !(defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_QEMU) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS)) current_set = 1; return; -#endif +#else grub_keyboard_controller_write (grub_keyboard_controller_orig & ~KEYBOARD_AT_TRANSLATE); @@ -352,6 +352,7 @@ set_scancodes (void) if (current_set == 1) return; grub_printf ("No supported scancode set found\n"); +#endif } static void @@ -569,7 +570,7 @@ 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) +#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 diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index 9e3d8eeb1..a10af5930 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -131,6 +131,7 @@ 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; @@ -266,7 +267,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++) @@ -338,8 +340,8 @@ 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) { @@ -1109,7 +1111,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} }; @@ -1189,7 +1194,6 @@ static grub_err_t grub_gfxterm_background_color_cmd (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { - grub_video_rgba_color_t color; struct grub_video_render_target *old_target; if (argc != 1) @@ -1199,7 +1203,7 @@ grub_gfxterm_background_color_cmd (grub_command_t cmd __attribute__ ((unused)), if (grub_video_get_info (NULL) != GRUB_ERR_NONE) return grub_errno; - if (grub_video_parse_color (args[0], &color) != GRUB_ERR_NONE) + if (grub_video_parse_color (args[0], &default_bg_color) != GRUB_ERR_NONE) return grub_errno; /* Destroy existing background bitmap if loaded. */ @@ -1216,9 +1220,10 @@ grub_gfxterm_background_color_cmd (grub_command_t cmd __attribute__ ((unused)), 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 (color); + 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 (color); + virtual_screen.bg_color_display = + grub_video_map_rgba_color (default_bg_color); blend_text_bg = 1; /* Mark whole screen as dirty. */ 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 1816bfae2..9abffcc0a 100644 --- a/grub-core/term/i386/pc/vga_text.c +++ b/grub-core/term/i386/pc/vga_text.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,11 @@ GRUB_MOD_LICENSE ("GPLv3+"); static int grub_curr_x, grub_curr_y; +#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) diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c index add112f4a..7b970587f 100644 --- a/grub-core/term/serial.c +++ b/grub-core/term/serial.c @@ -125,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; @@ -136,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)); @@ -157,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; @@ -239,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) { @@ -301,9 +310,18 @@ grub_serial_register (struct grub_serial_port *port) port->term_out = out; grub_terminfo_output_register (out, "vt100"); #ifdef GRUB_MACHINE_MIPS_LOONGSON - if (grub_strcmp (port->name, - (grub_arch_machine == GRUB_ARCH_MACHINE_YEELOONG) - ? "com0" : "com2") == 0) + 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); diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c index 3419a5117..f8b29ec2e 100644 --- a/grub-core/term/terminfo.c +++ b/grub-core/term/terminfo.c @@ -606,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, 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/video/colors.c b/grub-core/video/colors.c index 0637c5508..06625183e 100644 --- a/grub-core/video/colors.c +++ b/grub-core/video/colors.c @@ -21,6 +21,9 @@ #include #include #include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); struct named_color { @@ -208,14 +211,6 @@ grub_video_get_named_color (const char *name, return 0; } -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) { @@ -264,7 +259,7 @@ grub_video_parse_color (const char *s, grub_video_rgba_color_t *color) /* Count the hexits to determine the format. */ int hexits = 0; const char *end = s; - while (my_isxdigit (*end)) + while (grub_isxdigit (*end)) { end++; hexits++; 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 2cffcb3d9..2d9d99482 100644 --- a/grub-core/video/fb/video_fb.c +++ b/grub-core/video/fb/video_fb.c @@ -622,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, @@ -629,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, @@ -743,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 @@ -753,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 @@ -1195,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) diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index a109bcf43..92dd7ec07 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -20,15 +20,15 @@ #include #include -#include -#include +#include #include #include #include #include #include #include -#include +#include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -275,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) @@ -329,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) @@ -377,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 { @@ -698,11 +803,28 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, 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++) { @@ -745,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) @@ -861,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 = @@ -902,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 fe387a26b..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 @@ -34,7 +33,7 @@ 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; 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 8cdb2f61d..f2351dee9 100644 --- a/grub-core/video/readers/jpeg.c +++ b/grub-core/video/readers/jpeg.c @@ -39,6 +39,15 @@ GRUB_MOD_LICENSE ("GPLv3+"); #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)) @@ -66,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; @@ -82,6 +92,8 @@ struct grub_jpeg_data jpeg_data_unit_t cbdu; int vs, hs; + int dri; + int r1; int dc_value[3]; @@ -315,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) { @@ -526,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; @@ -563,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; @@ -588,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) { @@ -600,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); } @@ -610,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) { @@ -655,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; @@ -696,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 5728651e0..ae9879b16 100644 --- a/grub-core/video/readers/png.c +++ b/grub-core/video/readers/png.c @@ -625,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/video.c b/grub-core/video/video.c index 6a1d47304..ad87a69ff 100644 --- a/grub-core/video/video.c +++ b/grub-core/video/video.c @@ -376,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/ata.h b/include/grub/ata.h index c8f4e5e1b..1a19f27aa 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,30 +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_DEV_INIT = 10000, /* Give the device 10s on first try to spinon. */ + 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. */ @@ -120,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; @@ -129,49 +180,42 @@ struct grub_ata_device /* Set to 0 for ATA, set to 1 for ATAPI. */ int atapi; - int present; + int dma; - struct grub_ata_device *next; + 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/charset.h b/include/grub/charset.h index c8247f78a..b0960c940 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)) @@ -49,7 +51,7 @@ grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, /* 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; @@ -116,19 +118,52 @@ grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src, 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/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..c6d1ce8de --- /dev/null +++ b/include/grub/cryptodisk.h @@ -0,0 +1,147 @@ +/* + * 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; + + 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; + + 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_P (&grub_cryptodisk_list), 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 103b30633..fcacb23e8 100644 --- a/include/grub/cs5536.h +++ b/include/grub/cs5536.h @@ -77,6 +77,7 @@ #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 diff --git a/include/grub/datetime.h b/include/grub/datetime.h index c20fc8c36..a7154fa1a 100644 --- a/include/grub/datetime.h +++ b/include/grub/datetime.h @@ -46,7 +46,7 @@ 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); @@ -86,13 +86,13 @@ grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int32_t *nix) are bissextile*/ /* Convenience: let's have 3 consecutive non-bissextile years at the beginning of the epoch. So count from 1971 instead of 1970 */ - ret = SECPERYEAR + SECPERDAY; + ret = 2 * SECPERYEAR + SECPERDAY; /* Transform C divisions and modulos to mathematical ones */ - y4 = (datetime->year - 1971) / 4; - if (datetime->year < 1971) + y4 = (datetime->year - 1972) / 4; + if (datetime->year < 1972) y4--; - ay = datetime->year - 1971 - 4 * y4; + ay = datetime->year - 1972 - 4 * y4; ret += y4 * SECPER4YEARS; ret += ay * SECPERYEAR; @@ -125,4 +125,11 @@ grub_datetime2unixtime (const struct grub_datetime *datetime, grub_int32_t *nix) return 1; } +#if defined (__powerpc__) || defined (__sparc__) +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/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 867283494..d9afd5b7b 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -42,7 +42,7 @@ enum grub_disk_dev_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, }; @@ -51,6 +51,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 { @@ -61,7 +69,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); @@ -101,6 +110,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; @@ -133,9 +145,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 @@ -162,20 +175,14 @@ 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_mdraid09_init (void); diff --git a/include/grub/dl.h b/include/grub/dl.h index 5ce01199c..d5f009829 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -90,6 +90,9 @@ static const char grub_module_name_##name[] \ #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"; \ @@ -133,11 +136,12 @@ struct grub_dl Elf_Sym *symtab; void (*init) (struct grub_dl *mod); void (*fini) (void); -#ifdef __ia64__ +#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; @@ -173,10 +177,21 @@ void grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, grub_size_t *got); -#ifdef __ia64__ -#define GRUB_ARCH_DL_TRAMP_ALIGN 16 -#define GRUB_ARCH_DL_GOT_ALIGN 16 +#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 diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index ded03a1b3..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; @@ -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/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 9cedc3226..530e18c82 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -114,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 *) \ @@ -200,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); @@ -271,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/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 b44a573e1..b8c072761 100644 --- a/include/grub/emu/hostdisk.h +++ b/include/grub/emu/hostdisk.h @@ -21,6 +21,7 @@ #define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1 #include +#include void grub_util_biosdisk_init (const char *dev_map); void grub_util_biosdisk_fini (void); @@ -31,5 +32,16 @@ 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); +grub_err_t +grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat); +void grub_util_cryptodisk_print_uuid (grub_disk_t disk); +#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 fcf9da473..a9365f6a1 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -60,7 +60,7 @@ 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, ...); diff --git a/include/grub/env.h b/include/grub/env.h index c0107f16a..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); diff --git a/include/grub/err.h b/include/grub/err.h index 69bc6ec79..3a75f5698 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -56,7 +56,17 @@ typedef enum GRUB_ERR_IO, GRUB_ERR_ACCESS_DENIED, GRUB_ERR_EXTRACTOR, - GRUB_ERR_BUG + 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/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 3adb1706f..e08ac2e26 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -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); diff --git a/include/grub/fs.h b/include/grub/fs.h index 2c39332a9..dd274e151 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -25,6 +25,10 @@ #include #include +/* For embedding types. */ +#ifdef GRUB_UTIL +#include +#endif /* Forward declaration is required, because of mutual reference. */ struct grub_file; @@ -74,6 +78,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 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/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/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..376a18962 100644 --- a/include/grub/i386/pc/pxe.h +++ b/include/grub/i386/pc/pxe.h @@ -152,9 +152,9 @@ #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 @@ -162,8 +162,6 @@ #define GRUB_PXE_TFTP_PORT 69 -#define GRUB_PXE_VM_RFC1048 0x63825363L - #define GRUB_PXE_ERR_LEN 0xFFFFFFFF #ifndef ASM_FILE @@ -214,38 +212,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 +287,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/util/raid.h b/include/grub/i386/reboot.h similarity index 71% rename from include/grub/util/raid.h rename to include/grub/i386/reboot.h index 4da5eaaa8..c2716f3fa 100644 --- a/include/grub/util/raid.h +++ b/include/grub/i386/reboot.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) 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,11 +16,13 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_RAID_UTIL_HEADER -#define GRUB_RAID_UTIL_HEADER 1 +#ifndef GRUB_REBOOT_H +#define GRUB_REBOOT_H 1 + +#ifndef ASM_FILE + +extern grub_uint8_t grub_reboot_end[], grub_reboot_start[]; -#ifdef __linux__ -char** grub_util_raid_getmembers (const char *name); #endif -#endif /* ! GRUB_RAID_UTIL_HEADER */ +#endif diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h index 778049eef..b2fe900b6 100644 --- a/include/grub/i386/relocator.h +++ b/include/grub/i386/relocator.h @@ -48,6 +48,8 @@ struct grub_relocator16_state 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/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index 4c56cc20f..b84d75697 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 *); @@ -121,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, @@ -169,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, @@ -179,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 @@ -191,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/libgcc.h b/include/grub/libgcc.h index 19723fd23..7a433dc68 100644 --- a/include/grub/libgcc.h +++ b/include/grub/libgcc.h @@ -63,6 +63,12 @@ void EXPORT_FUNC (__divsi3) (void); # 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 diff --git a/include/grub/list.h b/include/grub/list.h index 75353010c..3dfb97ac6 100644 --- a/include/grub/list.h +++ b/include/grub/list.h @@ -54,11 +54,11 @@ grub_bad_type_cast_real (int line, const char *file) #define GRUB_AS_LIST(ptr) \ (GRUB_FIELD_MATCH (ptr, grub_list_t, next) ? \ - (grub_list_t) ptr : grub_bad_type_cast ()) + (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_list_t *) (void *) pptr : (grub_list_t *) grub_bad_type_cast ()) struct grub_named_list { @@ -73,12 +73,12 @@ void * EXPORT_FUNC(grub_named_list_find) (grub_named_list_t head, #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_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_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 @@ -106,12 +106,14 @@ grub_prio_list_remove (grub_prio_list_t *head, grub_prio_list_t item) ((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_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, 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 b962dfd6c..d77b88ff5 100644 --- a/include/grub/lvm.h +++ b/include/grub/lvm.h @@ -38,12 +38,14 @@ 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. */ + grub_disk_addr_t start; /* Sector number where the data area starts. */ struct grub_lvm_pv *next; }; struct grub_lvm_lv { char *name; + char *fullname; + char *compatname; unsigned int number; unsigned int segment_count; grub_uint64_t size; diff --git a/include/grub/mips/kernel.h b/include/grub/mips/kernel.h index d82d0a97d..07b08848d 100644 --- a/include/grub/mips/kernel.h +++ b/include/grub/mips/kernel.h @@ -16,15 +16,9 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_KERNEL_MACHINE_HEADER -#define GRUB_KERNEL_MACHINE_HEADER 1 +#ifndef GRUB_KERNEL_CPU_HEADER +#define GRUB_KERNEL_CPU_HEADER 1 #include -#ifndef ASM_FILE - -void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn)); - -#endif - #endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/include/grub/mips/loongson.h b/include/grub/mips/loongson.h index ce5eb5e3d..e6f0241f2 100644 --- a/include/grub/mips/loongson.h +++ b/include/grub/mips/loongson.h @@ -66,6 +66,7 @@ #define GRUB_CPU_LOONGSON_COP0_BADVADDR GRUB_CPU_REGISTER_WRAP($8) #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) diff --git a/include/grub/mips/loongson/ec.h b/include/grub/mips/loongson/ec.h index 62d1d33d9..3f8ff9931 100644 --- a/include/grub/mips/loongson/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/loongson/kernel.h b/include/grub/mips/loongson/kernel.h index 612221ed2..ba94e4331 100644 --- a/include/grub/mips/loongson/kernel.h +++ b/include/grub/mips/loongson/kernel.h @@ -23,7 +23,8 @@ #include #define GRUB_ARCH_MACHINE_YEELOONG 0 -#define GRUB_ARCH_MACHINE_FULOONG 1 +#define GRUB_ARCH_MACHINE_FULOONG2F 1 +#define GRUB_ARCH_MACHINE_FULOONG2E 2 #ifndef ASM_FILE diff --git a/include/grub/mips/loongson/pci.h b/include/grub/mips/loongson/pci.h index 3f828c2f8..57c7dd1fc 100644 --- a/include/grub/mips/loongson/pci.h +++ b/include/grub/mips/loongson/pci.h @@ -26,8 +26,6 @@ #define GRUB_LOONGSON_OHCI_PCIID 0x00351033 #define GRUB_LOONGSON_EHCI_PCIID 0x00e01033 -#define GRUB_LOONGSON_OHCI_GHOST_FUNCTION 4 -#define GRUB_LOONGSON_EHCI_GHOST_FUNCTION 5 #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/boot.h b/include/grub/mips/qemu_mips/at_keyboard.h similarity index 69% rename from include/grub/boot.h rename to include/grub/mips/qemu_mips/at_keyboard.h index 235774863..37cc625d1 100644 --- a/include/grub/boot.h +++ b/include/grub/mips/qemu_mips/at_keyboard.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2007 Free Software Foundation, Inc. + * 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 @@ -16,12 +16,10 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_BOOT_HEADER -#define GRUB_BOOT_HEADER 1 +#ifndef GRUB_MACHINE_AT_KEYBOARD_HEADER +#define GRUB_MACHINE_AT_KEYBOARD_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 KEYBOARD_REG_DATA 0xb4000060 +#define KEYBOARD_REG_STATUS 0xb4000064 -#endif /* ! GRUB_BOOT_HEADER */ +#endif diff --git a/include/grub/mips/qemu_mips/kernel.h b/include/grub/mips/qemu_mips/kernel.h index c08405e83..8b8b0149e 100644 --- a/include/grub/mips/qemu_mips/kernel.h +++ b/include/grub/mips/qemu_mips/kernel.h @@ -23,8 +23,7 @@ #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/misc.h b/include/grub/misc.h index da4bd4a7e..e1b13eeba 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,27 +262,6 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n) return (int) grub_tolower (*s1) - (int) grub_tolower (*s2); } -/* 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) -{ - grub_size_t grub_strlen (const char *s); - while (*input) - { - if (*input == ch) - { - grub_strcpy (output, with); - output += grub_strlen (with); - input++; - continue; - } - *output++ = *input++; - } - *output = '\0'; - return output; -} - 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); @@ -260,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 @@ -302,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) { @@ -337,12 +419,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 047006944..82b200c27 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -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..3913272eb 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,491 @@ #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; 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; + 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; 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; + 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_P (&grub_net_app_level_list), + 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/ia64/efi/kernel.h b/include/grub/net/ethernet.h similarity index 50% rename from include/grub/ia64/efi/kernel.h rename to include/grub/net/ethernet.h index ae75380f0..23a935e98 100644 --- a/include/grub/ia64/efi/kernel.h +++ b/include/grub/net/ethernet.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2007,2008,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,19 +16,26 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_KERNEL_HEADER -#define GRUB_MACHINE_KERNEL_HEADER 1 +#ifndef GRUB_NET_ETHERNET_HEADER +#define GRUB_NET_ETHERNET_HEADER 1 +#include +#include -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_MACHINE_PREFIX 0x8 +/* IANA Ethertype */ +typedef enum + { + GRUB_NET_ETHERTYPE_IP = 0x0800, + GRUB_NET_ETHERTYPE_ARP = 0x0806, + GRUB_NET_ETHERTYPE_IP6 = 0x86DD, + } grub_net_ethertype_t; -/* End of the data section. */ -#define GRUB_KERNEL_MACHINE_DATA_END 0x50 +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); -#ifndef ASM_FILE -/* The prefix which points to the directory where GRUB modules and its - configuration file are located. */ -extern char grub_prefix[]; -#endif - -#endif /* ! GRUB_MACHINE_KERNEL_HEADER */ +#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/ntfs.h b/include/grub/ntfs.h index e220fecf4..cf90ce110 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 (1024 >> 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 { @@ -120,8 +128,6 @@ struct grub_ntfs_bpb grub_uint32_t checksum; } __attribute__ ((packed)); -#define grub_ntfs_file grub_fshelp_node - struct grub_ntfs_attr { int flags; @@ -132,7 +138,7 @@ struct grub_ntfs_attr struct grub_ntfs_file *mft; }; -struct grub_fshelp_node +struct grub_ntfs_file { struct grub_ntfs_data *data; char *buf; @@ -174,13 +180,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 af724096d..75a46e128 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -19,39 +19,21 @@ #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 0xcd0 - -#define GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x730 - -/* 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_KERNEL_I386_PC_NO_REED_SOLOMON_PART 0x7e0 /* 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,40 +45,16 @@ /* 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 @@ -104,62 +62,31 @@ #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN 32 -#define GRUB_KERNEL_MIPS_LOONGSON_COMPRESSED_SIZE 0x8 -#define GRUB_KERNEL_MIPS_LOONGSON_UNCOMPRESSED_SIZE 0xc -#define GRUB_KERNEL_MIPS_LOONGSON_UNCOMPRESSED_ADDR 0x10 +#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_LOONGSON_TOTAL_MODULE_SIZE 0x08 -#define GRUB_KERNEL_MIPS_LOONGSON_PREFIX 0x0c -#define GRUB_KERNEL_MIPS_LOONGSON_PREFIX_END 0x54 #define GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR 0x80200000 #define GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN 32 -#define GRUB_KERNEL_MIPS_QEMU_MIPS_COMPRESSED_SIZE 0x8 -#define GRUB_KERNEL_MIPS_QEMU_MIPS_UNCOMPRESSED_SIZE 0xc -#define GRUB_KERNEL_MIPS_QEMU_MIPS_UNCOMPRESSED_ADDR 0x10 +#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 -#define GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX 0x0c -#define GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX_END 0x54 #define GRUB_KERNEL_MIPS_ARC_LINK_ADDR 0x8bd00000 #define GRUB_KERNEL_MIPS_ARC_LINK_ALIGN 32 -#define GRUB_KERNEL_MIPS_ARC_COMPRESSED_SIZE 0x8 -#define GRUB_KERNEL_MIPS_ARC_UNCOMPRESSED_SIZE 0xc -#define GRUB_KERNEL_MIPS_ARC_UNCOMPRESSED_ADDR 0x10 +#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_MIPS_ARC_PREFIX 0x0c -#define GRUB_KERNEL_MIPS_ARC_PREFIX_END 0x54 -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_I386_EFI_PREFIX 0x8 - -/* End of the data section. */ -#define GRUB_KERNEL_I386_EFI_PREFIX_END 0x50 - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_IA64_EFI_PREFIX 0x50 - -/* End of the data section. */ -#define GRUB_KERNEL_IA64_EFI_PREFIX_END 0xa0 - -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8 - -/* End of the data section. */ -#define GRUB_KERNEL_X86_64_EFI_PREFIX_END 0x50 - -#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 @@ -169,8 +96,10 @@ /* 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_LOONGSON_MOD_ALIGN 0x1 #define GRUB_KERNEL_MIPS_ARC_MOD_ALIGN 0x1 @@ -187,19 +116,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_UNCOMPRESSED_ADDR GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _UNCOMPRESSED_ADDR) -#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/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/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 index d5853639d..1eb43721a 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -42,6 +42,7 @@ struct grub_raid_array int number; /* The device number, taken from md_minor so we are consistent with the device name in Linux. */ + int became_readable_at; 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. */ 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..dfee69c62 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); diff --git a/include/grub/serial.h b/include/grub/serial.h index 41b720891..feaa5b1a7 100644 --- a/include/grub/serial.h +++ b/include/grub/serial.h @@ -96,6 +96,32 @@ 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) @@ -117,6 +143,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/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 4fd7a3a4b..89c1697d2 100644 --- a/include/grub/types.h +++ b/include/grub/types.h @@ -98,13 +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 PRIxGRUB_ADDR "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 PRIxGRUB_ADDR "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; @@ -114,8 +116,13 @@ 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_UINT_MAX 4294967295U + #if GRUB_CPU_SIZEOF_LONG == 8 # define GRUB_ULONG_MAX 18446744073709551615UL # define GRUB_LONG_MAX 9223372036854775807L @@ -126,15 +133,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; @@ -151,6 +152,18 @@ typedef grub_uint64_t grub_disk_addr_t; #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) @@ -199,6 +212,10 @@ 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 */ @@ -214,8 +231,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/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 bf4439599..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 { diff --git a/include/grub/video.h b/include/grub/video.h index 018994fde..352544c85 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -210,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, @@ -222,6 +282,7 @@ typedef enum grub_video_driver_id GRUB_VIDEO_DRIVER_BOCHS, GRUB_VIDEO_DRIVER_SDL, GRUB_VIDEO_DRIVER_SIS315PRO, + GRUB_VIDEO_DRIVER_RADEON_FULOONG2E, } grub_video_driver_id_t; typedef enum grub_video_adapter_prio @@ -312,6 +373,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; @@ -424,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); 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 index bee317e8a..8fc6dc5b5 100644 --- a/include/grub/zfs/dmu.h +++ b/include/grub/zfs/dmu.h @@ -88,6 +88,7 @@ typedef enum dmu_object_type { 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; diff --git a/include/grub/zfs/dsl_dir.h b/include/grub/zfs/dsl_dir.h index 41d77c790..6542a77fe 100644 --- a/include/grub/zfs/dsl_dir.h +++ b/include/grub/zfs/dsl_dir.h @@ -42,7 +42,9 @@ typedef struct dsl_dir_phys { grub_uint64_t dd_reserved; grub_uint64_t dd_props_zapobj; grub_uint64_t dd_deleg_zapobj; /* dataset permissions */ - grub_uint64_t dd_pad[20]; /* pad out to 256 bytes for good measure */ + 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 index a2b728d37..0845d1290 100644 --- a/include/grub/zfs/sa_impl.h +++ b/include/grub/zfs/sa_impl.h @@ -29,6 +29,9 @@ typedef struct sa_hdr_phys { } 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 index 22ee03b15..0e29fa44a 100644 --- a/include/grub/zfs/spa.h +++ b/include/grub/zfs/spa.h @@ -20,26 +20,24 @@ #ifndef GRUB_ZFS_SPA_HEADER #define GRUB_ZFS_SPA_HEADER 1 -typedef enum grub_zfs_endian - { - UNKNOWN_ENDIAN = -2, - LITTLE_ENDIAN = -1, - BIG_ENDIAN = 0 - } grub_zfs_endian_t; - -#define grub_zfs_to_cpu16(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu16(x) \ +#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) == BIG_ENDIAN) ? grub_cpu_to_be16(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) == BIG_ENDIAN) ? grub_be_to_cpu32(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) == BIG_ENDIAN) ? grub_cpu_to_be32(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) == BIG_ENDIAN) ? grub_be_to_cpu64(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) == BIG_ENDIAN) ? grub_cpu_to_be64(x) \ +#define grub_cpu_to_zfs64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? grub_cpu_to_be64(x) \ : grub_cpu_to_le64(x)) /* diff --git a/include/grub/zfs/zap_leaf.h b/include/grub/zfs/zap_leaf.h index 1ef654054..f2b7cb1da 100644 --- a/include/grub/zfs/zap_leaf.h +++ b/include/grub/zfs/zap_leaf.h @@ -69,7 +69,8 @@ typedef struct zap_leaf_phys { * with the ZAP_LEAF_CHUNK() macro. */ - grub_uint16_t l_hash[1]; + grub_uint16_t l_hash[0]; + grub_properly_aligned_t l_entries[0]; } zap_leaf_phys_t; typedef union zap_leaf_chunk { @@ -90,7 +91,7 @@ typedef union zap_leaf_chunk { { 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 { diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h index 057692573..e326c8b2f 100644 --- a/include/grub/zfs/zfs.h +++ b/include/grub/zfs/zfs.h @@ -24,11 +24,19 @@ #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 28ULL +#define SPA_VERSION 33ULL /* * The following are configuration names used in the nvlist describing a pool's @@ -112,12 +120,34 @@ 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 (char *nvlist, char *name); -char *grub_zfs_nvlist_lookup_nvlist (char *nvlist, char *name); -int grub_zfs_nvlist_lookup_uint64 (char *nvlist, char *name, +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 (char *nvlist, char *name, +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 (char *nvlist, char *name); +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/zio.h b/include/grub/zfs/zio.h index 797d4f9b3..b1c46da3a 100644 --- a/include/grub/zfs/zio.h +++ b/include/grub/zfs/zio.h @@ -30,7 +30,7 @@ typedef struct zio_eck { grub_uint64_t zec_magic; /* for validation, endianness */ zio_cksum_t zec_cksum; /* 256-bit checksum */ -} zio_eck_t; +} __attribute__ ((packed)) zio_eck_t; /* * Gang block headers are self-checksumming and contain an array @@ -65,6 +65,7 @@ enum zio_checksum { ZIO_CHECKSUM_FLETCHER_4, ZIO_CHECKSUM_SHA256, ZIO_CHECKSUM_ZILOG2, + ZIO_CHECKSUM_SHA256_MAC, ZIO_CHECKSUM_FUNCTIONS }; @@ -77,7 +78,16 @@ enum zio_compress { ZIO_COMPRESS_OFF, ZIO_COMPRESS_LZJB, ZIO_COMPRESS_EMPTY, - ZIO_COMPRESS_GZIP, + 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 }; diff --git a/include/grub/zfs/zio_checksum.h b/include/grub/zfs/zio_checksum.h index 0ef5a3ec7..e03c85a83 100644 --- a/include/grub/zfs/zio_checksum.h +++ b/include/grub/zfs/zio_checksum.h @@ -23,22 +23,6 @@ #ifndef _SYS_ZIO_CHECKSUM_H #define _SYS_ZIO_CHECKSUM_H -/* - * 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? */ - char *ci_name; /* descriptive name */ -} zio_checksum_info_t; - 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, diff --git a/po/Makefile.in.in b/po/Makefile.in.in index b0e7b8fa2..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) \ @@ -187,7 +187,7 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in $(srcdir)/POTFILES-shell --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; \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 8329fdf0a..1c718520b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,117 +1,534 @@ -# 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/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/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/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/raid.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/btrfs.c +./grub-core/fs/cpio.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/nilfs2.c +./grub-core/fs/ntfs.c +./grub-core/fs/ntfscomp.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/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/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/arc/datetime.c +./grub-core/lib/arg.c +./grub-core/lib/cmdline.c +./grub-core/lib/cmos_datetime.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/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/relocator.c +./grub-core/lib/ieee1275/cmos.c +./grub-core/lib/ieee1275/datetime.c +./grub-core/lib/ieee1275/halt.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/mips/relocator.c +./grub-core/lib/pbkdf2.c +./grub-core/lib/powerpc/relocator.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/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/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/ip.c +./grub-core/net/netbuff.c +./grub-core/net/net.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/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/ofconsole.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/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 +./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-pe2elf.c +./util/grub-probe.c +./util/grub-script-check.c +./util/grub-setup.c +./util/ieee1275/devicemap.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/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/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/deviceiter.c b/util/deviceiter.c index 30c18beea..208dcfdde 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) @@ -620,6 +640,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++) diff --git a/grub-core/kern/emu/getroot.c b/util/getroot.c similarity index 52% rename from grub-core/kern/emu/getroot.c rename to util/getroot.c index b1b4f188c..a4bc9f0af 100644 --- a/grub-core/kern/emu/getroot.c +++ b/util/getroot.c @@ -1,7 +1,7 @@ /* getroot.c - Get root device */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * 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 @@ -32,7 +32,13 @@ #include #include #include +#ifdef HAVE_LIMITS_H +#include +#endif #include +#include +#include +#include #ifdef HAVE_DEVICE_MAPPER # include @@ -50,11 +56,20 @@ # 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 @@ -102,12 +117,13 @@ xgetcwd (void) #ifdef __linux__ +#define ESCAPED_PATH_MAX (4 * PATH_MAX) struct mountinfo_entry { int id; int major, minor; - char enc_root[PATH_MAX], enc_path[PATH_MAX]; - char fstype[PATH_MAX], device[PATH_MAX]; + 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 @@ -117,6 +133,27 @@ struct mountinfo_entry 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) { @@ -153,6 +190,9 @@ grub_find_root_device_from_mountinfo (const char *dir, char **relroot) 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 @@ -237,7 +277,6 @@ grub_find_root_device_from_mountinfo (const char *dir, char **relroot) #endif /* __linux__ */ -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) static char * find_root_device_from_libzfs (const char *dir) { @@ -249,6 +288,7 @@ find_root_device_from_libzfs (const char *dir) if (! poolname) return NULL; +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) { zpool_handle_t *zpool; libzfs_handle_t *libzfs; @@ -283,7 +323,19 @@ find_root_device_from_libzfs (const char *dir) struct stat st; if (stat (device, &st) == 0) { - device = xstrdup (device); +#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; } @@ -292,6 +344,63 @@ find_root_device_from_libzfs (const char *dir) 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) @@ -299,7 +408,6 @@ find_root_device_from_libzfs (const char *dir) return device; } -#endif #ifdef __MINGW32__ @@ -358,7 +466,7 @@ grub_find_device (const char *dir, dev_t dev) if (S_ISLNK (st.st_mode)) { #ifdef __linux__ - if (strcmp (dir, "mapper") == 0) { + 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 @@ -431,7 +539,7 @@ grub_find_device (const char *dir, dev_t dev) continue; if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); + grub_util_error (_("cannot restore the original directory")); free (saved_cwd); closedir (dp); @@ -440,7 +548,7 @@ grub_find_device (const char *dir, dev_t dev) } if (chdir (saved_cwd) < 0) - grub_util_error ("cannot restore the original directory"); + grub_util_error (_("cannot restore the original directory")); free (saved_cwd); closedir (dp); @@ -558,17 +666,17 @@ grub_guess_root_device (const char *dir) &data, &data_len); if (num_ints < 1) - grub_util_error ("Storage info for `%s' does not include type", dir); + 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); + 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); + 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); + 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); + grub_util_error (_("Storage name for `%s' not NUL-terminated"), dir); os_dev = xmalloc (strlen ("/dev/") + data_len); memcpy (os_dev, "/dev/", strlen ("/dev/")); @@ -602,27 +710,36 @@ grub_guess_root_device (const char *dir) os_dev = grub_find_root_device_from_mountinfo (dir, NULL); #endif /* __linux__ */ -#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) if (!os_dev) os_dev = find_root_device_from_libzfs (dir); -#endif if (os_dev) { - if (stat (os_dev, &st) >= 0) - dev = st.st_rdev; - else - grub_util_error ("cannot stat `%s'", os_dev); - free (os_dev); - } - else - { - if (stat (dir, &st) >= 0) - dev = st.st_dev; - else - grub_util_error ("cannot stat `%s'", dir); + 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); @@ -637,85 +754,195 @@ grub_guess_root_device (const char *dir) return os_dev; } +#ifdef HAVE_DEVICE_MAPPER + static int -grub_util_is_lvm (const char *os_dev) +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; - uint32_t maj, min; - struct dm_tree_node *node = NULL; + struct dm_tree_node *node; const char *node_uuid; - struct stat st; + char *ret; - if (stat (os_dev, &st) < 0) - return 0; + if (!grub_util_open_dm (os_dev, &tree, &node)) + return NULL; - tree = dm_tree_create (); - if (! tree) - { - grub_printf ("Failed to create tree\n"); - 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); - 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); - return 0; - } 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 0; - } - if (strncmp (node_uuid, "LVM-", 4) != 0) - { - dm_tree_free (tree); - return 0; + return NULL; } + + ret = grub_strdup (node_uuid); + dm_tree_free (tree); - return 1; + + return ret; } -#else - return 1; -#endif /* HAVE_DEVICE_MAPPER */ +#endif + + return NULL; } -int -grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) +static enum grub_dev_abstraction_types +grub_util_get_dm_abstraction (const char *os_dev) { -#ifdef __linux__ +#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 - /* Check for LVM. */ - if (grub_util_is_lvm (os_dev)) - return GRUB_DEV_ABSTRACTION_LVM; +#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; } @@ -730,13 +957,14 @@ get_mdadm_uuid (const char *os_dev) if (pipe (mdadm_pipe) < 0) { - grub_util_warn ("Unable to create pipe for mdadm: %s", strerror (errno)); + 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)); + grub_util_warn (_("Unable to fork mdadm: %s"), strerror (errno)); else if (mdadm_pid == 0) { /* Child. */ @@ -767,7 +995,7 @@ get_mdadm_uuid (const char *os_dev) mdadm = fdopen (mdadm_pipe[0], "r"); if (! mdadm) { - grub_util_warn ("Unable to open stream from mdadm: %s", + grub_util_warn (_("Unable to open stream from mdadm: %s"), strerror (errno)); goto out; } @@ -801,32 +1029,236 @@ out: } #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 */ + grub_util_biosdisk_get_grub_dev (os_dev); + return; + } +} + 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 ("/dev/mapper/") - 1; + grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1; len = strlen (os_dev) - offset + 1; - grub_dev = xmalloc (len); + grub_dev = xmalloc (len + sizeof ("lvm/")); - for (i = 0; i < len; i++, offset++) - { - grub_dev[i] = os_dev[offset]; - if (os_dev[offset] == '-' && os_dev[offset + 1] == '-') - offset++; - } + 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') @@ -900,9 +1332,8 @@ grub_util_get_grub_dev (const char *os_dev) free (p); } else - grub_util_error ("unknown kind of RAID device `%s'", os_dev); + grub_util_error (_("unknown kind of RAID device `%s'"), os_dev); -#ifdef __linux__ { char *mdadm_name = get_mdadm_uuid (os_dev); struct stat st; @@ -927,9 +1358,8 @@ grub_util_get_grub_dev (const char *os_dev) free (mdadm_name); } } -#endif /* __linux__ */ - break; +#endif /* __linux__ */ default: /* GRUB_DEV_ABSTRACTION_NONE */ grub_dev = grub_util_biosdisk_get_grub_dev (os_dev); @@ -944,7 +1374,7 @@ 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); + grub_util_error (_("cannot stat `%s'"), blk_dev); if (S_ISBLK (st.st_mode)) return (blk_dev); @@ -958,10 +1388,258 @@ 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); + 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 f253a96f6..886155fe2 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -61,12 +62,15 @@ enum { CMD_CMP, CMD_HEX, CMD_CRC, - CMD_BLOCKLIST + 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)) @@ -110,7 +114,8 @@ 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) { @@ -178,7 +183,8 @@ 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); @@ -237,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; } @@ -298,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) @@ -327,6 +335,15 @@ 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_lvm_fini (); grub_mdraid09_fini (); grub_mdraid1x_fini (); @@ -341,6 +358,9 @@ fstest (int n, char **args) 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; @@ -359,6 +379,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++) @@ -387,13 +433,17 @@ static struct argp_option options[] = { {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} }; @@ -416,6 +466,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') @@ -450,6 +536,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) { @@ -472,14 +562,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; } @@ -490,6 +575,10 @@ 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; @@ -520,6 +609,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); @@ -555,6 +654,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); @@ -583,6 +683,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 bf654f741..789eb77c6 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -31,6 +31,7 @@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ platform=@platform@ host_os=@host_os@ +datarootdir=@datarootdir@ pkglibdir="${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}`" localedir="@datadir@/locale" @@ -73,7 +74,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 @@ -109,7 +110,7 @@ Install GRUB on your drive. EOF if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then cat <&2 @@ -331,6 +334,12 @@ if [ x"$platform" = xefi ]; then 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. @@ -444,6 +453,8 @@ for dir in "${localedir}"/*; do fi done +is_path_readable_by_grub "${grubdir}" || (echo "${grubdir}" not readable 1>&2 ; exit 1) + # 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 @@ -477,6 +488,18 @@ done # Device abstraction module, if any (lvm, raid). 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" @@ -510,11 +533,11 @@ if [ "x${devabstraction_module}" = "x" ] ; then # 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 ] || [ "x${grub_drive}" != "x${install_drive}" ] || ([ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${target_cpu}-${platform}" != x"sparc64-ieee1275" ]) ; then + 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" --device-map="${device_map}" --target=fs_uuid --device "${grub_device}"`" if [ "x${uuid}" = "x" ] ; then - if [ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${target_cpu}-${platform}" != x"sparc64-ieee1275" ]; then + 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 @@ -543,7 +566,7 @@ if [ "x${devabstraction_module}" = "x" ] ; then echo 'set prefix=($root)'"${relative_grubdir}" >> "${grubdir}/load.cfg" config_opt="-c ${grubdir}/load.cfg " modules="$modules search_fs_uuid" - elif [ "x$platform" = xefi ] || [ "x$platform" = xpc ]; then + else # we need to hardcode the partition number in the core image's prefix. if [ x"$grub_partition" = x ]; then prefix_drive="()" @@ -552,6 +575,13 @@ if [ "x${devabstraction_module}" = "x" ] ; then fi fi else + 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 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 513af47c1..aeabad976 100644 --- a/util/grub-menulst2cfg.c +++ b/util/grub-menulst2cfg.c @@ -24,6 +24,7 @@ #include #include #include +#include int main (int argc, char **argv) @@ -37,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; } @@ -46,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; } @@ -61,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; } diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index 1917da7a1..c408ccc1a 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -94,7 +94,7 @@ do esac done -. ${libdir}/grub/grub-mkconfig_lib +. ${libdir}/@PACKAGE@/grub-mkconfig_lib if [ "x$EUID" = "x" ] ; then EUID=`id -u` @@ -226,6 +226,8 @@ 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 \ @@ -241,6 +243,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 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 8303edd86..13897986b 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -63,10 +63,22 @@ is_path_readable_by_grub () # ... or if we can't figure out the abstraction module, for example if # memberlist fails on an LVM volume group. - if ${grub_probe} -t abstraction $path > /dev/null 2>&1 ; then : ; else + 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 } @@ -105,12 +117,6 @@ prepare_grub_to_access_device () { device="$1" - # Abstraction modules aren't auto-loaded. - 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 case "${module}" in @@ -121,11 +127,23 @@ prepare_grub_to_access_device () esac done + # Abstraction modules aren't auto-loaded. + abstraction="`"${grub_probe}" --device "${device}" --target=abstraction`" + for module in ${abstraction} ; do + echo "insmod ${module}" + done + 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=compatibility_hint`'" @@ -144,7 +162,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 @@ -154,21 +172,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 @@ -177,30 +195,30 @@ 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" + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" return "$?" } version_find_latest () { - local a="" + version_find_latest_a="" for i in "$@" ; do - if version_test_gt "$i" "$a" ; then - a="$i" + 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 @@ -214,9 +232,9 @@ gettext_quoted () { # remaining arguments to printf. This is a useful abbreviation and tends to # be easier to type. gettext_printf () { - local format="$1" + gettext_printf_format="$1" shift - printf "$(gettext_quoted "$format")" "$@" + printf "$(gettext_quoted "$gettext_printf_format")" "$@" } uses_abstraction () { 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 3108d4694..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++) @@ -866,7 +867,7 @@ write_font_pf2 (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); offset = 0; @@ -1063,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, @@ -1078,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++; } @@ -1124,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; } @@ -1140,10 +1141,10 @@ 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++) { @@ -1154,8 +1155,8 @@ main (int argc, char *argv[]) err = FT_New_Face (ft_lib, argv[optind], font_index, &ft_face); if (err) { - grub_printf ("can't open file %s, index %d: error %d", argv[optind], - font_index, err); + 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 @@ -1181,7 +1182,7 @@ main (int argc, char *argv[]) font_info.size = size; if (FT_Set_Pixel_Sizes (ft_face, size, size)) - grub_util_error ("can't set %dx%d font size", 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 9fc37df2b..ca8047df6 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -54,7 +55,7 @@ #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 @@ -67,26 +68,23 @@ struct image_target_desc IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_I386_IEEE1275, IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, - IMAGE_FULOONG_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC + 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_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; @@ -109,16 +107,12 @@ struct image_target_desc image_targets[] = .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, @@ -132,16 +126,12 @@ struct image_target_desc image_targets[] = .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, @@ -154,17 +144,13 @@ struct image_target_desc image_targets[] = .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 }, { @@ -173,17 +159,13 @@ struct image_target_desc image_targets[] = .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 }, { @@ -193,12 +175,10 @@ struct image_target_desc image_targets[] = .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 @@ -206,8 +186,6 @@ 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, }, @@ -218,16 +196,12 @@ struct image_target_desc image_targets[] = .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, @@ -241,16 +215,12 @@ struct image_target_desc image_targets[] = .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 }, { @@ -260,16 +230,12 @@ struct image_target_desc image_targets[] = .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 = EFI64_HEADER_SIZE, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .pe_target = GRUB_PE32_MACHINE_X86_64, .elf_target = EM_X86_64, }, @@ -280,16 +246,12 @@ struct image_target_desc image_targets[] = .bigendian = 0, .id = IMAGE_YEELOONG_FLASH, .flags = PLATFORM_FLAGS_DECOMPRESSORS, - .prefix = GRUB_KERNEL_MIPS_LOONGSON_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_LOONGSON_PREFIX_END, - .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .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_LOONGSON_LINK_ADDR, .elf_target = EM_MIPS, .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, @@ -297,21 +259,17 @@ struct image_target_desc image_targets[] = }, { .dirname = "mipsel-loongson", - .names = { "mipsel-fuloong-flash", NULL }, + .names = { "mipsel-fuloong2f-flash", NULL }, .voidp_sizeof = 4, .bigendian = 0, - .id = IMAGE_FULOONG_FLASH, + .id = IMAGE_FULOONG2F_FLASH, .flags = PLATFORM_FLAGS_DECOMPRESSORS, - .prefix = GRUB_KERNEL_MIPS_LOONGSON_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_LOONGSON_PREFIX_END, - .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .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_LOONGSON_LINK_ADDR, .elf_target = EM_MIPS, .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, @@ -320,21 +278,18 @@ struct image_target_desc image_targets[] = { .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, - .prefix = GRUB_KERNEL_MIPS_LOONGSON_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_LOONGSON_PREFIX_END, - .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .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_LOONGSON_LINK_ADDR, .elf_target = EM_MIPS, .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, @@ -347,16 +302,12 @@ struct image_target_desc image_targets[] = .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, @@ -370,16 +321,12 @@ struct image_target_desc image_targets[] = .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 }, { @@ -389,16 +336,12 @@ struct image_target_desc image_targets[] = .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 }, { @@ -408,16 +351,12 @@ struct image_target_desc image_targets[] = .bigendian = 0, .id = IMAGE_EFI, .flags = PLATFORM_FLAGS_NONE, - .prefix = GRUB_KERNEL_IA64_EFI_PREFIX, - .prefix_end = GRUB_KERNEL_IA64_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 = EFI64_HEADER_SIZE, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .pe_target = GRUB_PE32_MACHINE_IA64, .elf_target = EM_IA_64, }, @@ -429,16 +368,12 @@ struct image_target_desc image_targets[] = .id = IMAGE_MIPS_ARC, .flags = (PLATFORM_FLAGS_DECOMPRESSORS | PLATFORM_FLAGS_MODULES_BEFORE_KERNEL), - .prefix = GRUB_KERNEL_MIPS_ARC_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_ARC_PREFIX_END, - .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .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_ARC_LINK_ADDR, .elf_target = EM_MIPS, .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN, @@ -451,16 +386,48 @@ struct image_target_desc image_targets[] = .bigendian = 0, .id = IMAGE_LOONGSON_ELF, .flags = PLATFORM_FLAGS_DECOMPRESSORS, - .prefix = GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX_END, - .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .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, - .install_dos_part = TARGET_NO_FIELD, - .install_bsd_part = TARGET_NO_FIELD, .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, .elf_target = EM_MIPS, .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, @@ -473,16 +440,12 @@ struct image_target_desc image_targets[] = .bigendian = 1, .id = IMAGE_LOONGSON_ELF, .flags = PLATFORM_FLAGS_DECOMPRESSORS, - .prefix = GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX, - .prefix_end = GRUB_KERNEL_MIPS_QEMU_MIPS_PREFIX_END, - .raw_size = 0, .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, - .compressed_size = TARGET_NO_FIELD, - .kernel_image_size = TARGET_NO_FIELD, + .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_QEMU_MIPS_LINK_ADDR, .elf_target = EM_MIPS, .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, @@ -610,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]; @@ -623,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; @@ -664,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) @@ -691,8 +644,6 @@ compress_kernel_xz (char *kernel_img, size_t kernel_size, } *core_size -= strm.avail_out; - - *core_size += raw_size; } #endif @@ -701,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); @@ -751,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; @@ -763,6 +716,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], 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"); @@ -787,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)); @@ -802,10 +765,6 @@ 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)) @@ -897,39 +856,32 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], offset += config_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); - if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) - kernel_img = core_img + total_module_size; - else - kernel_img = core_img; - grub_util_info ("the core size is 0x%x", core_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_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 *) (kernel_img + image_target->kernel_image_size)) - = grub_host_to_target32 (kernel_size); - if (image_target->compressed_size != TARGET_NO_FIELD) - *((grub_uint32_t *) (kernel_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 *) (kernel_img + image_target->install_dos_part)) - = grub_host_to_target32 (-2); - *((grub_int32_t *) (kernel_img + image_target->install_bsd_part)) - = grub_host_to_target32 (-2); - } if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) { @@ -943,30 +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_LOONGSON_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_LOONGSON_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->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) - *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_LOONGSON_UNCOMPRESSED_ADDR)) - = grub_host_to_target_addr (image_target->link_addr - total_module_size); - else - *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_LOONGSON_UNCOMPRESSED_ADDR)) - = grub_host_to_target_addr (image_target->link_addr); + 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); @@ -993,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) @@ -1006,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); @@ -1014,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"); @@ -1251,7 +1230,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], rom_img = xmalloc (rom_size); memset (rom_img, 0, rom_size); - *((grub_int32_t *) (kernel_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR)) + *((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR)) = grub_host_to_target32 ((grub_uint32_t) -rom_size); memcpy (rom_img, core_img, core_size); @@ -1278,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); @@ -1302,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); @@ -1316,7 +1296,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], } break; case IMAGE_YEELOONG_FLASH: - case IMAGE_FULOONG_FLASH: + case IMAGE_FULOONG2F_FLASH: { char *rom_img; size_t rom_size; @@ -1335,7 +1315,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* None yet. */ - const grub_uint8_t fuloong_fwstart_good_hash[512 / 8] = + 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, @@ -1347,10 +1327,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], }; const grub_uint8_t *fwstart_good_hash; - if (image_target->id == IMAGE_FULOONG_FLASH) + if (image_target->id == IMAGE_FULOONG2F_FLASH) { - fwstart_good_hash = fuloong_fwstart_good_hash; - boot_path = grub_util_get_path (dir, "fwstart_fuloong.img"); + fwstart_good_hash = fuloong2f_fwstart_good_hash; + boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img"); } else { @@ -1367,11 +1347,11 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], 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"); + 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"); + grub_util_error (_("firmware image is too big")); rom_size = 512 * 1024; rom_img = xmalloc (rom_size); @@ -1389,6 +1369,28 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], core_size = rom_size; } break; + 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; @@ -1741,7 +1743,7 @@ main (int argc, char *argv[]) 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; @@ -1782,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': @@ -1819,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); } diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index 04501cb40..8de07747d 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -260,9 +260,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]\n\ -i, --input set input filename. Default is STDIN\n\ -o, --output set output filename. Default is STDOUT\n\ @@ -270,7 +270,7 @@ Usage: %s [OPTIONS]\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); } @@ -300,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'; } @@ -396,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) @@ -414,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); } @@ -479,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"); @@ -490,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 61a7ec3ad..e5a2172fd 100644 --- a/util/grub-mknetdir.in +++ b/util/grub-mknetdir.in @@ -29,6 +29,7 @@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ host_os=@host_os@ localedir=@datadir@/locale +datarootdir=@datarootdir@ pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" self=`basename $0` @@ -45,6 +46,12 @@ debug=no debug_image= subdir=`echo /boot/grub | sed ${transform}` 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. @@ -196,11 +203,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 @@ -209,13 +225,31 @@ 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 source "${override_dir}"/modinfo.sh diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c index dc2afdb6e..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,91 +157,42 @@ 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 { @@ -251,27 +201,24 @@ main (int argc, char *argv[]) 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 8367c4dd4..eff77088f 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -31,15 +31,15 @@ pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.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 @@ -129,7 +129,7 @@ do --xorriso) xorriso=`argument $option "$@"`; shift ;; --xorriso=*) - xorriso=`echo "${option}/" | sed 's/--xorriso=//'` ;; + xorriso=`echo "${option}" | sed 's/--xorriso=//'` ;; *) source="${source} ${option} $@"; break ;; @@ -275,7 +275,7 @@ 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 "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 @@ -296,11 +296,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..b0dbf9b0e --- /dev/null +++ b/util/grub-mkstandalone.in @@ -0,0 +1,190 @@ +#! /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@ +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..da7d604a2 --- /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_raid_fini (); + grub_raid_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 4b93faa05..51d41c9f0 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'}, diff --git a/util/grub-probe.c b/util/grub-probe.c index b486a82e5..e33a2ad10 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -36,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -56,6 +57,7 @@ enum { PRINT_DEVICE, PRINT_PARTMAP, PRINT_ABSTRACTION, + PRINT_CRYPTODISK_UUID, PRINT_HINT_STR, PRINT_BIOS_HINT, PRINT_IEEE1275_HINT, @@ -72,15 +74,49 @@ 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 @@ -222,6 +258,42 @@ print_full_name (const char *drive, grub_device_t dev) printf ("%s", drive); } +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_LVM_ID) + printf ("lvm "); + + 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 probe (const char *path, char *device_name) { @@ -233,19 +305,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) { @@ -255,7 +330,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) { @@ -266,7 +342,7 @@ 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_HINT_STR) { @@ -437,97 +513,29 @@ probe (const char *path, char *device_name) if (print == PRINT_ABSTRACTION) { - 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; - grub_disk_t raid_disk; - - raid_level = probe_raid_level (dev->disk); - if (raid_level >= 0) - { - is_raid = 1; - is_raid5 |= (raid_level == 5); - is_raid6 |= (raid_level == 6); - raid_disk = dev->disk; - } - - if ((is_lvm) && (dev->disk->dev->memberlist)) - list = dev->disk->dev->memberlist (dev->disk); - while (list) - { - raid_level = probe_raid_level (list->disk); - if (raid_level >= 0) - { - is_raid = 1; - is_raid5 |= (raid_level == 5); - is_raid6 |= (raid_level == 6); - raid_disk = list->disk; - } - - tmp = list->next; - free (list); - list = tmp; - } - - if (is_raid) - { - printf ("raid "); - if (is_raid5) - printf ("raid5rec "); - if (is_raid6) - printf ("raid6rec "); - if (raid_disk->dev->raidname) - printf ("%s ", raid_disk->dev->raidname (raid_disk)); - } - - if (is_lvm) - printf ("lvm "); - + 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); - - /* 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; - - 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) { @@ -537,7 +545,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); @@ -548,10 +556,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); } @@ -581,23 +589,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)\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); @@ -649,6 +657,8 @@ 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, "hints_string")) print = PRINT_HINT_STR; else if (!strcmp (optarg, "bios_hints")) @@ -691,13 +701,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); } @@ -708,6 +718,7 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_gcry_init_all (); grub_lvm_fini (); grub_mdraid09_fini (); @@ -725,6 +736,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 2d1b31c9a..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); } @@ -157,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 @@ -193,7 +193,7 @@ main (int argc, char *argv[]) if (found_input && script == 0) { - fprintf (stderr, "error: line no: %u\n", lineno); + fprintf (stderr, _("error: line no: %u\n"), lineno); return 1; } diff --git a/util/grub-setup.c b/util/grub-setup.c index 7d47fa654..8965143c5 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 @@ -50,6 +49,7 @@ #include "progname.h" #include #include +#include #define _GNU_SOURCE 1 #include @@ -101,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; @@ -283,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 @@ -408,37 +364,59 @@ setup (const char *dir, free (tmp_img); - if (! dest_partmap) + if (! dest_partmap && ! fs) { 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 || fs) + if (multiple_partmaps || (dest_partmap && 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; } - if (!dest_partmap->embed) + if (dest_partmap && !dest_partmap->embed) { - grub_util_warn ("Partition style '%s' doesn't support embeding", + 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 (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) @@ -448,7 +426,7 @@ setup (const char *dir, block--; if ((char *) block <= core_img) - grub_util_error ("No terminator in the core image"); + grub_util_error (_("No terminator in the core image")); } save_first_sector (sectors[0] + grub_partition_get_start (container), @@ -470,10 +448,14 @@ setup (const char *dir, + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY) = grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size); + void *tmp = xmalloc (core_size); + grub_memcpy (tmp, core_img, core_size); 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, 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; @@ -608,7 +590,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) @@ -669,8 +651,7 @@ 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)); grub_util_biosdisk_flush (root_dev->disk); grub_util_biosdisk_flush (dest_dev->disk); @@ -894,6 +875,7 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_gcry_init_all (); grub_lvm_fini (); grub_mdraid09_fini (); @@ -954,10 +936,12 @@ main (int argc, char *argv[]) arguments.dir ? : DEFAULT_DIRECTORY); } -#ifdef __linux__ +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) if (grub_util_lvm_isvolume (root_dev)) must_embed = 1; +#endif +#ifdef __linux__ if (root_dev[0] == 'm' && root_dev[1] == 'd' && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/')) { @@ -972,12 +956,12 @@ main (int argc, char *argv[]) int i; if (arguments.device[0] == '/') - devicelist = grub_util_raid_getmembers (arguments.device); + devicelist = grub_util_raid_getmembers (arguments.device, 1); else { char *devname; devname = xasprintf ("/dev/%s", dest_dev); - devicelist = grub_util_raid_getmembers (dest_dev); + devicelist = grub_util_raid_getmembers (dest_dev, 1); free (devname); } diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 9da1511f5..54012f854 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -25,7 +25,7 @@ libdir=@libdir@ locale_dir=`echo ${GRUB_PREFIX}/locale | sed ${transform}` grub_lang=`echo $LANG | cut -d . -f 1` -. ${libdir}/grub/grub-mkconfig_lib +. ${libdir}/@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 diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index 8c54eab97..d04b0a4fe 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -20,7 +20,8 @@ set -e prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +datarootdir=@datarootdir@ +. ${libdir}/@PACKAGE@/grub-mkconfig_lib CLASS="--class gnu --class os" diff --git a/util/grub.d/10_illumos.in b/util/grub.d/10_illumos.in new file mode 100644 index 000000000..2b87dfa4f --- /dev/null +++ b/util/grub.d/10_illumos.in @@ -0,0 +1,54 @@ +#! /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@ +bindir=@bindir@ +libdir=@libdir@ +datarootdir=@datarootdir@ +. ${libdir}/@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 3600c74f9..a1b86b82b 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 @@ -21,7 +21,8 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +datarootdir=@datarootdir@ +. ${libdir}/@PACKAGE@/grub-mkconfig_lib export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@localedir@ @@ -98,6 +99,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 @@ -153,7 +160,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} diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index 1d1eb403f..fe4f0e730 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -21,7 +21,8 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +datarootdir=@datarootdir@ +. ${libdir}/@PACKAGE@/grub-mkconfig_lib export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@localedir@ @@ -155,7 +156,7 @@ 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" \ diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in index ffd31ad93..8c232b01b 100644 --- a/util/grub.d/10_netbsd.in +++ b/util/grub.d/10_netbsd.in @@ -21,7 +21,8 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +datarootdir=@datarootdir@ +. ${libdir}/@PACKAGE@/grub-mkconfig_lib export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@localedir@ diff --git a/util/grub.d/10_windows.in b/util/grub.d/10_windows.in index fd068dd2d..20fd4e044 100644 --- a/util/grub.d/10_windows.in +++ b/util/grub.d/10_windows.in @@ -20,7 +20,8 @@ set -e prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +datarootdir=@datarootdir@ +. ${libdir}/@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 083391c40..2f1b4af88 100644 --- a/util/grub.d/20_linux_xen.in +++ b/util/grub.d/20_linux_xen.in @@ -21,7 +21,8 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +datarootdir=@datarootdir@ +. ${libdir}/@PACKAGE@/grub-mkconfig_lib export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR=@localedir@ diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index d9d4b0a96..c0b5d7cd7 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -21,7 +21,7 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +. ${libdir}/@PACKAGE@/grub-mkconfig_lib if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then exit 0 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 1a433345d..20a571191 100644 --- a/util/ieee1275/ofpath.c +++ b/util/ieee1275/ofpath.c @@ -23,6 +23,7 @@ #include #include #include +#include #endif #include @@ -53,6 +54,7 @@ grub_util_error (const char *fmt, ...) exit (1); } +#define _(x) x #endif static void @@ -106,7 +108,7 @@ find_obppath(char *of_path, const char *sysfs_path_orig) { kill_trailing_dir(sysfs_path); if (!strcmp(sysfs_path, "/sys")) - grub_util_error("'obppath' not found in parent dirs of %s", + grub_util_error(_("'obppath' not found in parent dirs of %s"), sysfs_path_orig); continue; } @@ -131,12 +133,12 @@ block_device_get_sysfs_path_and_link(const char *devicenode, snprintf(sysfs_path, sysfs_path_len, "/sys/block/%s", devicenode); if (!realpath (sysfs_path, rpath)) - grub_util_error ("cannot get the real path of `%s'", sysfs_path); + grub_util_error (_("cannot get the real path of `%s'"), sysfs_path); strcat(rpath, "/device"); if (!realpath (rpath, sysfs_path)) - grub_util_error ("cannot get the real path of `%s'", rpath); + grub_util_error (_("cannot get the real path of `%s'"), rpath); free (rpath); } @@ -247,12 +249,12 @@ vendor_is_ATA(const char *path) snprintf(buf, PATH_MAX, "%s/vendor", path); fd = open(buf, 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); 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); @@ -288,7 +290,7 @@ check_sas (char *sysfs_path, int *tgt) 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,6 +299,7 @@ check_sas (char *sysfs_path, int *tgt) free (path); free (p); + close (fd); } static void @@ -375,7 +378,7 @@ grub_util_devname_to_ofpath (const char *devname) 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); + grub_util_error (_("cannot get the real path of `%s'"), devname); device = get_basename (name_buf); devnode = strip_trailing_digits (name_buf); @@ -397,7 +400,7 @@ grub_util_devname_to_ofpath (const char *devname) New models have no floppy at all. */ strcpy (ofpath, "floppy"); else - grub_util_error ("unknown device type %s\n", device); + grub_util_error (_("unknown device type %s\n"), device); free (devnode); free (devicenode); @@ -413,12 +416,13 @@ 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); + free (of_path); return 0; } diff --git a/util/import_gcry.py b/util/import_gcry.py index b2a0a5451..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,11 +100,23 @@ 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 ("#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") @@ -103,6 +127,7 @@ for cipher_file in cipher_files: skip = False skip2 = False ismd = False + iscipher = False iscryptostart = False iscomma = False isglue = False @@ -114,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 @@ -132,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) @@ -157,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: @@ -169,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: @@ -181,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 () @@ -249,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) @@ -283,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") @@ -300,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 () @@ -329,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/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/raid.c b/util/raid.c index a6aa5f95e..8de5fbac0 100644 --- a/util/raid.c +++ b/util/raid.c @@ -21,7 +21,6 @@ #ifdef __linux__ #include #include -#include #include #include @@ -34,9 +33,10 @@ #include #include #include +#include char ** -grub_util_raid_getmembers (const char *name) +grub_util_raid_getmembers (const char *name, int bootable) { int fd, ret, i, j; char **devicelist; @@ -47,19 +47,26 @@ grub_util_raid_getmembers (const char *name) fd = open (name, O_RDONLY); if (fd == -1) - grub_util_error ("can't open %s: %s", name, strerror (errno)); + 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 *)); @@ -68,7 +75,7 @@ grub_util_raid_getmembers (const 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)) { @@ -80,6 +87,8 @@ grub_util_raid_getmembers (const 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 index 998452e67..430ce1308 100644 --- a/util/update-grub_lib.in +++ b/util/update-grub_lib.in @@ -18,6 +18,6 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ -. ${libdir}/grub/grub-mkconfig_lib +. ${libdir}/@PACKAGE@/grub-mkconfig_lib grub_warn "update-grub_lib is deprecated, use grub-mkconfig_lib instead"