]> git.proxmox.com Git - grub2.git/commitdiff
merge mainline into ahci
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 24 Dec 2010 15:16:01 +0000 (16:16 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 24 Dec 2010 15:16:01 +0000 (16:16 +0100)
28 files changed:
1  2 
grub-core/Makefile.core.def
grub-core/commands/crc.c
grub-core/commands/hdparm.c
grub-core/commands/i386/pc/vbeinfo.c
grub-core/commands/i386/pc/vbetest.c
grub-core/disk/ahci.c
grub-core/disk/ata.c
grub-core/disk/pata.c
grub-core/disk/scsi.c
grub-core/disk/usbms.c
grub-core/efiemu/runtime/efiemu.sh
grub-core/gnulib/alloca.h
grub-core/gnulib/argp-version-etc.c
grub-core/gnulib/argp-version-etc.h
grub-core/gnulib/fnmatch.h
grub-core/gnulib/getopt.h
grub-core/kern/disk.c
grub-core/kern/i386/ieee1275/init.c
grub-core/kern/i386/loader.S
grub-core/kern/i386/misc.S
grub-core/lib/crc.c
grub-core/loader/i386/bsd_helper.S
grub-core/loader/i386/bsd_trampoline.S
grub-core/loader/i386/efi/linux.c
grub-core/loader/i386/ieee1275/linux.c
grub-core/loader/i386/linux_trampoline.S
include/grub/disk.h
include/grub/scsi.h

index 0000000000000000000000000000000000000000,37c0ce9702a95ce77f78174ff5ca47452d13bf92..dde945412111634f48edb67322cce18380356b3c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1517 +1,1523 @@@
 -  name = ata_pthru;
 -  common = disk/ata_pthru.c;
+ AutoGen definitions Makefile.tpl;
+ script = {
+   installdir = noinst;
+   name = gensyminfo.sh;
+   common = gensyminfo.sh.in;
+ };
+ script = {
+   installdir = noinst;
+   name = genmod.sh;
+   common = genmod.sh.in;
+ };
+ kernel = {
+   name = kernel;
+   nostrip = emu;
+   emu_ldflags              = '-Wl,-r,-d';
+   x86_efi_ldflags          = '-Wl,-r,-d';
+   x86_efi_stripflags       = '--strip-unneeded -K start -R .note -R .comment';
+   i386_pc_ldflags          = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags          = '$(TARGET_IMG_BASE_LDOPT),0x8200';
+   i386_qemu_ldflags        = '$(TARGET_IMG_LDFLAGS)';
+   i386_qemu_ldflags        = '$(TARGET_IMG_BASE_LDOPT),0x8200';
+   ldadd = '$(LDADD_KERNEL)';
+   i386_coreboot_ldflags    = '-Wl,-Ttext=0x8200';
+   i386_multiboot_ldflags   = '-Wl,-Ttext=0x8200';
+   i386_ieee1275_ldflags    = '-Wl,-Ttext=0x10000';
+   mips_yeeloong_ldflags    = '-Wl,-Ttext,0x80200000';
+   powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000';
+   sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400';
+   mips_yeeloong_cppflags = '-DUSE_ASCII_FAILBACK';
+   i386_qemu_cppflags     = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+   emu_cflags = '$(CFLAGS_GNULIB)';
+   emu_cppflags = '$(CPPFLAGS_GNULIB)';
+   i386_pc_startup = kern/i386/pc/startup.S;
+   i386_efi_startup = kern/i386/efi/startup.S;
+   x86_64_efi_startup = kern/x86_64/efi/startup.S;
+   i386_qemu_startup = kern/i386/qemu/startup.S;
+   i386_ieee1275_startup = kern/i386/ieee1275/startup.S;
+   i386_coreboot_startup = kern/i386/coreboot/startup.S;
+   i386_multiboot_startup = kern/i386/coreboot/startup.S;
+   mips_yeeloong_startup = kern/mips/startup.S;
+   sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S;
+   powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S;
+   common = kern/command.c;
+   common = kern/corecmd.c;
+   common = kern/device.c;
+   common = kern/disk.c;
+   common = kern/dl.c;
+   common = kern/env.c;
+   common = kern/err.c;
+   common = kern/file.c;
+   common = kern/fs.c;
+   common = kern/list.c;
+   common = kern/main.c;
+   common = kern/misc.c;
+   common = kern/parser.c;
+   common = kern/partition.c;
+   common = kern/rescue_parser.c;
+   common = kern/rescue_reader.c;
+   common = kern/term.c;
+   noemu = kern/mm.c;
+   noemu = kern/time.c;
+   noemu = kern/generic/millisleep.c;
+   noemu_nodist = symlist.c;
+   i386_pc = kern/generic/rtc_get_time_ms.c;
+   x86_efi = kern/generic/rtc_get_time_ms.c;
+   i386_qemu = kern/generic/rtc_get_time_ms.c;
+   i386_coreboot = kern/generic/rtc_get_time_ms.c;
+   i386_multiboot = kern/generic/rtc_get_time_ms.c;
+   mips_yeeloong = kern/generic/rtc_get_time_ms.c;
+   ieee1275 = disk/ieee1275/ofdisk.c;
+   ieee1275 = kern/ieee1275/cmain.c;
+   ieee1275 = kern/ieee1275/ieee1275.c;
+   ieee1275 = kern/ieee1275/mmap.c;
+   ieee1275 = kern/ieee1275/openfw.c;
+   ieee1275 = term/ieee1275/ofconsole.c;
+   terminfoinkernel = term/terminfo.c;
+   terminfoinkernel = term/tparm.c;
+   terminfoinkernel = commands/extcmd.c;
+   terminfoinkernel = lib/arg.c;
+   i386 = kern/i386/dl.c;
+   i386_coreboot_multiboot_qemu = kern/i386/coreboot/init.c;
+   i386_coreboot_multiboot_qemu = term/i386/pc/vga_text.c;
+   i386_coreboot_multiboot_qemu = term/i386/vga_common.c;
+   i386_pc = term/i386/vga_common.c;
+   x86 = kern/i386/pit.c;
+   x86_efi = disk/efi/efidisk.c;
+   x86_efi = kern/efi/efi.c;
+   x86_efi = kern/efi/init.c;
+   x86_efi = kern/efi/mm.c;
+   x86_efi = kern/i386/efi/init.c;
+   x86_efi = term/efi/console.c;
+   i386_efi = kern/i386/tsc.c;
+   x86_64_efi = kern/i386/tsc.c;
+   x86_64_efi = kern/x86_64/dl.c;
+   x86_64_efi = kern/x86_64/efi/callwrap.S;
+   i386_pc = kern/i386/pc/init.c;
+   i386_pc = kern/i386/pc/mmap.c;
+   i386_pc = kern/i386/tsc.c;
+   i386_pc = term/i386/pc/console.c;
+   i386_qemu = bus/pci.c;
+   i386_qemu = kern/i386/qemu/init.c;
+   i386_qemu = kern/i386/qemu/mmap.c;
+   i386_qemu = kern/i386/tsc.c;
+   i386_coreboot = kern/i386/coreboot/mmap.c;
+   i386_coreboot = kern/i386/tsc.c;
+   i386_multiboot = kern/i386/multiboot_mmap.c;
+   i386_multiboot = kern/i386/tsc.c;
+   i386_ieee1275 = kern/ieee1275/init.c;
+   mips_yeeloong = term/ns8250.c;
+   mips_yeeloong = bus/bonito.c;
+   mips_yeeloong = bus/cs5536.c;
+   mips_yeeloong = bus/pci.c;
+   mips_yeeloong = kern/mips/cache.S;
+   mips_yeeloong = kern/mips/dl.c;
+   mips_yeeloong = kern/mips/init.c;
+   mips_yeeloong = kern/mips/yeeloong/init.c;
+   mips_yeeloong = term/at_keyboard.c;
+   mips_yeeloong = term/serial.c;
+   mips_yeeloong = video/sm712.c;
+   extra_dist = video/sm712_init.c;
+   mips_yeeloong = 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;
+   emu = kern/emu/console.c;
+   emu = kern/emu/getroot.c;
+   emu = kern/emu/hostdisk.c;
+   emu = kern/emu/hostfs.c;
+   emu = kern/emu/main.c;
+   emu = kern/emu/misc.c;
+   emu = kern/emu/mm.c;
+   emu = kern/emu/time.c;
+   videoinkernel = term/gfxterm.c;
+   videoinkernel = font/font.c;
+   videoinkernel = font/font_cmd.c;
+   videoinkernel = io/bufio.c;
+   videoinkernel = video/bitmap.c;
+   videoinkernel = video/bitmap_scale.c;
+   videoinkernel = video/fb/fbblit.c;
+   videoinkernel = video/fb/fbfill.c;
+   videoinkernel = video/fb/fbutil.c;
+   videoinkernel = video/fb/video_fb.c;
+   videoinkernel = video/video.c;
+   videoinkernel = commands/boot.c;
+   extra_dist = kern/i386/realmode.S;
+   extra_dist = kern/i386/pc/lzma_decode.S;
+   extra_dist = kern/mips/cache_flush.S;
+ };
+ program = {
+   name = grub-emu;
+   mansection = 1;
+   emu = kern/emu/full.c;
+   emu_nodist = grub_emu_init.c;
+   ldadd = 'kernel.img$(EXEEXT)';
+   ldadd = '$(MODULE_FILES)';
+   ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)';
+   enable = emu;
+ };
+ program = {
+   name = grub-emu-lite;
+   emu = kern/emu/lite.c;
+   emu_nodist = symlist.c;
+   ldadd = 'kernel.img$(EXEEXT)';
+   ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)';
+   enable = emu;
+ };
+ image = {
+   name = boot;
+   i386_pc = boot/i386/pc/boot.S;
+   i386_qemu = boot/i386/qemu/boot.S;
+   sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S;
+   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+   i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)';
+   i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+   i386_qemu_ccasflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)';
+   sparc64_ieee1275_objcopyflags = '-O a.out-sunos-big';
+   sparc64_ieee1275_ldflags = ' -Wl,-Ttext=0x4000';
+   objcopyflags = '-O binary';
+   enable = i386_pc;
+   enable = i386_qemu;
+   enable = sparc64_ieee1275;
+ };
+ image = {
+   name = cdboot;
+   i386_pc = boot/i386/pc/cdboot.S;
+   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+   objcopyflags = '-O binary';
+   enable = i386_pc;
+ };
+ image = {
+   name = pxeboot;
+   i386_pc = boot/i386/pc/pxeboot.S;
+   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00';
+   objcopyflags = '-O binary';
+   enable = i386_pc;
+ };
+ image = {
+   name = diskboot;
+   i386_pc = boot/i386/pc/diskboot.S;
+   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8000';
+   sparc64_ieee1275 = boot/sparc64/ieee1275/diskboot.S;
+   sparc64_ieee1275_ldflags = '-Wl,-Ttext=0x4200';
+   objcopyflags = '-O binary';
+   enable = i386_pc;
+   enable = sparc64_ieee1275;
+ };
+ image = {
+   name = lnxboot;
+   i386_pc = boot/i386/pc/lnxboot.S;
+   i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x6000';
+   objcopyflags = '-O binary';
+   enable = i386_pc;
+ };
+ image = {
+   name = xz_decompress;
+   mips = boot/mips/startup_raw.S;
+   common = boot/decompressor/minilib.c;
+   common = boot/decompressor/xz.c;
+   common = lib/xzembed/xz_dec_bcj.c;
+   common = lib/xzembed/xz_dec_lzma2.c;
+   common = lib/xzembed/xz_dec_stream.c;
+   cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
+   mips_cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000';
+   objcopyflags = '-O binary';
+   ldflags = '-static-libgcc -Wl,-Ttext,0x80100000';
+   ldadd = '-lgcc';
+   cflags = '-static-libgcc';
+   enable = mips;
+ };
+ image = {
+   name = none_decompress;
+   mips = boot/mips/startup_raw.S;
+   common = boot/decompressor/none.c;
+   mips_cppflags = '-DGRUB_EMBED_DECOMPRESSOR=1 -DGRUB_MACHINE_LINK_ADDR=0x80200000';
+   objcopyflags = '-O binary';
+   ldflags = '-static-libgcc -Wl,-Ttext,0x80100000';
+   ldadd = '-lgcc';
+   cflags = '-static-libgcc';
+   enable = mips;
+ };
+ image = {
+   name = fwstart;
+   mips_yeeloong = boot/mips/yeeloong/fwstart.S;
+   objcopyflags = '-O binary';
+   enable = mips_yeeloong;
+ };
+ module = {
+   name = trig;
+   common_nodist = trigtables.c;
+   extra_dist = gentrigtables.c;
+ };
+ module = {
+   name = cs5536;
+   x86 = bus/cs5536.c;
+   enable = x86;
+ };
+ module = {
+   name = libusb;
+   emu = bus/usb/emu/usb.c;
+   enable = emu;
+   condition = COND_GRUB_EMU_USB;
+ };
+ module = {
+   name = lsspd;
+   mips_yeeloong = commands/mips/yeeloong/lsspd.c;
+   enable = mips_yeeloong;
+ };
+ module = {
+   name = usb;
+   common = bus/usb/usb.c;
+   noemu = bus/usb/usbtrans.c;
+   noemu = bus/usb/usbhub.c;
+   enable = emu;
+   enable = usb;
+   emu_condition = COND_GRUB_EMU_USB;
+ };
+ module = {
+   name = usbserial_common;
+   common = bus/usb/serial/common.c;
+   enable = usb;
+ };
+ module = {
+   name = usbserial_pl2303;
+   common = bus/usb/serial/pl2303.c;
+   enable = usb;
+ };
+ module = {
+   name = usbserial_ftdi;
+   common = bus/usb/serial/ftdi.c;
+   enable = usb;
+ };
+ module = {
+   name = uhci;
+   common = bus/usb/uhci.c;
+   enable = x86;
+ };
+ module = {
+   name = ohci;
+   common = bus/usb/ohci.c;
+   enable = pci;
+ };
+ module = {
+   name = pci;
+   noemu = bus/pci.c;
+   emu = bus/emu/pci.c;
+   emu = commands/lspci.c;
+   enable = emu;
+   enable = i386_pc;
+   enable = x86_efi;
+   enable = i386_ieee1275;
+   enable = i386_coreboot;
+   enable = i386_multiboot;
+   emu_condition = COND_GRUB_EMU_PCI;
+ };
+ library = {
+   name = libgnulib.a;
+   common = gnulib/regex.c;
+   cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
+ };
+ module = {
+   name = cmostest;
+   common = commands/i386/cmostest.c;
+   enable = cmos;
+ };
+ module = {
+   name = iorw;
+   common = commands/iorw.c;
+   enable = x86;
+ };
+ module = {
+   name = regexp;
+   common = commands/regexp.c;
+   common = commands/wildcard.c;
+   ldadd = libgnulib.a;
+   cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+   cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
+ };
+ module = {
+   name = acpi;
+   common = commands/acpi.c;
+   x86_efi = commands/efi/acpi.c;
+   i386_pc = commands/i386/pc/acpi.c;
+   i386_coreboot = commands/i386/pc/acpi.c;
+   i386_multiboot = commands/i386/pc/acpi.c;
+   enable = x86_efi;
+   enable = i386_pc;
+   enable = i386_coreboot;
+   enable = i386_multiboot;
+ };
+ module = {
+   name = lsacpi;
+   common = commands/lsacpi.c;
+   enable = x86_efi;
+   enable = i386_pc;
+   enable = i386_coreboot;
+   enable = i386_multiboot;
+ };
+ module = {
+   name = lsefisystab;
+   common = commands/efi/lsefisystab.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = lssal;
+   common = commands/efi/lssal.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = lsefimmap;
+   common = commands/efi/lsefimmap.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = blocklist;
+   common = commands/blocklist.c;
+ };
+ module = {
+   name = boot;
+   common = commands/boot.c;
+   i386_pc = lib/i386/pc/biosnum.c;
+   enable = videomodules;
+ };
+ module = {
+   name = cat;
+   common = commands/cat.c;
+ };
+ module = {
+   name = cmp;
+   common = commands/cmp.c;
+ };
+ module = {
+   name = configfile;
+   common = commands/configfile.c;
+ };
+ module = {
+   name = cpuid;
+   x86 = commands/i386/cpuid.c;
+   enable = x86;
+ };
+ module = {
+   name = date;
+   common = commands/date.c;
+ };
+ module = {
+   name = drivemap;
+   i386_pc = commands/i386/pc/drivemap.c;
+   i386_pc = commands/i386/pc/drivemap_int13h.S;
+   enable = i386_pc;
+ };
+ module = {
+   name = echo;
+   common = commands/echo.c;
+ };
+ module = {
+   name = extcmd;
+   common = commands/extcmd.c;
+   common = lib/arg.c;
+   enable = terminfomodule;
+ };
+ module = {
+   name = fixvideo;
+   x86_efi = commands/efi/fixvideo.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = gptsync;
+   common = commands/gptsync.c;
+ };
+ module = {
+   name = halt;
+   nopc = commands/halt.c;
+   i386_pc = commands/i386/pc/halt.c;
+   i386_pc = commands/acpihalt.c;
+   i386_coreboot = commands/acpihalt.c;
+   i386_multiboot = commands/acpihalt.c;
+   x86_efi = commands/acpihalt.c;
+   i386_multiboot = lib/i386/halt.c;
+   i386_coreboot = lib/i386/halt.c;
+   i386_qemu = lib/i386/halt.c;
+   x86_efi = lib/efi/halt.c;
+   ieee1275 = lib/ieee1275/halt.c;
+   emu = lib/emu/halt.c;
+ };
+ module = {
+   name = hashsum;
+   common = commands/hashsum.c;
+ };
+ module = {
+   name = hdparm;
+   common = commands/hdparm.c;
+   common = lib/hexdump.c;
+   enable = pci;
+ };
+ module = {
+   name = help;
+   common = commands/help.c;
+ };
+ module = {
+   name = hexdump;
+   common = commands/hexdump.c;
+   common = lib/hexdump.c;
+ };
+ module = {
+   name = keystatus;
+   common = commands/keystatus.c;
+ };
+ module = {
+   name = loadbios;
+   x86_efi = commands/efi/loadbios.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = loadenv;
+   common = commands/loadenv.c;
+   common = lib/envblk.c;
+ };
+ module = {
+   name = ls;
+   common = commands/ls.c;
+ };
+ module = {
+   name = lsmmap;
+   common = commands/lsmmap.c;
+ };
+ module = {
+   name = lspci;
+   common = commands/lspci.c;
+   enable = pci;
+ };
+ module = {
+   name = memrw;
+   common = commands/memrw.c;
+ };
+ module = {
+   name = minicmd;
+   common = commands/minicmd.c;
+ };
+ module = {
+   name = parttool;
+   common = commands/parttool.c;
+ };
+ module = {
+   name = password;
+   common = commands/password.c;
+ };
+ module = {
+   name = password_pbkdf2;
+   common = commands/password_pbkdf2.c;
+ };
+ module = {
+   name = play;
+   x86 = commands/i386/pc/play.c;
+   enable = x86;
+ };
+ module = {
+   name = probe;
+   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;
+   extra_dist = commands/search.c;
+ };
+ module = {
+   name = search_fs_file;
+   common = commands/search_file.c;
+ };
+ module = {
+   name = search_fs_uuid;
+   common = commands/search_uuid.c;
+ };
+ module = {
+   name = search_label;
+   common = commands/search_label.c;
+ };
+ module = {
+   name = setpci;
+   common = commands/setpci.c;
+   enable = x86;
+ };
+ module = {
+   name = sleep;
+   common = commands/sleep.c;
+ };
+ module = {
+   name = suspend;
+   ieee1275 = commands/ieee1275/suspend.c;
+   enable = i386_ieee1275;
+   enable = powerpc_ieee1275;
+ };
+ module = {
+   name = terminal;
+   common = commands/terminal.c;
+ };
+ module = {
+   name = test;
+   common = commands/test.c;
+ };
+ module = {
+   name = true;
+   common = commands/true.c;
+ };
+ module = {
+   name = usbtest;
+   common = commands/usbtest.c;
+   enable = usb;
+   enable = emu;
+   emu_condition = COND_GRUB_EMU_USB;
+ };
+ module = {
+   name = videoinfo;
+   common = commands/videoinfo.c;
+ };
+ module = {
+   name = videotest;
+   common = commands/videotest.c;
+ };
+ module = {
+   name = xnu_uuid;
+   common = commands/xnu_uuid.c;
+ };
+ module = {
+   name = dm_nv;
+   common = disk/dmraid_nvidia.c;
+ };
+ module = {
+   name = loopback;
+   common = disk/loopback.c;
+ };
+ module = {
+   name = lvm;
+   common = disk/lvm.c;
+ };
+ module = {
+   name = mdraid09;
+   common = disk/mdraid_linux.c;
+ };
+ module = {
+   name = mdraid1x;
+   common = disk/mdraid1x_linux.c;
+ };
+ module = {
+   name = raid;
+   common = disk/raid.c;
+ };
+ module = {
+   name = raid5rec;
+   common = disk/raid5_recover.c;
+ };
+ module = {
+   name = raid6rec;
+   common = disk/raid6_recover.c;
+ };
+ module = {
+   name = scsi;
+   common = disk/scsi.c;
+ };
+ module = {
+   name = memdisk;
+   common = disk/memdisk.c;
+ };
+ module = {
+   name = ata;
+   common = disk/ata.c;
+   enable = pci;
+ };
+ module = {
++  name = ahci;
++  common = disk/ahci.c;
++  enable = pci;
++};
++
++module = {
++  name = pata;
++  common = disk/pata.c;
+   enable = pci;
+ };
+ module = {
+   name = biosdisk;
+   i386_pc = disk/i386/pc/biosdisk.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = usbms;
+   common = disk/usbms.c;
+   enable = usb;
+   enable = emu;
+   emu_condition = COND_GRUB_EMU_USB;
+ };
+ module = {
+   name = nand;
+   ieee1275 = disk/ieee1275/nand.c;
+   enable = i386_ieee1275;
+ };
+ module = {
+   name = efiemu;
+   common = efiemu/main.c;
+   common = efiemu/i386/loadcore32.c;
+   common = efiemu/i386/loadcore64.c;
+   i386_pc = efiemu/i386/pc/cfgtables.c;
+   i386_coreboot = efiemu/i386/pc/cfgtables.c;
+   i386_multiboot = efiemu/i386/pc/cfgtables.c;
+   i386_ieee1275 = efiemu/i386/nocfgtables.c;
+   i386_qemu = efiemu/i386/nocfgtables.c;
+   common = efiemu/mm.c;
+   common = efiemu/loadcore_common.c;
+   common = efiemu/symbols.c;
+   common = efiemu/loadcore32.c;
+   common = efiemu/loadcore64.c;
+   common = efiemu/prepare32.c;
+   common = efiemu/prepare64.c;
+   common = efiemu/pnvram.c;
+   common = efiemu/i386/coredetect.c;
+   extra_dist = efiemu/prepare.c;
+   extra_dist = efiemu/loadcore.c;
+   extra_dist = efiemu/runtime/efiemu.S;
+   extra_dist = efiemu/runtime/efiemu.c;
+   enable = i386_pc;
+   enable = i386_coreboot;
+   enable = i386_ieee1275;
+   enable = i386_multiboot;
+   enable = i386_qemu;
+ };
+ module = {
+   name = font;
+   common = font/font.c;
+   common = font/font_cmd.c;
+   enable = videomodules;
+ };
+ module = {
+   name = affs;
+   common = fs/affs.c;
+ };
+ module = {
+   name = afs;
+   common = fs/afs.c;
+ };
+ 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;
+ };
+ module = {
+   name = btrfs;
+   common = fs/btrfs.c;
+ };
+ module = {
+   name = cpio;
+   common = fs/cpio.c;
+ };
+ module = {
+   name = ext2;
+   common = fs/ext2.c;
+ };
+ module = {
+   name = fat;
+   common = fs/fat.c;
+ };
+ module = {
+   name = fshelp;
+   common = fs/fshelp.c;
+ };
+ module = {
+   name = hfs;
+   common = fs/hfs.c;
+ };
+ module = {
+   name = hfsplus;
+   common = fs/hfsplus.c;
+ };
+ module = {
+   name = iso9660;
+   common = fs/iso9660.c;
+ };
+ module = {
+   name = jfs;
+   common = fs/jfs.c;
+ };
+ module = {
+   name = minix;
+   common = fs/minix.c;
+ };
+ module = {
+   name = minix2;
+   common = fs/minix2.c;
+ };
+ module = {
+   name = nilfs2;
+   common = fs/nilfs2.c;
+ };
+ module = {
+   name = ntfs;
+   common = fs/ntfs.c;
+ };
+ module = {
+   name = ntfscomp;
+   common = fs/ntfscomp.c;
+ };
+ module = {
+   name = reiserfs;
+   common = fs/reiserfs.c;
+ };
+ module = {
+   name = sfs;
+   common = fs/sfs.c;
+ };
+ module = {
+   name = tar;
+   common = fs/tar.c;
+ };
+ module = {
+   name = udf;
+   common = fs/udf.c;
+ };
+ module = {
+   name = ufs1;
+   common = fs/ufs.c;
+ };
+ module = {
+   name = ufs2;
+   common = fs/ufs2.c;
+ };
+ module = {
+   name = xfs;
+   common = fs/xfs.c;
+ };
+ module = {
+   name = zfs;
+   common = fs/zfs/zfs.c;
+   common = fs/zfs/zfs_lzjb.c;
+   common = fs/zfs/zfs_sha256.c;
+   common = fs/zfs/zfs_fletcher.c;
+ };
+ module = {
+   name = zfsinfo;
+   common = fs/zfs/zfsinfo.c;
+ };
+ module = {
+   name = pxe;
+   i386_pc = fs/i386/pc/pxe.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = gettext;
+   common = gettext/gettext.c;
+ };
+ module = {
+   name = gfxmenu;
+   common = gfxmenu/gfxmenu.c;
+   common = gfxmenu/model.c;
+   common = gfxmenu/view.c;
+   common = gfxmenu/font.c;
+   common = gfxmenu/icon_manager.c;
+   common = gfxmenu/theme_loader.c;
+   common = gfxmenu/widget-box.c;
+   common = gfxmenu/gui_canvas.c;
+   common = gfxmenu/gui_circular_progress.c;
+   common = gfxmenu/gui_box.c;
+   common = gfxmenu/gui_label.c;
+   common = gfxmenu/gui_list.c;
+   common = gfxmenu/gui_image.c;
+   common = gfxmenu/gui_progress_bar.c;
+   common = gfxmenu/gui_util.c;
+   common = gfxmenu/gui_string_util.c;
+   common = gfxmenu/named_colors.c;
+ };
+ module = {
+   name = hello;
+   common = hello/hello.c;
+ };
+ module = {
+   name = gzio;
+   common = io/gzio.c;
+ };
+ module = {
+   name = bufio;
+   common = io/bufio.c;
+   enable = videomodules;
+ };
+ module = {
+   name = elf;
+   common = kern/elf.c;
+ };
+ module = {
+   name = crypto;
+   common = lib/crypto.c;
+   extra_dist = lib/libgcrypt-grub/cipher/crypto.lst;
+ };
+ module = {
+   name = pbkdf2;
+   common = lib/pbkdf2.c;
+ };
+ module = {
+   name = relocator;
+   common = lib/relocator.c;
+   x86 = lib/i386/relocator16.S;
+   x86 = lib/i386/relocator32.S;
+   x86 = lib/i386/relocator64.S;
+   i386 = lib/i386/relocator_asm.S;
+   x86_64 = lib/x86_64/relocator_asm.S;
+   x86 = lib/i386/relocator.c;
+   ieee1275 = lib/ieee1275/relocator.c;
+   x86_efi = lib/efi/relocator.c;
+   mips = lib/mips/relocator_asm.S;
+   mips = lib/mips/relocator.c;
+   powerpc = lib/powerpc/relocator_asm.S;
+   powerpc = lib/powerpc/relocator.c;
+   extra_dist = lib/i386/relocator_common.S;
+   extra_dist = kern/powerpc/cache_flush.S;
+   enable = mips;
+   enable = powerpc;
+   enable = x86;
+ };
+ module = {
+   name = datetime;
+   cmos = lib/cmos_datetime.c;
+   x86_efi = lib/efi/datetime.c;
+   sparc64_ieee1275 = lib/ieee1275/datetime.c;
+   powerpc_ieee1275 = lib/ieee1275/datetime.c;
+   enable = noemu;
+ };
+ module = {
+   name = setjmp;
+   common = lib/setjmp.S;
+   extra_dist = lib/i386/setjmp.S;
+   extra_dist = lib/mips/setjmp.S;
+   extra_dist = lib/x86_64/setjmp.S;
+   extra_dist = lib/sparc64/setjmp.S;
+   extra_dist = lib/powerpc/setjmp.S;
+ };
+ module = {
+   name = aout;
+   common = loader/aout.c;
+   enable = x86;
+ };
+ module = {
+   name = bsd;
+   x86 = loader/i386/bsd.c;
+   x86 = loader/i386/bsd32.c;
+   x86 = loader/i386/bsd64.c;
+   extra_dist = loader/i386/bsdXX.c;
+   extra_dist = loader/i386/bsd_pagetable.c;
+   enable = x86;
+ };
+ module = {
+   name = linux16;
+   i386_pc = loader/i386/pc/linux.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = ntldr;
+   i386_pc = loader/i386/pc/ntldr.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = multiboot2;
+   cppflags = "-DGRUB_USE_MULTIBOOT2";
+   common = loader/multiboot.c;
+   common = loader/multiboot_mbi2.c;
+   enable = x86;
+   enable = mips;
+ };
+ module = {
+   name = multiboot;
+   common = loader/multiboot.c;
+   x86 = loader/i386/multiboot_mbi.c;
+   extra_dist = loader/multiboot_elfxx.c;
+   enable = x86;
+ };
+ module = {
+   name = linux;
+   x86 = loader/i386/linux.c;
+   i386_pc = lib/i386/pc/vesa_modes_table.c;
+   mips = loader/mips/linux.c;
+   powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
+   sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
+   enable = noemu;
+ };
+ module = {
+   name = xnu;
+   x86 = loader/xnu_resume.c;
+   x86 = loader/i386/xnu.c;
+   x86 = loader/macho32.c;
+   x86 = loader/macho64.c;
+   x86 = loader/macho.c;
+   x86 = loader/xnu.c;
+   extra_dist = loader/machoXX.c;
+   enable = x86;
+ };
+ module = {
+   name = appleldr;
+   x86_efi = loader/efi/appleloader.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = chain;
+   x86_efi = loader/efi/chainloader.c;
+   i386_pc = loader/i386/pc/chainloader.c;
+   enable = i386_pc;
+   enable = x86_efi;
+ };
+ module = {
+   name = mmap;
+   common = mmap/mmap.c;
+   x86 = mmap/i386/uppermem.c;
+   x86 = mmap/i386/mmap.c;
+   i386_pc = mmap/i386/pc/mmap.c;
+   i386_pc = mmap/i386/pc/mmap_helper.S;
+   x86_efi = mmap/efi/mmap.c;
+   mips_yeeloong = mmap/mips/yeeloong/uppermem.c;
+   enable = x86;
+   enable = mips_yeeloong;
+ };
+ module = {
+   name = normal;
+   common = normal/main.c;
+   common = normal/cmdline.c;
+   common = normal/dyncmd.c;
+   common = normal/auth.c;
+   common = normal/autofs.c;
+   common = normal/color.c;
+   common = normal/completion.c;
+   common = normal/datetime.c;
+   common = normal/menu.c;
+   common = normal/menu_entry.c;
+   common = normal/menu_text.c;
+   common = normal/misc.c;
+   common = normal/crypto.c;
+   common = normal/term.c;
+   common = normal/context.c;
+   common = normal/charset.c;
+   common = script/main.c;
+   common = script/script.c;
+   common = script/execute.c;
+   common = script/function.c;
+   common = script/lexer.c;
+   common = script/argv.c;
+   common = commands/menuentry.c;
+   common = unidata.c;
+   common_nodist = grub_script.tab.c;
+   common_nodist = grub_script.yy.c;
+   common_nodist = grub_script.tab.h;
+   common_nodist = grub_script.yy.h;
+   extra_dist = script/yylex.l;
+   extra_dist = script/parser.y;
+   cflags = '$(CFLAGS_POSIX) -Wno-error';
+   cppflags = '$(CPPFLAGS_POSIX)';
+ };
+ module = {
+   name = part_acorn;
+   common = partmap/acorn.c;
+ };
+ module = {
+   name = part_amiga;
+   common = partmap/amiga.c;
+ };
+ module = {
+   name = part_apple;
+   common = partmap/apple.c;
+ };
+ module = {
+   name = part_gpt;
+   common = partmap/gpt.c;
+ };
+ module = {
+   name = part_msdos;
+   common = partmap/msdos.c;
+ };
+ module = {
+   name = part_sun;
+   common = partmap/sun.c;
+ };
+ module = {
+   name = part_bsd;
+   common = partmap/bsdlabel.c;
+ };
+ module = {
+   name = part_sunpc;
+   common = partmap/sunpc.c;
+ };
+ module = {
+   name = msdospart;
+   common = parttool/msdospart.c;
+ };
+ module = {
+   name = at_keyboard;
+   common = term/at_keyboard.c;
+   enable = x86;
+ };
+ module = {
+   name = gfxterm;
+   common = term/gfxterm.c;
+   enable = videomodules;
+ };
+ module = {
+   name = serial;
+   common = term/serial.c;
+   x86 = term/ns8250.c;
+   enable = emu;
+   enable = i386;
+   enable = x86_64_efi;
+   emu_condition = COND_GRUB_EMU_USB;
+ };
+ module = {
+   name = sendkey;
+   i386_pc = commands/i386/pc/sendkey.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = terminfo;
+   common = term/terminfo.c;
+   common = term/tparm.c;
+   enable = terminfomodule;
+ };
+ module = {
+   name = usb_keyboard;
+   common = term/usb_keyboard.c;
+   enable = usb;
+ };
+ module = {
+   name = vga;
+   i386_pc = video/i386/pc/vga.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = vga_text;
+   common = term/i386/pc/vga_text.c;
+   common = term/i386/vga_common.c;
+   enable = i386_pc;
+   enable = i386_coreboot;
+   enable = i386_multiboot;
+ };
+ module = {
+   name = video_cirrus;
+   x86 = video/cirrus.c;
+   enable = x86;
+ };
+ module = {
+   name = video_bochs;
+   x86 = video/bochs.c;
+   enable = x86;
+ };
+ module = {
+   name = functional_test;
+   common = tests/lib/functional_test.c;
+   common = tests/lib/test.c;
+ };
+ module = {
+   name = example_functional_test;
+   common = tests/example_functional_test.c;
+   cflags = -Wno-format;
+ };
+ module = {
+   name = bitmap;
+   common = video/bitmap.c;
+   enable = videomodules;
+ };
+ module = {
+   name = bitmap_scale;
+   common = video/bitmap_scale.c;
+   enable = videomodules;
+ };
+ module = {
+   name = efi_gop;
+   x86_efi = video/efi_gop.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = efi_uga;
+   x86_efi = video/efi_uga.c;
+   enable = x86_efi;
+ };
+ module = {
+   name = jpeg;
+   common = video/readers/jpeg.c;
+ };
+ module = {
+   name = png;
+   common = video/readers/png.c;
+ };
+ module = {
+   name = tga;
+   common = video/readers/tga.c;
+ };
+ module = {
+   name = vbe;
+   i386_pc = video/i386/pc/vbe.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = video_fb;
+   common = video/fb/video_fb.c;
+   common = video/fb/fbblit.c;
+   common = video/fb/fbfill.c;
+   common = video/fb/fbutil.c;
+   enable = videomodules;
+ };
+ module = {
+   name = video;
+   common = video/video.c;
+   enable = videomodules;
+ };
+ module = {
+   name = ieee1275_fb;
+   ieee1275 = video/ieee1275.c;
+   enable = powerpc;
+   enable = sparc64;
+ };
+ module = {
+   name = sdl;
+   emu = video/emu/sdl.c;
+   enable = emu;
+   condition = COND_GRUB_EMU_SDL;
+ };
+ module = {
+   name = datehook;
+   common = hook/datehook.c;
+ };
+ module = {
+   name = legacycfg;
+   common = commands/legacycfg.c;
+   common = lib/legacy_parse.c;
+   emu = lib/i386/pc/vesa_modes_table.c;
+   enable = i386_pc;
+   enable = emu;
+ };
+ module = {
+   name = test_blockarg;
+   common = tests/test_blockarg.c;
+ };
+ module = {
+   name = xzio;
+   common = io/xzio.c;
+   common = lib/xzembed/xz_dec_bcj.c;
+   common = lib/xzembed/xz_dec_lzma2.c;
+   common = lib/xzembed/xz_dec_stream.c;
+   cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
+ };
+ module = {
+   name = testload;
+   common = commands/testload.c;
+ };
+ module = {
+   name = lsapm;
+   common = commands/i386/pc/lsapm.c;
+   enable = i386_pc;
+ };
+ module = {
+   name = keylayouts;
+   common = commands/keylayouts.c;
+   enable = videomodules;
+ };
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1c1a690aab85febbb4c1ec739715242ea7592183
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,71 @@@
++/* crc.c - command to calculate the crc32 checksum of a file  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2008,2010  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/disk.h>
++#include <grub/file.h>
++#include <grub/misc.h>
++#include <grub/lib/crc.h>
++#include <grub/command.h>
++#include <grub/i18n.h>
++
++static grub_err_t
++grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)),
++            int argc, char **args)
++
++{
++  grub_file_t file;
++  char buf[GRUB_DISK_SECTOR_SIZE];
++  grub_ssize_t size;
++  grub_uint32_t crc;
++
++  if (argc != 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
++
++  file = grub_file_open (args[0]);
++  if (! file)
++    return 0;
++
++  crc = 0;
++  while ((size = grub_file_read (file, buf, sizeof (buf))) > 0)
++    crc = grub_getcrc32 (crc, buf, size);
++
++  if (grub_errno)
++    goto fail;
++
++  grub_printf ("%08x\n", crc);
++
++ fail:
++  grub_file_close (file);
++  return 0;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(crc)
++{
++  cmd = grub_register_command ("crc", grub_cmd_crc,
++                             N_("FILE"),
++                             N_("Calculate the crc32 checksum of a file."));
++}
++
++GRUB_MOD_FINI(crc)
++{
++  grub_unregister_command (cmd);
++}
index 0000000000000000000000000000000000000000,b6ab7875516c24b12a16ccdfd0df94e4728bce18..0154ece577558ebfab0ca2813c3a08634b3ed0fc
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,420 +1,441 @@@
 -grub_hdparm_do_ata_cmd (grub_disk_t disk, grub_uint8_t cmd,
+ /* hdparm.c - command to get/set ATA disk parameters.  */
+ /*
+  *  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 <http://www.gnu.org/licenses/>.
+  */
+ #include <grub/ata.h>
++#include <grub/scsi.h>
+ #include <grub/disk.h>
+ #include <grub/dl.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/lib/hexdump.h>
+ #include <grub/extcmd.h>
+ #include <grub/i18n.h>
+ static const struct grub_arg_option options[] = {
+   {"apm",             'B', 0, N_("Set Advanced Power Management\n"
+                             "(1=low, ..., 254=high, 255=off)."),
+                             0, ARG_TYPE_INT},
+   {"power",           'C', 0, N_("Check power mode."), 0, ARG_TYPE_NONE},
+   {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."),
+                             0, ARG_TYPE_NONE},
+   {"health",          'H', 0, N_("Check SMART health status."), 0, ARG_TYPE_NONE},
+   {"aam",             'M', 0, N_("Set Automatic Acoustic Management\n"
+                             "(0=off, 128=quiet, ..., 254=fast)."),
+                             0, ARG_TYPE_INT},
+   {"standby-timeout", 'S', 0, N_("Set standby timeout\n"
+                             "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."),
+                             0, ARG_TYPE_INT},
+   {"standby",         'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE},
+   {"sleep",           'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE},
+   {"identify",        'i', 0, N_("Print drive identity and settings."),
+                             0, ARG_TYPE_NONE},
+   {"dumpid",          'I', 0, N_("Dump contents of ATA IDENTIFY sector."),
+                              0, ARG_TYPE_NONE},
+   {"smart",            -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT},
+   {"quiet",           'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE},
+   {0, 0, 0, 0, 0, 0}
+ };
+ enum grub_ata_smart_commands
+   {
+     GRUB_ATA_FEAT_SMART_ENABLE  = 0xd8,
+     GRUB_ATA_FEAT_SMART_DISABLE = 0xd9,
+     GRUB_ATA_FEAT_SMART_STATUS  = 0xda,
+   };
+ static int quiet = 0;
+ static grub_err_t
 -  apt.taskfile[GRUB_ATA_REG_CMD] = cmd;
 -  apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
 -  apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors;
++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));
 -  if (grub_disk_ata_pass_through (disk, &apt))
++  apt.taskfile.cmd = cmd;
++  apt.taskfile.features = features;
++  apt.taskfile.sectors = sectors;
+   apt.buffer = buffer;
+   apt.size = size;
 -grub_hdparm_do_check_powermode_cmd (grub_disk_t disk)
++  if (ata->dev->readwrite (ata, &apt))
+     return grub_errno;
+   return GRUB_ERR_NONE;
+ }
+ static int
 -  apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE;
++grub_hdparm_do_check_powermode_cmd (grub_ata_t ata)
+ {
+   struct grub_disk_ata_pass_through_parms apt;
+   grub_memset (&apt, 0, sizeof (apt));
 -  if (grub_disk_ata_pass_through (disk, &apt))
++  apt.taskfile.cmd = GRUB_ATA_CMD_CHECK_POWER_MODE;
 -  return apt.taskfile[GRUB_ATA_REG_SECTORS];
++  if (ata->dev->readwrite (ata, &apt))
+     return -1;
 -grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
++  return apt.taskfile.sectors;
+ }
+ static int
 -  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;
++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));
 -  if (grub_disk_ata_pass_through (disk, &apt))
++  apt.taskfile.cmd = GRUB_ATA_CMD_SMART;
++  apt.taskfile.features = features;
++  apt.taskfile.lba_mid  = 0x4f;
++  apt.taskfile.lba_high = 0xc2;
 -      if (   apt.taskfile[GRUB_ATA_REG_LBAMID]  == 0x4f
 -          && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2)
++  if (ata->dev->readwrite (ata, &apt))
+     return -1;
+   if (features == GRUB_ATA_FEAT_SMART_STATUS)
+     {
 -      else if (   apt.taskfile[GRUB_ATA_REG_LBAMID]  == 0xf4
 -             && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c)
++      if (   apt.taskfile.lba_mid  == 0x4f
++          && apt.taskfile.lba_high == 0xc2)
+       return 0; /* Good SMART status.  */
 -                      grub_disk_t disk, grub_uint8_t cmd)
++      else if (   apt.taskfile.lba_mid  == 0xf4
++             && apt.taskfile.lba_high == 0x2c)
+       return 1; /* Bad SMART status.  */
+       else
+       return -1;
+     }
+   return 0;
+ }
+ static grub_err_t
+ grub_hdparm_simple_cmd (const char * msg,
 -  grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, 0);
++                      grub_ata_t ata, grub_uint8_t cmd)
+ {
+   if (! quiet && msg)
+     grub_printf ("%s", msg);
 -                       grub_disk_t disk, grub_uint8_t cmd,
++  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");
+   return err;
+ }
+ static grub_err_t
+ grub_hdparm_set_val_cmd (const char * msg, int val,
 -  grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors,
++                       grub_ata_t ata, grub_uint8_t cmd,
+                        grub_uint8_t features, grub_uint8_t sectors)
+ {
+   if (! quiet && msg && *msg)
+     {
+       if (val >= 0)
+       grub_printf ("Set %s to %d", msg, val);
+       else
+       grub_printf ("Disable %s", msg);
+     }
 -  if (! grub_disk_ata_pass_through)
 -    return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available");
 -
++  grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, features, sectors,
+                                          NULL, 0);
+   if (! quiet && msg)
+     grub_printf ("%s\n", ! err ? "" : ": not supported");
+   return err;
+ }
+ static const char *
+ le16_to_char (char *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;
+ }
+ static void
+ grub_hdparm_print_identify (const char * idbuf)
+ {
+   const grub_uint16_t * idw = (const grub_uint16_t *) idbuf;
+   /* Print identity strings.  */
+   char tmp[40];
+   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));
+   /* Print AAM, APM and SMART settings.  */
+   grub_uint16_t features1 = grub_le_to_cpu16 (idw[82]);
+   grub_uint16_t features2 = grub_le_to_cpu16 (idw[83]);
+   grub_uint16_t enabled1  = grub_le_to_cpu16 (idw[85]);
+   grub_uint16_t enabled2  = grub_le_to_cpu16 (idw[86]);
+   grub_printf ("Automatic Acoustic Management: ");
+   if (features2 & 0x0200)
+     {
+       if (enabled2 & 0x0200)
+       {
+         grub_uint16_t aam = grub_le_to_cpu16 (idw[94]);
+         grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n",
+                      aam & 0xff, (aam >> 8) & 0xff);
+       }
+       else
+       grub_printf ("disabled\n");
+     }
+   else
+     grub_printf ("not supported\n");
+   grub_printf ("Advanced Power Management: ");
+   if (features2 & 0x0008)
+     {
+       if (enabled2 & 0x0008)
+       grub_printf ("%u (1=low, ..., 254=high)\n",
+                    grub_le_to_cpu16 (idw[91]) & 0xff);
+       else
+       grub_printf ("disabled\n");
+     }
+   else
+     grub_printf ("not supported\n");
+   grub_printf ("SMART Feature Set: ");
+   if (features1 & 0x0001)
+     grub_printf ("%sabled\n", (enabled1 & 0x0001 ? "en" : "dis"));
+   else
+     grub_printf ("not supported\n");
+   /* Print security settings.  */
+   grub_uint16_t security = grub_le_to_cpu16 (idw[128]);
+   grub_printf ("ATA Security: ");
+   if (security & 0x0001)
+     grub_printf ("%s, %s, %s, %s\n",
+                (security & 0x0002 ? "ENABLED" : "disabled"),
+                (security & 0x0004 ? "**LOCKED**"  : "not locked"),
+                (security & 0x0008 ? "frozen" : "NOT FROZEN"),
+                (security & 0x0010 ? "COUNT EXPIRED" : "count not expired"));
+   else
+     grub_printf ("not supported\n");
+ }
+ static void
+ grub_hdparm_print_standby_tout (int timeout)
+ {
+   if (timeout == 0)
+     grub_printf ("off");
+   else if (timeout <= 252 || timeout == 255)
+     {
+       int h = 0, m = 0 , s = 0;
+       if (timeout == 255)
+       {
+         m = 21;
+         s = 15;
+       }
+       else if (timeout == 252)
+       m = 21;
+       else if (timeout <= 240)
+       {
+         s = timeout * 5;
+         m = s / 60;
+         s %= 60;
+       }
+       else
+       {
+         m = (timeout - 240) * 30;
+         h  = m / 60;
+         m %= 60;
+       }
+       grub_printf ("%02d:%02d:%02d", h, m, s);
+     }
+   else
+     grub_printf ("invalid or vendor-specific");
+ }
+ static int get_int_arg (const struct grub_arg_list *state)
+ {
+   return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1);
+ }
+ 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)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument");
+   grub_size_t len = grub_strlen (args[0]);
+   if (! (args[0][0] == '(' && args[0][len - 1] == ')'))
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name");
+   args[0][len - 1] = 0;
 -      disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam);
+   int i = 0;
+   int apm          = get_int_arg (&state[i++]);
+   int power        = state[i++].set;
+   int sec_freeze   = state[i++].set;
+   int health       = state[i++].set;
+   int aam          = get_int_arg (&state[i++]);
+   int standby_tout = get_int_arg (&state[i++]);
+   int standby_now  = state[i++].set;
+   int sleep_now    = state[i++].set;
+   int ident        = state[i++].set;
+   int dumpid       = state[i++].set;
+   int enable_smart = get_int_arg (&state[i++]);
+   quiet            = state[i++].set;
+   /* Open disk.  */
+   grub_disk_t disk = grub_disk_open (&args[0][1]);
+   if (! disk)
+     return grub_errno;
+   if (disk->partition)
+     {
+       grub_disk_close (disk);
+       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),
 -      (apm != 255 ? apm : -1), disk, GRUB_ATA_CMD_SET_FEATURES,
 -      (apm != 255 ? 0x05 : 0x85), (apm != 255 ? apm : 0));
++                           ata, GRUB_ATA_CMD_SET_FEATURES,
++                           (aam ? 0x42 : 0xc2), aam);
+   if (apm >= 0)
+     grub_hdparm_set_val_cmd ("Advanced Power Management",
 -      grub_hdparm_set_val_cmd ("", -1, disk, GRUB_ATA_CMD_IDLE, 0, standby_tout);
++                           (apm != 255 ? apm : -1), ata,
++                           GRUB_ATA_CMD_SET_FEATURES,
++                           (apm != 255 ? 0x05 : 0x85),
++                           (apm != 255 ? apm : 0));
+   if (standby_tout >= 0)
+     {
+       if (! quiet)
+       {
+         grub_printf ("Set standby timeout to %d (", standby_tout);
+         grub_hdparm_print_standby_tout (standby_tout);
+         grub_printf (")");
+       }
+       /* The IDLE cmd sets disk to idle mode and configures standby timer.  */
 -      int err = grub_hdparm_do_smart_cmd (disk, (enable_smart ?
++      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"));
 -    grub_hdparm_simple_cmd ("Freeze security settings", disk,
++      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)
 -      if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_IDENTIFY_DEVICE,
++    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];
 -      int mode = grub_hdparm_do_check_powermode_cmd (disk);
++      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
+       {
+         if (ident)
+           grub_hdparm_print_identify (buf);
+         if (dumpid)
+           hexdump (0, buf, sizeof (buf));
+       }
+     }
+   /* Check power mode.  */
+   if (power)
+     {
+       grub_printf ("Disk power mode is: ");
 -      int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS);
++      int mode = grub_hdparm_do_check_powermode_cmd (ata);
+       if (mode < 0)
+         grub_printf ("unknown\n");
+       else
+       grub_printf ("%s (0x%02x)\n",
+                    (mode == 0xff ? "active/idle" :
+                     mode == 0x80 ? "idle" :
+                     mode == 0x00 ? "standby" : "unknown"), mode);
+     }
+   /* Check health.  */
+   int status = 0;
+   if (health)
+     {
+       if (! quiet)
+       grub_printf ("SMART status is: ");
 -    grub_hdparm_simple_cmd ("Set disk to standby mode", disk,
++      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*"));
+       status = (err > 0);
+     }
+   /* Change power mode.  */
+   if (standby_now)
 -    grub_hdparm_simple_cmd ("Set disk to sleep 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", ata,
+                           GRUB_ATA_CMD_SLEEP);
+   grub_disk_close (disk);
+   grub_errno = GRUB_ERR_NONE;
+   return status;
+ }
+ static grub_extcmd_t cmd;
+ GRUB_MOD_INIT(hdparm)
+ {
+   cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0,
+                             N_("[OPTIONS] DISK"),
+                             N_("Get/set ATA disk parameters."), options);
+ }
+ GRUB_MOD_FINI(hdparm)
+ {
+   grub_unregister_extcmd (cmd);
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c266bbfcbbf65add3a6f015428c49f0982432bdf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,185 @@@
++/* vbeinfo.c - command to list compatible VBE video modes.  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2005,2007,2008,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/env.h>
++#include <grub/misc.h>
++#include <grub/machine/init.h>
++#include <grub/machine/vbe.h>
++#include <grub/mm.h>
++#include <grub/command.h>
++#include <grub/i18n.h>
++
++static void *
++real2pm (grub_vbe_farptr_t ptr)
++{
++  return (void *) ((((unsigned long) ptr & 0xFFFF0000) >> 12UL)
++                 + ((unsigned long) ptr & 0x0000FFFF));
++}
++
++static grub_err_t
++grub_cmd_vbeinfo (grub_command_t cmd __attribute__ ((unused)),
++                int argc __attribute__ ((unused)),
++                char **args __attribute__ ((unused)))
++{
++  struct grub_vbe_info_block controller_info;
++  struct grub_vbe_mode_info_block mode_info_tmp;
++  grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE;
++  grub_uint16_t *video_mode_list;
++  grub_uint16_t *p;
++  grub_uint16_t *saved_video_mode_list;
++  grub_size_t video_mode_list_size;
++  grub_err_t err;
++  char *modevar;
++
++  err = grub_vbe_probe (&controller_info);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  grub_printf ("VBE info:   version: %d.%d  OEM software rev: %d.%d\n",
++             controller_info.version >> 8,
++               controller_info.version & 0xFF,
++               controller_info.oem_software_rev >> 8,
++               controller_info.oem_software_rev & 0xFF);
++
++  /* The total_memory field is in 64 KiB units.  */
++  grub_printf ("            total memory: %d KiB\n",
++               (controller_info.total_memory << 16) / 1024);
++
++  /* Because the information on video modes is stored in a temporary place,
++     it is better to copy it to somewhere safe.  */
++  p = video_mode_list = real2pm (controller_info.video_mode_ptr);
++  while (*p++ != 0xFFFF)
++    ;
++
++  video_mode_list_size = (grub_addr_t) p - (grub_addr_t) video_mode_list;
++  saved_video_mode_list = grub_malloc (video_mode_list_size);
++  if (! saved_video_mode_list)
++    return grub_errno;
++
++  grub_memcpy (saved_video_mode_list, video_mode_list, video_mode_list_size);
++
++  grub_printf ("List of compatible video modes:\n");
++  grub_printf ("Legend: P=Packed pixel, D=Direct color, "
++             "mask/pos=R/G/B/reserved\n");
++
++  /* Walk through all video modes listed.  */
++  for (p = saved_video_mode_list; *p != 0xFFFF; p++)
++    {
++      const char *memory_model = 0;
++      grub_uint32_t mode = (grub_uint32_t) *p;
++
++      err = grub_vbe_get_video_mode_info (mode, &mode_info_tmp);
++      if (err != GRUB_ERR_NONE)
++      {
++        grub_errno = GRUB_ERR_NONE;
++        continue;
++      }
++
++      if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_SUPPORTED) == 0)
++      /* If not available, skip it.  */
++      continue;
++
++      if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_RESERVED_1) == 0)
++      /* Not enough information.  */
++      continue;
++
++      if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_COLOR) == 0)
++      /* Monochrome is unusable.  */
++      continue;
++
++      if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_LFB_AVAIL) == 0)
++      /* We support only linear frame buffer modes.  */
++      continue;
++
++      if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_GRAPHICS) == 0)
++      /* We allow only graphical modes.  */
++      continue;
++
++      switch (mode_info_tmp.memory_model)
++      {
++      case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL:
++        memory_model = "Packed";
++        break;
++      case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR:
++        memory_model = "Direct";
++        break;
++
++      default:
++        break;
++      }
++
++      if (! memory_model)
++      continue;
++
++      grub_printf ("0x%03x:  %4d x %4d x %2d  %s",
++                   mode,
++                   mode_info_tmp.x_resolution,
++                   mode_info_tmp.y_resolution,
++                   mode_info_tmp.bits_per_pixel,
++                   memory_model);
++
++      /* Show mask and position details for direct color modes.  */
++      if (mode_info_tmp.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)
++        grub_printf (", mask: %d/%d/%d/%d  pos: %d/%d/%d/%d",
++                     mode_info_tmp.red_mask_size,
++                     mode_info_tmp.green_mask_size,
++                     mode_info_tmp.blue_mask_size,
++                     mode_info_tmp.rsvd_mask_size,
++                     mode_info_tmp.red_field_position,
++                     mode_info_tmp.green_field_position,
++                     mode_info_tmp.blue_field_position,
++                     mode_info_tmp.rsvd_field_position);
++      grub_printf ("\n");
++    }
++
++  grub_free (saved_video_mode_list);
++
++  /* Check existence of vbe_mode environment variable.  */
++  modevar = grub_env_get ("vbe_mode");
++
++  if (modevar != 0)
++    {
++      unsigned long value;
++
++      value = grub_strtoul (modevar, 0, 0);
++      if (grub_errno == GRUB_ERR_NONE)
++      use_mode = value;
++      else
++      grub_errno = GRUB_ERR_NONE;
++    }
++
++  grub_printf ("Configured VBE mode (vbe_mode) = 0x%03x\n", use_mode);
++
++  return 0;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(vbeinfo)
++{
++  cmd =
++    grub_register_command ("vbeinfo", grub_cmd_vbeinfo, 0,
++                         N_("List compatible VESA BIOS extension video modes."));
++}
++
++GRUB_MOD_FINI(vbeinfo)
++{
++  grub_unregister_command (cmd);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d2921c09dc206f72f8016236d319de860e81a5e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,179 @@@
++/* vbetest.c - command to test VESA BIOS Extension 2.0+ support.  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2005,2007  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/normal.h>
++#include <grub/dl.h>
++#include <grub/env.h>
++#include <grub/misc.h>
++#include <grub/term.h>
++#include <grub/machine/init.h>
++#include <grub/machine/vbe.h>
++#include <grub/video.h>
++#include <grub/err.h>
++#include <grub/i18n.h>
++
++static grub_err_t
++grub_cmd_vbetest (grub_command_t cmd __attribute__ ((unused)),
++                int argc __attribute__ ((unused)),
++                char **args __attribute__ ((unused)))
++{
++  grub_err_t err;
++  char *modevar;
++  struct grub_vbe_mode_info_block mode_info;
++  struct grub_vbe_info_block controller_info;
++  grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE;
++  grub_uint32_t old_mode;
++  grub_uint8_t *framebuffer = 0;
++  grub_uint32_t bytes_per_scan_line = 0;
++  unsigned char *ptr;
++  int i;
++
++  grub_printf ("Probing for VESA BIOS Extension ... ");
++
++  /* Check if VESA BIOS exists.  */
++  err = grub_vbe_probe (&controller_info);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  grub_printf ("found!\n");
++
++  /* Dump out controller information.  */
++  grub_printf ("VBE signature = %c%c%c%c\n",
++             controller_info.signature[0],
++             controller_info.signature[1],
++             controller_info.signature[2],
++             controller_info.signature[3]);
++
++  grub_printf ("VBE version = %d.%d\n",
++             controller_info.version >> 8,
++             controller_info.version & 0xFF);
++  grub_printf ("OEM string ptr = %08x\n",
++             controller_info.oem_string_ptr);
++  grub_printf ("Total memory = %d\n",
++             controller_info.total_memory);
++
++  err = grub_vbe_get_video_mode (&old_mode);
++  grub_printf ("Get video mode err = %04x\n", err);
++
++  if (err == GRUB_ERR_NONE)
++    grub_printf ("Old video mode = %04x\n", old_mode);
++  else
++    grub_errno = GRUB_ERR_NONE;
++
++  /* Check existence of vbe_mode environment variable.  */
++  modevar = grub_env_get ("vbe_mode");
++  if (modevar != 0)
++    {
++      unsigned long value;
++
++      value = grub_strtoul (modevar, 0, 0);
++      if (grub_errno == GRUB_ERR_NONE)
++      use_mode = value;
++      else
++      grub_errno = GRUB_ERR_NONE;
++    }
++
++  err = grub_vbe_get_video_mode_info (use_mode, &mode_info);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  /* Dump out details about the mode being tested.  */
++  grub_printf ("mode: 0x%03x\n",
++               use_mode);
++  grub_printf ("width : %d\n",
++               mode_info.x_resolution);
++  grub_printf ("height: %d\n",
++               mode_info.y_resolution);
++  grub_printf ("memory model: %02x\n",
++               mode_info.memory_model);
++  grub_printf ("bytes/scanline: %d\n",
++               mode_info.bytes_per_scan_line);
++  grub_printf ("bytes/scanline (lin): %d\n",
++               mode_info.lin_bytes_per_scan_line);
++  grub_printf ("base address: %08x\n",
++               mode_info.phys_base_addr);
++  grub_printf ("red mask/pos: %d/%d\n",
++               mode_info.red_mask_size,
++               mode_info.red_field_position);
++  grub_printf ("green mask/pos: %d/%d\n",
++               mode_info.green_mask_size,
++               mode_info.green_field_position);
++  grub_printf ("blue mask/pos: %d/%d\n",
++               mode_info.blue_mask_size,
++               mode_info.blue_field_position);
++
++  grub_printf ("Press any key to continue.\n");
++
++  grub_getkey ();
++
++  /* Setup GFX mode.  */
++  err = grub_vbe_set_video_mode (use_mode, &mode_info);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  /* Determine framebuffer address and how many bytes are in scan line.  */
++  framebuffer = (grub_uint8_t *) mode_info.phys_base_addr;
++  ptr = framebuffer;
++
++  if (controller_info.version >= 0x300)
++    {
++      bytes_per_scan_line = mode_info.lin_bytes_per_scan_line;
++    }
++  else
++    {
++      bytes_per_scan_line = mode_info.bytes_per_scan_line;
++    }
++
++  /* Draw some random data to screen.  */
++  for (i = 0; i < 256 * 256; i++)
++    {
++      ptr[i] = i & 0x0F;
++    }
++
++  /* Draw white line to screen.  */
++  for (i = 0; i < 100; i++)
++    {
++      ptr[mode_info.bytes_per_scan_line * 50 + i] = 0x0F;
++    }
++
++  /* Draw another white line to screen.  */
++  grub_memset (ptr + bytes_per_scan_line * 51, 0x0f, bytes_per_scan_line);
++
++  grub_getkey ();
++
++  grub_video_restore ();
++
++  /* Restore old video mode.  */
++  grub_vbe_set_video_mode (old_mode, 0);
++
++  return grub_errno;
++}
++
++static grub_command_t cmd;
++
++GRUB_MOD_INIT(vbetest)
++{
++  cmd = grub_register_command ("vbetest", grub_cmd_vbetest,
++                             0, N_("Test VESA BIOS Extension 2.0+ support."));
++}
++
++GRUB_MOD_FINI(vbetest)
++{
++  grub_unregister_command (cmd);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..946db82e15518733ea71573083ab3f22546b0986
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,426 @@@
++/*
++ *  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 <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/disk.h>
++#include <grub/mm.h>
++#include <grub/time.h>
++#include <grub/pci.h>
++#include <grub/ata.h>
++#include <grub/scsi.h>
++#include <grub/misc.h>
++#include <grub/list.h>
++
++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[16];
++  grub_uint32_t reserved[0xc];
++  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[6];
++  grub_uint32_t sata_active;
++  grub_uint32_t command_issue;
++  grub_uint32_t unused2[17];
++};
++
++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];
++};
++
++enum
++  {
++    GRUB_AHCI_HBA_CAP_NPORTS_MASK = 0x1f
++  };
++
++enum
++  {
++    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;
++};
++
++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 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));
++
++  hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN;
++
++  nports = (hba->cap & GRUB_AHCI_HBA_CAP_NPORTS_MASK) + 1;
++
++  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");
++  grub_dprintf ("ahci", "%d AHCI ports\n", nports);
++
++  for (i = 0; i < nports; i++)
++    {
++      struct grub_ahci_device *adev;
++      struct grub_pci_dma_chunk *command_list;
++      struct grub_pci_dma_chunk *command_table;
++
++      if (!(hba->ports_implemented & (1 << i)))
++      continue;
++
++      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;
++      }
++
++      adev = grub_malloc (sizeof (*adev));
++      if (!adev)
++      {
++        grub_dma_free (command_list);
++        grub_dma_free (command_table);
++        return 1;
++      }
++
++      grub_dprintf ("ahci", "found device ahci%d (port %d)\n", numdevs, i);
++
++      adev->hba = hba;
++      adev->port = i;
++      adev->num = numdevs++;
++      adev->command_list_chunk = command_list;
++      adev->command_list = grub_dma_get_virt (command_list);
++      adev->command_table_chunk = command_table;
++      adev->command_table = grub_dma_get_virt (command_table);
++      adev->command_list->command_table_base
++      = grub_dma_get_phys (command_table);
++
++      adev->hba->ports[i].command_list_base = grub_dma_get_phys (command_list);
++      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;
++}
++
++
++\f
++
++static int
++grub_ahci_iterate (int (*hook) (int id, int bus))
++{
++  struct grub_ahci_device *dev;
++
++  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 (grub_ata_t disk,
++                   struct grub_disk_ata_pass_through_parms *parms)
++{
++  struct grub_ahci_device *dev = (struct grub_ahci_device *) disk->data;
++  struct grub_pci_dma_chunk *bufc;
++  grub_uint64_t endtime;
++  unsigned i;
++
++  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));
++
++  /* FIXME: support port multipliers.  */
++  dev->command_list[0].config
++    = (4 << 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);
++  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;
++  for (i = 0; i < sizeof (parms->taskfile.raw); i++)
++    dev->command_table[0].cfis[register_map[i]] = parms->taskfile.raw[i];
++
++  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;
++
++  if (parms->write)
++    grub_memcpy ((char *) grub_dma_get_virt (bufc), parms->buffer, parms->size);
++
++  grub_dprintf ("ahci", "AHCI command schedulded\n");
++  dev->hba->ports[dev->port].inten = (1 << 5);
++  dev->hba->ports[dev->port].intstatus = (1 << 5);
++  dev->hba->ports[dev->port].command_issue |= 1;
++  dev->hba->ports[dev->port].command |= 1;
++
++  endtime = grub_get_time_ms () + 1000;  
++  while (!(dev->hba->ports[dev->port].intstatus & (1 << 5)))
++    if (grub_get_time_ms () > endtime)
++      {
++      grub_dprintf ("ahci", "AHCI timeout\n");
++      dev->hba->ports[dev->port].command &= ~1;
++      /* FIXME: free resources.  */
++      return grub_error (GRUB_ERR_IO, "AHCI transfer timeouted");
++      }
++
++  grub_dprintf ("ahci", "AHCI command completed succesfully\n");
++  dev->hba->ports[dev->port].command &= ~1;
++
++  if (!parms->write)
++    grub_memcpy (parms->buffer, (char *) grub_dma_get_virt (bufc), parms->size);
++  grub_dma_free (bufc);
++
++  return GRUB_ERR_NONE;
++}
++
++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;
++
++  return GRUB_ERR_NONE;
++}
++
++static struct grub_ata_dev grub_ahci_dev =
++  {
++    .iterate = grub_ahci_iterate,
++    .open = grub_ahci_open,
++    .readwrite = grub_ahci_readwrite,
++  };
++
++\f
++
++GRUB_MOD_INIT(ahci)
++{
++  /* To prevent two drivers operating on the same disks.  */
++  //  grub_disk_firmware_is_tainted = 1;
++  if (0 && 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);
++}
++
++GRUB_MOD_FINI(ahci)
++{
++  grub_ata_dev_unregister (&grub_ahci_dev);
++}
index 0000000000000000000000000000000000000000,fe677e2a02412cab69f18e565ab122078bbd6baa..04b81cd27c888f646bb7ef71aa0df3c11a3d38a9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,916 +1,593 @@@
 -#include <grub/time.h>
 -#include <grub/pci.h>
+ /* ata.c - ATA disk access.  */
+ /*
+  *  GRUB  --  GRand Unified Bootloader
+  *  Copyright (C) 2007, 2008, 2009  Free Software Foundation, Inc.
+  *
+  *  GRUB is free software: you can redistribute it and/or modify
+  *  it under the terms of the GNU General Public License as published by
+  *  the Free Software Foundation, either version 3 of the License, or
+  *  (at your option) any later version.
+  *
+  *  GRUB is distributed in the hope that it will be useful,
+  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *  GNU General Public License for more details.
+  *
+  *  You should have received a copy of the GNU General Public License
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <grub/ata.h>
+ #include <grub/dl.h>
+ #include <grub/disk.h>
+ #include <grub/mm.h>
 -#include <grub/cs5536.h>
+ #include <grub/scsi.h>
 -/* 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;
 -}
 -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));
 -}
 -
 -static void
 -grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size)
 -{
 -  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 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_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';
+ }
 -grub_ata_dumpinfo (struct grub_ata_device *dev, char *info)
+ static void
 -grub_atapi_identify (struct grub_ata_device *dev)
++grub_ata_dumpinfo (struct grub_ata *dev, char *info)
+ {
+   char text[41];
+   /* 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);
+   if (! dev->atapi)
+     {
+       grub_dprintf ("ata", "Addressing: %d\n", dev->addr);
+       grub_dprintf ("ata", "Sectors: %lld\n", (unsigned long long) dev->size);
+     }
+ }
+ static grub_err_t
 -  grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
 -  grub_ata_wait ();
 -  if (grub_ata_check_ready (dev))
 -    {
 -      grub_free (info);
 -      return grub_errno;
 -    }
++grub_atapi_identify (struct grub_ata *dev)
+ {
++  struct grub_disk_ata_pass_through_parms parms;
+   char *info;
++  grub_err_t err;
+   info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
+   if (! info)
+     return grub_errno;
 -  grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE);
 -  grub_ata_wait ();
++  grub_memset (&parms, 0, sizeof (parms));
++  parms.taskfile.disk = 0;
++  parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE;
 -  if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
 -    {
 -      grub_free (info);
 -      return grub_errno;
 -    }
 -  grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE);
++  err = dev->dev->readwrite (dev, &parms);
++  if (err)
++    return err;
 -grub_atapi_wait_drq (struct grub_ata_device *dev,
 -                   grub_uint8_t ireason,
 -                   int milliseconds)
 -{
 -  /* 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)
++  if (parms.size != GRUB_DISK_SECTOR_SIZE)
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
++                     "device cannot be identified");
+   dev->atapi = 1;
+   grub_ata_dumpinfo (dev, info);
+   grub_free (info);
+   return GRUB_ERR_NONE;
+ }
+ static grub_err_t
 -  grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4);
 -  grub_ata_wait ();
 -  if (grub_ata_check_ready (dev))
 -    {
 -      grub_free (info);
 -      return grub_errno;
 -    }
++grub_ata_identify (struct grub_ata *dev)
+ {
++  struct grub_disk_ata_pass_through_parms parms;
+   char *info;
+   grub_uint16_t *info16;
++  grub_err_t err;
+   info = grub_malloc (GRUB_DISK_SECTOR_SIZE);
+   if (! info)
+     return grub_errno;
+   info16 = (grub_uint16_t *) info;
++  grub_memset (&parms, 0, sizeof (parms));
++  parms.buffer = info;
++  parms.taskfile.disk = 0;
 -  grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE);
 -  grub_ata_wait ();
++  parms.taskfile.cmd = GRUB_ATA_CMD_IDENTIFY_DEVICE;
 -  if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD))
++  err = dev->dev->readwrite (dev, &parms);
++  if (err)
++    return err;
 -      grub_errno = GRUB_ERR_NONE;
 -      grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
 -
++  if (parms.size != GRUB_DISK_SECTOR_SIZE)
+     {
++      grub_uint8_t sts = parms.taskfile.status;
+       grub_free (info);
 -        && (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04 /* ABRT */))
+       if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ
+         | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR
 -  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;
 -    }
 -
++        && (parms.taskfile.error & 0x04 /* ABRT */))
+       /* Device without ATA IDENTIFY, try ATAPI.  */
+       return grub_atapi_identify (dev);
+       else if (sts == 0x00)
+       /* No device, return error but don't print message.  */
+       return GRUB_ERR_UNKNOWN_DEVICE;
+       else
+       /* Other Error.  */
+       return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+                          "device cannot be identified");
+     }
 -check_device (struct grub_ata_device *dev)
 -{
 -  grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
 -  grub_ata_wait ();
 -
 -  /* Try to detect if the port is in use by writing to it,
 -     waiting for a while and reading it again.  If the value
 -     was preserved, there is a device connected.  */
 -  grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
 -  grub_ata_wait ();
 -  grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
 -  grub_dprintf ("ata", "sectors=0x%x\n", sec);
 -  if (sec != 0x5A)
 -    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected");
 -
 -  /* The above test may detect a second (slave) device
 -     connected to a SATA controller which supports only one
 -     (master) device.  It is not safe to use the status register
 -     READY bit to check for controller channel existence.  Some
 -     ATAPI commands (RESET, DIAGNOSTIC) may clear this bit.  */
 -
 -  /* Use the IDENTIFY DEVICE command to query the device.  */
 -  return grub_ata_identify (dev);
 -}
 -
 -static grub_err_t
 -grub_ata_device_initialize (int port, int device, int addr, int addr2)
 -{
 -  struct grub_ata_device *dev;
 -  struct grub_ata_device **devp;
 -  grub_err_t err;
 -
 -  grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
 -              port, device, addr, addr2);
 -
 -  dev = grub_malloc (sizeof(*dev));
 -  if (! dev)
 -    return grub_errno;
 -
 -  /* Setup the device information.  */
 -  dev->port = port;
 -  dev->device = device;
 -  dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE;
 -  dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE;
 -  dev->next = NULL;
 -
 -  /* Register the device.  */
 -  for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
 -  *devp = dev;
 -
 -  err = check_device (dev);
 -  if (err)
 -    grub_print_error ();
 -
 -  return 0;
 -}
 -
 -static int NESTED_FUNC_ATTR
 -grub_ata_pciinit (grub_pci_device_t dev,
 -                grub_pci_id_t pciid)
 -{
 -  static int compat_use[2] = { 0 };
 -  grub_pci_address_t addr;
 -  grub_uint32_t class;
 -  grub_uint32_t bar1;
 -  grub_uint32_t bar2;
 -  int rega;
 -  int regb;
 -  int i;
 -  static int controller = 0;
 -  int cs5536 = 0;
 -  int nports = 2;
 -
 -  /* Read class.  */
 -  addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
 -  class = grub_pci_read (addr);
 -
 -  /* AMD CS5536 Southbridge.  */
 -  if (pciid == GRUB_CS5536_PCIID)
 -    {
 -      cs5536 = 1;
 -      nports = 1;
 -    }
 -
 -  /* Check if this class ID matches that of a PCI IDE Controller.  */
 -  if (!cs5536 && (class >> 16 != 0x0101))
 -    return 0;
 -
 -  for (i = 0; i < nports; i++)
 -    {
 -      /* Set to 0 when the channel operated in compatibility mode.  */
 -      int compat;
 -
 -      /* We don't support non-compatibility mode for CS5536.  */
 -      if (cs5536)
 -      compat = 0;
 -      else
 -      compat = (class >> (8 + 2 * i)) & 1;
 -
 -      rega = 0;
 -      regb = 0;
 -
 -      /* If the channel is in compatibility mode, just assign the
 -       default registers.  */
 -      if (compat == 0 && !compat_use[i])
 -      {
 -        rega = grub_ata_ioaddress[i];
 -        regb = grub_ata_ioaddress2[i];
 -        compat_use[i] = 1;
 -      }
 -      else if (compat)
 -      {
 -        /* Read the BARs, which either contain a mmapped IO address
 -           or the IO port address.  */
 -        addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES
 -                                      + sizeof (grub_uint64_t) * i);
 -        bar1 = grub_pci_read (addr);
 -        addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES
 -                                      + sizeof (grub_uint64_t) * i
 -                                      + sizeof (grub_uint32_t));
 -        bar2 = grub_pci_read (addr);
 -
 -        /* Check if the BARs describe an IO region.  */
 -        if ((bar1 & 1) && (bar2 & 1))
 -          {
 -            rega = bar1 & ~3;
 -            regb = bar2 & ~3;
 -          }
 -      }
 -
 -      grub_dprintf ("ata",
 -                  "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n",
 -                  grub_pci_get_bus (dev), grub_pci_get_device (dev),
 -                  grub_pci_get_function (dev), compat, rega, regb);
 -
 -      if (rega && regb)
 -      {
 -        grub_errno = GRUB_ERR_NONE;
 -        grub_ata_device_initialize (controller * 2 + i, 0, rega, regb);
 -
 -        /* Most errors raised by grub_ata_device_initialize() are harmless.
 -           They just indicate this particular drive is not responding, most
 -           likely because it doesn't exist.  We might want to ignore specific
 -           error types here, instead of printing them.  */
 -        if (grub_errno)
 -          {
 -            grub_print_error ();
 -            grub_errno = GRUB_ERR_NONE;
 -          }
 -
 -        grub_ata_device_initialize (controller * 2 + i, 1, rega, regb);
 -
 -        /* Likewise.  */
 -        if (grub_errno)
 -          {
 -            grub_print_error ();
 -            grub_errno = GRUB_ERR_NONE;
 -          }
 -      }
 -    }
 -
 -  controller++;
 -
 -  return 0;
 -}
 -
 -static grub_err_t
 -grub_ata_initialize (void)
 -{
 -  grub_pci_iterate (grub_ata_pciinit);
 -  return 0;
 -}
 -
 -static void
 -grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector,
 -               grub_size_t size)
 -{
 -  grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size);
 -  grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF);
 -  grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF);
 -  grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF);
 -}
 -
 -static grub_err_t
 -grub_ata_setaddress (struct grub_ata_device *dev,
 -                   grub_ata_addressing_t addressing,
+   /* Now it is certain that this is not an ATAPI device.  */
+   dev->atapi = 0;
+   /* CHS is always supported.  */
+   dev->addr = GRUB_ATA_CHS;
+   /* Check if LBA is supported.  */
+   if (info16[49] & (1 << 9))
+     {
+       /* Check if LBA48 is supported.  */
+       if (info16[83] & (1 << 10))
+       dev->addr = GRUB_ATA_LBA48;
+       else
+       dev->addr = GRUB_ATA_LBA;
+     }
+   /* Determine the amount of sectors.  */
+   if (dev->addr != GRUB_ATA_LBA48)
+     dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60]));
+   else
+     dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100]));
+   /* Read CHS information.  */
+   dev->cylinders = info16[1];
+   dev->heads = info16[3];
+   dev->sectors_per_track = info16[6];
+   grub_ata_dumpinfo (dev, info);
+   grub_free(info);
+   return 0;
+ }
+ static grub_err_t
 -  switch (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_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);
++  switch (dev->addr)
+     {
+     case GRUB_ATA_CHS:
+       {
+       unsigned int cylinder;
+       unsigned int head;
+       unsigned int sect;
+       /* Calculate the sector, cylinder and head to use.  */
+       sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1;
+       cylinder = (((grub_uint32_t) sector / dev->sectors_per_track)
+                   / dev->heads);
+       head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads;
+       if (sect > dev->sectors_per_track
+           || cylinder > dev->cylinders
+           || head > dev->heads)
+         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,
 -                     0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F));
 -      if (grub_ata_check_ready (dev))
 -      return grub_errno;
++      
++      parms->taskfile.disk = head;
++      parms->taskfile.sectnum = sect;
++      parms->taskfile.cyllsb = cylinder & 0xFF;
++      parms->taskfile.cylmsb = cylinder >> 8;
+       break;
+       }
+     case GRUB_ATA_LBA:
+       if (size == 256)
+       size = 0;
 -      grub_ata_setlba (dev, sector, size);
++      parms->taskfile.disk = ((sector >> 24) & 0x0F);
 -      grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4));
 -      if (grub_ata_check_ready (dev))
 -      return grub_errno;
++      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_setlba (dev, sector >> 24, size >> 8);
++      parms->taskfile.disk = 0;
+       /* Set "Previous".  */
 -      grub_ata_setlba (dev, sector, size);
++      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".  */
 -  struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
 -
 -  grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n", (unsigned long long) size, rw);
++      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;
+     }
+   return GRUB_ERR_NONE;
+ }
+ static grub_err_t
+ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
+                   grub_size_t size, char *buf, int rw)
+ {
 -  grub_ata_addressing_t addressing = dev->addr;
++  struct grub_ata *ata = disk->data;
 -      batch = 256;
++  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;
+     }
+   else
+     {
+       if (addressing == GRUB_ATA_LBA48)
+       addressing = GRUB_ATA_LBA;
 -
 -      /* 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");
 -      }
 -
++      if (addressing != GRUB_ATA_CHS)
++      batch = 256;
++      else
++      batch = 1;
+       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);
 -static int
 -grub_ata_iterate (int (*hook) (const char *name))
++      grub_memset (&parms, 0, sizeof (parms));
++      grub_ata_setaddress (ata, &parms, sector, batch);
++      parms.taskfile.cmd = (! rw ? cmd : cmd_write);
++      parms.buffer = buf;
++      parms.size = batch * GRUB_DISK_SECTOR_SIZE;
++  
++      err = ata->dev->readwrite (ata, &parms);
++      if (err)
++      return err;
++      if (parms.size != batch * GRUB_DISK_SECTOR_SIZE)
++      return grub_error (GRUB_ERR_READ_ERROR, "incomplete read");
++      buf += GRUB_DISK_SECTOR_SIZE * batch;
+       sector += batch;
+       nsectors += batch;
+     }
+   return GRUB_ERR_NONE;
+ }
\f
 -  struct grub_ata_device *dev;
++static inline void
++grub_ata_real_close (struct grub_ata *ata)
+ {
 -  for (dev = grub_ata_devices; dev; dev = dev->next)
++  if (ata->dev->close)
++    ata->dev->close (ata);
++}
++
++static struct grub_ata *
++grub_ata_real_open (int id, int bus)
++{
++  struct grub_ata *ata;
++  grub_ata_dev_t p;
 -      char devname[10];
++  ata = grub_malloc (sizeof (*ata));
++  if (!ata)
++    return NULL;
++  for (p = grub_ata_dev_list; p; p = p->next)
+     {
 -
 -      err = check_device (dev);
 -      if (err)
+       grub_err_t err;
 -      if (dev->atapi)
 -      continue;
 -
 -      grub_snprintf (devname, sizeof (devname), 
 -                   "ata%d", dev->port * 2 + dev->device);
++      if (p->open (id, bus, ata))
+       {
+         grub_errno = GRUB_ERR_NONE;
+         continue;
+       }
++      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;
++}
 -      if (hook (devname))
 -      return 1;
 -    }
++static int
++grub_ata_iterate (int (*hook_in) (const char *name))
++{
++  auto int hook (int id, int bus);
++  int hook (int id, int bus)
++  {
++    struct grub_ata *ata;
++    int ret;
++    char devname[40];
 -  struct grub_ata_device *dev;
 -  grub_err_t err;
 -
 -  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;
 -    }
 -
 -  if (! dev)
 -    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
++    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))
++      return 1;
+   return 0;
+ }
+ static grub_err_t
+ grub_ata_open (const char *name, grub_disk_t disk)
+ {
 -  if (dev->atapi)
++  unsigned id, bus;
++  struct grub_ata *ata;
 -  err = check_device (dev);
 -
 -  if (err)
 -    return err;
++  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;
 -  disk->total_sectors = dev->size;
++  if (ata->atapi)
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
 -  disk->id = (unsigned long) dev;
++  disk->total_sectors = ata->size;
 -  disk->data = dev;
++  disk->id = grub_make_scsi_id (id, bus, 0);
 -grub_ata_close (grub_disk_t disk __attribute__((unused)))
++  disk->data = ata;
+   return 0;
+ }
+ static void
 -
++grub_ata_close (grub_disk_t disk)
+ {
 -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;
 -
 -}
 -
++  struct grub_ata *ata = disk->data;
++  grub_ata_real_close (ata);
+ }
+ static grub_err_t
+ grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector,
+              grub_size_t size, char *buf)
+ {
+   return grub_ata_readwrite (disk, sector, size, buf, 0);
+ }
+ static grub_err_t
+ grub_ata_write (grub_disk_t disk,
+               grub_disk_addr_t sector,
+               grub_size_t size,
+               const char *buf)
+ {
+   return grub_ata_readwrite (disk, sector, size, (char *) buf, 1);
+ }
+ static struct grub_disk_dev grub_atadisk_dev =
+   {
+     .name = "ATA",
+     .id = GRUB_DISK_DEVICE_ATA_ID,
+     .iterate = grub_ata_iterate,
+     .open = grub_ata_open,
+     .close = grub_ata_close,
+     .read = grub_ata_read,
+     .write = grub_ata_write,
+     .next = 0
+   };
\f
+ /* ATAPI code.  */
 -grub_atapi_read (struct grub_scsi *scsi,
 -               grub_size_t cmdsize __attribute__((unused)),
 -               char *cmd, grub_size_t size, char *buf)
+ static grub_err_t
 -  struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data;
++grub_atapi_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
++               grub_size_t size, char *buf)
+ {
 -  if (grub_atapi_packet (dev, cmd, size))
 -    return grub_errno;
 -
 -  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;
 -    }
 -
++  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));
++
++  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;
++
++  parms.size = size;
++  parms.buffer = buf;
++  
++  err = dev->dev->readwrite (dev, &parms);
++  if (err)
++    return err;
 -grub_atapi_open (int devnum, struct grub_scsi *scsi)
++  if (parms.size != size)
++    return grub_error (GRUB_ERR_READ_ERROR, "incomplete ATAPI read");
+   return GRUB_ERR_NONE;
+ }
+ static grub_err_t
+ grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)),
+                 grub_size_t cmdsize __attribute__((unused)),
+                 char *cmd __attribute__((unused)),
+                 grub_size_t size __attribute__((unused)),
+                 char *buf __attribute__((unused)))
+ {
+   // XXX: scsi.mod does not use write yet.
+   return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented");
+ }
+ static grub_err_t
 -  struct grub_ata_device *dev;
 -  struct grub_ata_device *devfnd = 0;
 -  grub_err_t err;
++grub_atapi_open (int id, int bus, struct grub_scsi *scsi)
+ {
 -  for (dev = grub_ata_devices; dev; dev = dev->next)
 -    {
 -      if (dev->port * 2 + dev->device == devnum)
 -      {
 -        devfnd = dev;
 -        break;
 -      }
 -    }
++  struct grub_ata *ata;
 -  grub_dprintf ("ata", "opening ATAPI dev `ata%d'\n", devnum);
++  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");
 -  if (! devfnd)
 -    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
++  scsi->data = ata;
 -  err = check_device (devfnd);
 -  if (err)
 -    return err;
++  return GRUB_ERR_NONE;
++}
 -  if (! devfnd->atapi)
 -    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
++static int
++grub_atapi_iterate (int (*hook_in) (int id, int bus, int luns))
++{
++  auto int hook (int id, int bus);
++  int hook (int id, int bus)
++  {
++    struct grub_ata *ata;
++    int ret;
 -  scsi->data = devfnd;
++    ata = grub_ata_real_open (id, bus);
 -  return GRUB_ERR_NONE;
++    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))
++      return 1;
++  return 0;
++}
 -    .name = "ata",
 -    .id = GRUB_SCSI_SUBSYSTEM_ATAPI,
++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 =
+   {
 -    .write = grub_atapi_write
+     .iterate = grub_atapi_iterate,
+     .open = grub_atapi_open,
++    .close = grub_atapi_close,
+     .read = grub_atapi_read,
 -  /* 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 ();
 -
++    .write = grub_atapi_write,
++    .next = 0
+   };
\f
+ GRUB_MOD_INIT(ata)
+ {
+   grub_disk_dev_register (&grub_atadisk_dev);
+   /* ATAPI devices are handled by scsi.mod.  */
+   grub_scsi_dev_register (&grub_atapi_dev);
+ }
+ GRUB_MOD_FINI(ata)
+ {
+   grub_scsi_dev_unregister (&grub_atapi_dev);
+   grub_disk_dev_unregister (&grub_atadisk_dev);
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b6edf78d68988f58c0347affde655fabf3228980
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,513 @@@
++/* 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 <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/ata.h>
++#include <grub/scsi.h>
++#include <grub/disk.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/pci.h>
++#include <grub/cs5536.h>
++#include <grub/time.h>
++
++/* 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 };
++static const grub_port_t grub_pata_ioaddress2[] = { GRUB_ATA_CH0_PORT2, 
++                                                  GRUB_ATA_CH1_PORT2 };
++
++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;
++  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;
++
++  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);
++}
++
++static inline void
++grub_pata_regset2 (struct grub_pata_device *dev, int reg, int val)
++{
++  grub_outb (val, dev->ioaddress2 + reg);
++}
++
++static inline grub_uint8_t
++grub_pata_regget2 (struct grub_pata_device *dev, int reg)
++{
++  return grub_inb (dev->ioaddress2 + 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)
++{
++  if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY)
++    return grub_pata_wait_not_busy (dev, 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)
++{ 
++  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));
++  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)
++{
++  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);
++}
++
++/* 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)
++{
++  struct grub_pata_device *dev = (struct grub_pata_device *) disk->data;
++  grub_size_t nread = 0;
++
++  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=%d\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, (parms->cmdsize ? 0 : 0xE0)
++                  | dev->device << 4
++                  | (parms->taskfile.disk & 0xf));
++  if (grub_pata_check_ready (dev))
++    return grub_errno;
++
++  int i;
++  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 = 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;
++      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;
++
++  /* 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, int addr2)
++{
++  struct grub_pata_device *dev;
++  struct grub_pata_device **devp;
++  grub_err_t err;
++
++  grub_dprintf ("pata", "detecting device %d,%d (0x%x, 0x%x)\n",
++              port, device, addr, addr2);
++
++  dev = grub_malloc (sizeof(*dev));
++  if (! dev)
++    return grub_errno;
++
++  /* Setup the device information.  */
++  dev->port = port;
++  dev->device = device;
++  dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE;
++  dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE;
++  dev->next = NULL;
++
++  /* Register the device.  */
++  for (devp = &grub_pata_devices; *devp; devp = &(*devp)->next);
++  *devp = dev;
++
++  err = check_device (dev);
++  if (err)
++    grub_print_error ();
++
++  return 0;
++}
++
++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 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_pata_ioaddress[i];
++        regb = grub_pata_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 ("pata",
++                  "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_pata_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_pata_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_pata_initialize (void)
++{
++  grub_pci_iterate (grub_pata_pciinit);
++  return 0;
++}
++
++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;
++
++  return GRUB_ERR_NONE;
++}
++
++static int
++grub_pata_iterate (int (*hook) (int id, int bus))
++{
++  struct grub_pata_device *dev;
++
++  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,
++  };
++
++
++\f
++
++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);
++}
index 0000000000000000000000000000000000000000,902ab12c39364daf52cd5069768ce2b41da296f7..b989a98ad1f2ae1c6c7bb7ebaffd74cbfaf8133a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,604 +1,620 @@@
 -  auto int scsi_iterate (int bus, int luns);
+ /* scsi.c - scsi support.  */
+ /*
+  *  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 <http://www.gnu.org/licenses/>.
+  */
+ #include <grub/disk.h>
+ #include <grub/dl.h>
+ #include <grub/kernel.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/types.h>
+ #include <grub/scsi.h>
+ #include <grub/scsicmd.h>
+ #include <grub/time.h>
\f
+ static grub_scsi_dev_t grub_scsi_dev_list;
++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)
+ {
+   dev->next = grub_scsi_dev_list;
+   grub_scsi_dev_list = dev;
+ }
+ void
+ grub_scsi_dev_unregister (grub_scsi_dev_t dev)
+ {
+   grub_scsi_dev_t *p, q;
+   for (p = &grub_scsi_dev_list, q = *p; q; p = &(q->next), q = q->next)
+     if (q == dev)
+       {
+         *p = q->next;
+       break;
+       }
+ }
\f
+ /* Check result of previous operation.  */
+ static grub_err_t
+ grub_scsi_request_sense (grub_scsi_t scsi)
+ {
+   struct grub_scsi_request_sense rs;
+   struct grub_scsi_request_sense_data rsd;
+   grub_err_t err;
+   rs.opcode = grub_scsi_cmd_request_sense;
+   rs.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   rs.reserved1 = 0;
+   rs.reserved2 = 0;
+   rs.alloc_length = 0x12; /* XXX: Hardcoded for now */
+   rs.control = 0;
+   grub_memset (rs.pad, 0, sizeof(rs.pad));
+   err = scsi->dev->read (scsi, sizeof (rs), (char *) &rs,
+                        sizeof (rsd), (char *) &rsd);
+   if (err)
+     return err;
+   return GRUB_ERR_NONE;
+ }
+ /* Self commenting... */
+ static grub_err_t
+ grub_scsi_test_unit_ready (grub_scsi_t scsi)
+ {
+   struct grub_scsi_test_unit_ready tur;
+   grub_err_t err;
+   grub_err_t err_sense;
+   
+   tur.opcode = grub_scsi_cmd_test_unit_ready;
+   tur.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   tur.reserved1 = 0;
+   tur.reserved2 = 0;
+   tur.reserved3 = 0;
+   tur.control = 0;
+   grub_memset (tur.pad, 0, sizeof(tur.pad));
+   err = scsi->dev->read (scsi, sizeof (tur), (char *) &tur,
+                        0, NULL);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+   /* err_sense is ignored for now and Request Sense Data also... */
+   
+   if (err)
+     return err;
+   return GRUB_ERR_NONE;
+ }
+ /* Determine if the device is removable and the type of the device
+    SCSI.  */
+ static grub_err_t
+ grub_scsi_inquiry (grub_scsi_t scsi)
+ {
+   struct grub_scsi_inquiry iq;
+   struct grub_scsi_inquiry_data iqd;
+   grub_err_t err;
+   grub_err_t err_sense;
+   iq.opcode = grub_scsi_cmd_inquiry;
+   iq.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   iq.page = 0;
+   iq.reserved = 0;
+   iq.alloc_length = 0x24; /* XXX: Hardcoded for now */
+   iq.control = 0;
+   grub_memset (iq.pad, 0, sizeof(iq.pad));
+   err = scsi->dev->read (scsi, sizeof (iq), (char *) &iq,
+                        sizeof (iqd), (char *) &iqd);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+   /* err_sense is ignored for now and Request Sense Data also... */
+   if (err)
+     return err;
+   scsi->devtype = iqd.devtype & GRUB_SCSI_DEVTYPE_MASK;
+   scsi->removable = iqd.rmb >> GRUB_SCSI_REMOVABLE_BIT;
+   return GRUB_ERR_NONE;
+ }
+ /* Read the capacity and block size of SCSI.  */
+ static grub_err_t
+ grub_scsi_read_capacity (grub_scsi_t scsi)
+ {
+   struct grub_scsi_read_capacity rc;
+   struct grub_scsi_read_capacity_data rcd;
+   grub_err_t err;
+   grub_err_t err_sense;
+   rc.opcode = grub_scsi_cmd_read_capacity;
+   rc.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   rc.logical_block_addr = 0;
+   rc.reserved1 = 0;
+   rc.reserved2 = 0;
+   rc.PMI = 0;
+   rc.control = 0;
+   rc.pad = 0;
+       
+   err = scsi->dev->read (scsi, sizeof (rc), (char *) &rc,
+                        sizeof (rcd), (char *) &rcd);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+ /* err_sense is ignored for now and Request Sense Data also... */
+   if (err)
+     return err;
+   scsi->size = grub_be_to_cpu32 (rcd.size);
+   scsi->blocksize = grub_be_to_cpu32 (rcd.blocksize);
+   return GRUB_ERR_NONE;
+ }
+ /* Send a SCSI request for DISK: read SIZE sectors starting with
+    sector SECTOR to BUF.  */
+ static grub_err_t
+ grub_scsi_read10 (grub_disk_t disk, grub_disk_addr_t sector,
+                 grub_size_t size, char *buf)
+ {
+   grub_scsi_t scsi;
+   struct grub_scsi_read10 rd;
+   grub_err_t err;
+   grub_err_t err_sense;
+   scsi = disk->data;
+   rd.opcode = grub_scsi_cmd_read10;
+   rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   rd.lba = grub_cpu_to_be32 (sector);
+   rd.reserved = 0;
+   rd.size = grub_cpu_to_be16 (size);
+   rd.reserved2 = 0;
+   rd.pad = 0;
+   err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+   /* err_sense is ignored for now and Request Sense Data also... */
+   return err;
+ }
+ /* Send a SCSI request for DISK: read SIZE sectors starting with
+    sector SECTOR to BUF.  */
+ static grub_err_t
+ grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector,
+                 grub_size_t size, char *buf)
+ {
+   grub_scsi_t scsi;
+   struct grub_scsi_read12 rd;
+   grub_err_t err;
+   grub_err_t err_sense;
+   scsi = disk->data;
+   rd.opcode = grub_scsi_cmd_read12;
+   rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   rd.lba = grub_cpu_to_be32 (sector);
+   rd.size = grub_cpu_to_be32 (size);
+   rd.reserved = 0;
+   rd.control = 0;
+   err = scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->blocksize, buf);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+   /* err_sense is ignored for now and Request Sense Data also... */
+   return err;
+ }
+ #if 0
+ /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
+    sectors starting with SECTOR.  */
+ static grub_err_t
+ grub_scsi_write10 (grub_disk_t disk, grub_disk_addr_t sector,
+                  grub_size_t size, char *buf)
+ {
+   grub_scsi_t scsi;
+   struct grub_scsi_write10 wr;
+   grub_err_t err;
+   grub_err_t err_sense;
+   scsi = disk->data;
+   wr.opcode = grub_scsi_cmd_write10;
+   wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   wr.lba = grub_cpu_to_be32 (sector);
+   wr.reserved = 0;
+   wr.size = grub_cpu_to_be16 (size);
+   wr.reserved2 = 0;
+   wr.pad = 0;
+   err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+   /* err_sense is ignored for now and Request Sense Data also... */
+   return err;
+ }
+ /* Send a SCSI request for DISK: write the data stored in BUF to SIZE
+    sectors starting with SECTOR.  */
+ static grub_err_t
+ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
+                  grub_size_t size, char *buf)
+ {
+   grub_scsi_t scsi;
+   struct grub_scsi_write12 wr;
+   grub_err_t err;
+   grub_err_t err_sense;
+   scsi = disk->data;
+   wr.opcode = grub_scsi_cmd_write12;
+   wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT;
+   wr.lba = grub_cpu_to_be32 (sector);
+   wr.size = grub_cpu_to_be32 (size);
+   wr.reserved = 0;
+   wr.control = 0;
+   err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf);
+   /* Each SCSI command should be followed by Request Sense.
+      If not so, many devices STALLs or definitely freezes. */
+   err_sense = grub_scsi_request_sense (scsi);
+   if (err_sense != GRUB_ERR_NONE)
+       grub_errno = err;
+   /* err_sense is ignored for now and Request Sense Data also... */
+   return err;
+ }
+ #endif
\f
+ static int
+ grub_scsi_iterate (int (*hook) (const char *name))
+ {
+   grub_scsi_dev_t p;
 -  int scsi_iterate (int bus, int luns)
++  auto int scsi_iterate (int id, int bus, int luns);
 -        sname = grub_xasprintf ("%s%d", p->name, bus);
++  int scsi_iterate (int id, int bus, int luns)
+     {
+       int i;
+       /* In case of a single LUN, just return `usbX'.  */
+       if (luns == 1)
+       {
+         char *sname;
+         int ret;
 -        sname = grub_xasprintf ("%s%d%c", p->name, bus, 'a' + i);
++        sname = grub_xasprintf ("%s%d", grub_scsi_names[id], bus);
+         if (!sname)
+           return 1;
+         ret = hook (sname);
+         grub_free (sname);
+         return ret;
+       }
+       /* In case of multiple LUNs, every LUN will get a prefix to
+        distinguish it.  */
+       for (i = 0; i < luns; i++)
+       {
+         char *sname;
+         int ret;
 -  for (p = grub_scsi_dev_list; p; p = p->next)
++        sname = grub_xasprintf ("%s%d%c", grub_scsi_names[id], bus, 'a' + i);
+         if (!sname)
+           return 1;
+         ret = hook (sname);
+         grub_free (sname);
+         if (ret)
+           return 1;
+       }
+       return 0;
+     }
+   for (p = grub_scsi_dev_list; p; p = p->next)
+     if (p->iterate && (p->iterate) (scsi_iterate))
+       return 1;
+   return 0;
+ }
+ static grub_err_t
+ grub_scsi_open (const char *name, grub_disk_t disk)
+ {
+   grub_scsi_dev_t p;
+   grub_scsi_t scsi;
+   grub_err_t err;
+   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
+      LUN.  */
+   if (nameend >= name && *nameend >= 'a' && *nameend <= 'z')
+     {
+       lun = *nameend - 'a';
+       nameend--;
+     }
+   else
+     lun = 0;
+   while (nameend >= name && grub_isdigit (*nameend))
+     nameend--;
+   if (!nameend[1] || !grub_isdigit (nameend[1]))
+     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
+   bus = grub_strtoul (nameend + 1, 0, 0);
+   scsi = grub_malloc (sizeof (*scsi));
+   if (! scsi)
+     return grub_errno;
 -      if (grub_strncmp (p->name, name, nameend - name) != 0)
 -      continue;
++  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))
+     {
 -      if (p->open (bus, scsi))
 -      continue;
++      grub_free (scsi);
++      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
++    }
 -      disk->id = grub_make_scsi_id (p->id, bus, lun);
++  for (p = grub_scsi_dev_list; p; p = p->next)
++    {
++      if (p->open (id, bus, scsi))
++      {
++        grub_errno = GRUB_ERR_NONE;
++        continue;
++      }
 -
++      disk->id = grub_make_scsi_id (id, bus, lun);
+       disk->data = scsi;
+       scsi->dev = p;
+       scsi->lun = lun;
+       scsi->bus = bus;
+       grub_dprintf ("scsi", "dev opened\n");
+       err = grub_scsi_inquiry (scsi);
+       if (err)
+       {
+         grub_free (scsi);
+         grub_dprintf ("scsi", "inquiry failed\n");
+         return err;
+       }
+       grub_dprintf ("scsi", "inquiry: devtype=0x%02x removable=%d\n",
+                   scsi->devtype, scsi->removable);
+       /* Try to be conservative about the device types
+        supported.  */
+       if (scsi->devtype != grub_scsi_devtype_direct
+         && scsi->devtype != grub_scsi_devtype_cdrom)
+       {
+         grub_free (scsi);
+         return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+                            "unknown SCSI device");
+       }
+       /* According to USB MS tests specification, issue Test Unit Ready
+        * until OK */
+       maxtime = grub_get_time_ms () + 5000; /* It is safer value */
+       do
+         {
+         /* Timeout is necessary - for example in case when we have
+          * universal card reader with more LUNs and we have only
+          * one card inserted (or none), so only one LUN (or none)
+          * will be ready - and we want not to hang... */
+         if (grub_get_time_ms () > maxtime)
+             {
+               err = GRUB_ERR_READ_ERROR;
+               grub_free (scsi);
+               grub_dprintf ("scsi", "LUN is not ready - timeout\n");
+               return err;
+             }
+           err = grub_scsi_test_unit_ready (scsi);
+         }
+       while (err == GRUB_ERR_READ_ERROR);
+       /* Reset grub_errno !
+        * It is set to some error code in loop before... */
+       grub_errno = GRUB_ERR_NONE;
+       /* Read capacity of media */
+       err = grub_scsi_read_capacity (scsi);
+       if (err)
+       {
+         grub_free (scsi);
+         grub_dprintf ("scsi", "READ CAPACITY failed\n");
+         return err;
+       }
+       /* SCSI blocks can be something else than 512, although GRUB
+        wants 512 byte blocks.  */
+       disk->total_sectors = ((grub_uint64_t)scsi->size
+                              * (grub_uint64_t)scsi->blocksize)
+                           >> GRUB_DISK_SECTOR_BITS;
+       grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
+                   scsi->size, scsi->blocksize);
+       grub_dprintf ("scsi", "Disk total 512 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");
+ }
+ static void
+ grub_scsi_close (grub_disk_t disk)
+ {
+   grub_scsi_t scsi;
+   scsi = disk->data;
+   if (scsi->dev->close)
+     scsi->dev->close (scsi);
+   grub_free (scsi);
+ }
+ static grub_err_t
+ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
+               grub_size_t size, char *buf)
+ {
+   grub_scsi_t scsi;
+   scsi = disk->data;
+   /* SCSI sectors are variable in size.  GRUB uses 512 byte
+      sectors.  */
+   if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE)
+     {
+       unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS;
+       if (! (spb != 0 && (scsi->blocksize & GRUB_DISK_SECTOR_SIZE) == 0))
+       return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                          "unsupported SCSI block size");
+       grub_uint32_t sector_mod = 0;
+       sector = grub_divmod64 (sector, spb, &sector_mod);
+       if (! (sector_mod == 0 && size % spb == 0))
+       return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+                          "unaligned SCSI read not supported");
+       size /= spb;
+     }
+   /* 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
+        * unknown to me (specially on OHCI). Do not use it. */
+   /* Split transfer requests to device sector size because */
+   /* some devices are not able to transfer more than 512-1024 bytes */
+   grub_err_t err = GRUB_ERR_NONE;
+   for ( ; size; size--)
+     {
+       /* Depending on the type, select a read function.  */
+       switch (scsi->devtype)
+         {
+           case grub_scsi_devtype_direct:
+             err = grub_scsi_read10 (disk, sector, 1, buf);
+             break;
+           case grub_scsi_devtype_cdrom:
+             err = grub_scsi_read12 (disk, sector, 1, buf);
+             break;
+           default: /* This should not happen */
+             return GRUB_ERR_READ_ERROR;
+         }
+       if (err)
+         return err;
+       sector++;
+       buf += scsi->blocksize;
+     }
+   return err;
+ #endif
+ }
+ static grub_err_t
+ grub_scsi_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)))
+ {
+ #if 0
+   /* XXX: Not tested yet!  */
+   /* XXX: This should depend on the device type?  */
+   return grub_scsi_write10 (disk, sector, size, buf);
+ #endif
+   return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ }
+ static struct grub_disk_dev grub_scsi_dev =
+   {
+     .name = "scsi",
+     .id = GRUB_DISK_DEVICE_SCSI_ID,
+     .iterate = grub_scsi_iterate,
+     .open = grub_scsi_open,
+     .close = grub_scsi_close,
+     .read = grub_scsi_read,
+     .write = grub_scsi_write,
+     .next = 0
+   };
+ GRUB_MOD_INIT(scsi)
+ {
+   grub_disk_dev_register (&grub_scsi_dev);
+ }
+ GRUB_MOD_FINI(scsi)
+ {
+   grub_disk_dev_unregister (&grub_scsi_dev);
+ }
index 0000000000000000000000000000000000000000,e63105ccc645d3d6b29688fd538f335d8d12b023..4e1af7be3d09580cbdd435687101642f76585380
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,435 +1,437 @@@
 -grub_usbms_iterate (int (*hook) (int bus, int luns))
+ /* usbms.c - USB Mass Storage Support.  */
+ /*
+  *  GRUB  --  GRand Unified Bootloader
+  *  Copyright (C) 2008  Free Software Foundation, Inc.
+  *
+  *  GRUB is free software: you can redistribute it and/or modify
+  *  it under the terms of the GNU General Public License as published by
+  *  the Free Software Foundation, either version 3 of the License, or
+  *  (at your option) any later version.
+  *
+  *  GRUB is distributed in the hope that it will be useful,
+  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *  GNU General Public License for more details.
+  *
+  *  You should have received a copy of the GNU General Public License
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ #include <grub/dl.h>
+ #include <grub/mm.h>
+ #include <grub/usb.h>
+ #include <grub/scsi.h>
+ #include <grub/scsicmd.h>
+ #include <grub/misc.h>
+ #define GRUB_USBMS_DIRECTION_BIT      7
+ /* The USB Mass Storage Command Block Wrapper.  */
+ struct grub_usbms_cbw
+ {
+   grub_uint32_t signature;
+   grub_uint32_t tag;
+   grub_uint32_t transfer_length;
+   grub_uint8_t flags;
+   grub_uint8_t lun;
+   grub_uint8_t length;
+   grub_uint8_t cbwcb[16];
+ } __attribute__ ((packed));
+ struct grub_usbms_csw
+ {
+   grub_uint32_t signature;
+   grub_uint32_t tag;
+   grub_uint32_t residue;
+   grub_uint8_t status;
+ } __attribute__ ((packed));
+ struct grub_usbms_dev
+ {
+   struct grub_usb_device *dev;
+   int luns;
+   int config;
+   int interface;
+   struct grub_usb_desc_endp *in;
+   struct grub_usb_desc_endp *out;
+   int in_maxsz;
+   int out_maxsz;
+ };
+ typedef struct grub_usbms_dev *grub_usbms_dev_t;
+ /* FIXME: remove limit.  */
+ #define MAX_USBMS_DEVICES 128
+ static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES];
+ static int first_available_slot = 0;
+ static grub_err_t
+ grub_usbms_reset (grub_usb_device_t dev, int interface)
+ {
+   return grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0);
+ }
+ static void
+ grub_usbms_detach (grub_usb_device_t usbdev, int config, int interface)
+ {
+   unsigned i;
+   for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
+     if (grub_usbms_devices[i] && grub_usbms_devices[i]->dev == usbdev
+       && grub_usbms_devices[i]->interface == interface
+       && grub_usbms_devices[i]->config == config)
+       {
+       grub_free (grub_usbms_devices[i]);
+       grub_usbms_devices[i] = 0;
+       }
+ }
+ static int
+ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno)
+ {
+   struct grub_usb_desc_if *interf
+     = usbdev->config[configno].interf[interfno].descif;
+   int j;
+   grub_uint8_t luns = 0;
+   unsigned curnum;
+   grub_usb_err_t err;
+   if (first_available_slot == ARRAY_SIZE (grub_usbms_devices))
+     return 0;
+   curnum = first_available_slot;
+   first_available_slot++;
+   interf = usbdev->config[configno].interf[interfno].descif;
+   if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK
+        /* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */
+        && interf->subclass != GRUB_USBMS_SUBCLASS_RBC
+        && interf->subclass != GRUB_USBMS_SUBCLASS_MMC2
+        && interf->subclass != GRUB_USBMS_SUBCLASS_UFI 
+        && interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 )
+       || interf->protocol != GRUB_USBMS_PROTOCOL_BULK)
+     return 0;
+   grub_usbms_devices[curnum] = grub_zalloc (sizeof (struct grub_usbms_dev));
+   if (! grub_usbms_devices[curnum])
+     return 0;
+   grub_usbms_devices[curnum]->dev = usbdev;
+   grub_usbms_devices[curnum]->interface = interfno;
+   grub_dprintf ("usbms", "alive\n");
+   /* Iterate over all endpoints of this interface, at least a
+      IN and OUT bulk endpoint are required.  */
+   for (j = 0; j < interf->endpointcnt; j++)
+     {
+       struct grub_usb_desc_endp *endp;
+       endp = &usbdev->config[0].interf[interfno].descendp[j];
+       if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+       {
+         /* Bulk IN endpoint.  */
+         grub_usbms_devices[curnum]->in = endp;
+         /* Clear Halt is not possible yet! */
+         /* grub_usb_clear_halt (usbdev, endp->endp_addr); */
+         grub_usbms_devices[curnum]->in_maxsz = endp->maxpacket;
+       }
+       else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
+       {
+         /* Bulk OUT endpoint.  */
+         grub_usbms_devices[curnum]->out = endp;
+         /* Clear Halt is not possible yet! */
+         /* grub_usb_clear_halt (usbdev, endp->endp_addr); */
+         grub_usbms_devices[curnum]->out_maxsz = endp->maxpacket;
+       }
+     }
+   if (!grub_usbms_devices[curnum]->in || !grub_usbms_devices[curnum]->out)
+     {
+       grub_free (grub_usbms_devices[curnum]);
+       grub_usbms_devices[curnum] = 0;
+       return 0;
+     }
+   grub_dprintf ("usbms", "alive\n");
+   /* XXX: Activate the first configuration.  */
+   grub_usb_set_configuration (usbdev, 1);
+   /* Query the amount of LUNs.  */
+   err = grub_usb_control_msg (usbdev, 0xA1, 254, 0, interfno, 1, (char *) &luns);
+               
+   if (err)
+     {
+       /* In case of a stall, clear the stall.  */
+       if (err == GRUB_USB_ERR_STALL)
+       {
+         grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->in->endp_addr);
+         grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->out->endp_addr);
+       }
+       /* Just set the amount of LUNs to one.  */
+       grub_errno = GRUB_ERR_NONE;
+       grub_usbms_devices[curnum]->luns = 1;
+     }
+   else
+     /* luns = 0 means one LUN with ID 0 present ! */
+     /* We get from device not number of LUNs but highest
+      * LUN number. LUNs are numbered from 0, 
+      * i.e. number of LUNs is luns+1 ! */
+     grub_usbms_devices[curnum]->luns = luns + 1;
+   grub_dprintf ("usbms", "alive\n");
+   usbdev->config[configno].interf[interfno].detach_hook = grub_usbms_detach;
+ #if 0 /* All this part should be probably deleted.
+        * This make trouble on some devices if they are not in
+        * Phase Error state - and there they should be not in such state...
+        * Bulk only mass storage reset procedure should be used only
+        * on place and in time when it is really necessary. */
+   /* Reset recovery procedure */
+   /* Bulk-Only Mass Storage Reset, after the reset commands
+      will be accepted.  */
+   grub_usbms_reset (usbdev, i);
+   grub_usb_clear_halt (usbdev, usbms->in->endp_addr);
+   grub_usb_clear_halt (usbdev, usbms->out->endp_addr);
+ #endif
+   return 1;
+ }
\f
+ static int
 -      if (hook (i, grub_usbms_devices[i]->luns))
++grub_usbms_iterate (int (*hook) (int id, int bus, int luns))
+ {
+   unsigned i;
+   grub_usb_poll_devices ();
+   for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
+     if (grub_usbms_devices[i])
+       {
 -grub_usbms_open (int devnum, struct grub_scsi *scsi)
++      if (hook (GRUB_SCSI_SUBSYSTEM_USBMS, i, grub_usbms_devices[i]->luns))
+         return 1;
+       }
+   return 0;
+ }
+ static grub_err_t
+ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                    grub_size_t size, char *buf, int read_write)
+ {
+   struct grub_usbms_cbw cbw;
+   grub_usbms_dev_t dev = (grub_usbms_dev_t) scsi->data;
+   struct grub_usbms_csw status;
+   static grub_uint32_t tag = 0;
+   grub_usb_err_t err = GRUB_USB_ERR_NONE;
+   grub_usb_err_t errCSW = GRUB_USB_ERR_NONE;
+   int retrycnt = 3 + 1;
+  retry:
+   retrycnt--;
+   if (retrycnt == 0)
+     return grub_error (GRUB_ERR_IO, "USB Mass Storage stalled");
+   /* Setup the request.  */
+   grub_memset (&cbw, 0, sizeof (cbw));
+   cbw.signature = grub_cpu_to_le32 (0x43425355);
+   cbw.tag = tag++;
+   cbw.transfer_length = grub_cpu_to_le32 (size);
+   cbw.flags = (!read_write) << GRUB_USBMS_DIRECTION_BIT;
+   cbw.lun = scsi->lun; /* In USB MS CBW are LUN bits on another place than in SCSI CDB, both should be set correctly. */
+   cbw.length = cmdsize;
+   grub_memcpy (cbw.cbwcb, cmd, cmdsize);
+   
+   /* Debug print of CBW content. */
+   grub_dprintf ("usb", "CBW: sign=0x%08x tag=0x%08x len=0x%08x\n",
+       cbw.signature, cbw.tag, cbw.transfer_length);
+   grub_dprintf ("usb", "CBW: flags=0x%02x lun=0x%02x CB_len=0x%02x\n",
+       cbw.flags, cbw.lun, cbw.length);
+   grub_dprintf ("usb", "CBW: cmd:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+       cbw.cbwcb[ 0], cbw.cbwcb[ 1], cbw.cbwcb[ 2], cbw.cbwcb[ 3],
+       cbw.cbwcb[ 4], cbw.cbwcb[ 5], cbw.cbwcb[ 6], cbw.cbwcb[ 7],
+       cbw.cbwcb[ 8], cbw.cbwcb[ 9], cbw.cbwcb[10], cbw.cbwcb[11],
+       cbw.cbwcb[12], cbw.cbwcb[13], cbw.cbwcb[14], cbw.cbwcb[15]);
+   /* Write the request.
+    * XXX: Error recovery is maybe still not fully correct. */
+   err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr,
+                            sizeof (cbw), (char *) &cbw);
+   if (err)
+     {
+       if (err == GRUB_USB_ERR_STALL)
+       {
+         grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+         goto CheckCSW;
+       }
+       return grub_error (GRUB_ERR_IO, "USB Mass Storage request failed");
+     }
+   /* Read/write the data, (maybe) according to specification.  */
+   if (size && (read_write == 0))
+     {
+       err = grub_usb_bulk_read (dev->dev, dev->in->endp_addr, size, buf);
+       grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL); 
+       if (err)
+         {
+           if (err == GRUB_USB_ERR_STALL)
+           grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+           goto CheckCSW;
+         }
+       /* Debug print of received data. */
+       grub_dprintf ("usb", "buf:\n");
+       if (size <= 64)
+       {
+         unsigned i;
+         for (i = 0; i < size; i++)
+           grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
+       }
+       else
+           grub_dprintf ("usb", "Too much data for debug print...\n");
+     }
+   else if (size)
+     {
+       err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr, size, buf);
+       grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL);
+       grub_dprintf ("usb", "First 16 bytes of sent data:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+       buf[ 0], buf[ 1], buf[ 2], buf[ 3],
+       buf[ 4], buf[ 5], buf[ 6], buf[ 7],
+       buf[ 8], buf[ 9], buf[10], buf[11],
+       buf[12], buf[13], buf[14], buf[15]);
+       if (err)
+         {
+           if (err == GRUB_USB_ERR_STALL)
+           grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+           goto CheckCSW;
+         }
+       /* Debug print of sent data. */
+       if (size <= 256)
+       {
+         unsigned i;
+         for (i=0; i<size; i++)
+           grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
+       }
+       else
+           grub_dprintf ("usb", "Too much data for debug print...\n");
+     }
+   /* Read the status - (maybe) according to specification.  */
+ CheckCSW:
+   errCSW = grub_usb_bulk_read (dev->dev, dev->in->endp_addr,
+                   sizeof (status), (char *) &status);
+   if (errCSW)
+     {
+       grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+       errCSW = grub_usb_bulk_read (dev->dev, dev->in->endp_addr,
+                               sizeof (status), (char *) &status);
+       if (errCSW)
+         { /* Bulk-only reset device. */
+           grub_dprintf ("usb", "Bulk-only reset device - errCSW\n");
+           grub_usbms_reset (dev->dev, dev->interface);
+           grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+           grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+         goto retry;
+         }
+     }
+   /* Debug print of CSW content. */
+   grub_dprintf ("usb", "CSW: sign=0x%08x tag=0x%08x resid=0x%08x\n",
+       status.signature, status.tag, status.residue);
+   grub_dprintf ("usb", "CSW: status=0x%02x\n", status.status);
+   
+   /* If phase error or not valid signature, do bulk-only reset device. */
+   if ((status.status == 2) ||
+       (status.signature != grub_cpu_to_le32(0x53425355)))
+     { /* Bulk-only reset device. */
+       grub_dprintf ("usb", "Bulk-only reset device - bad status\n");
+       grub_usbms_reset (dev->dev, dev->interface);
+       grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
+       grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
+       goto retry;
+     }
+   /* If "command failed" status or data transfer failed -> error */
+   if ((status.status || err) && !read_write)
+     return grub_error (GRUB_ERR_READ_ERROR,
+                      "error communication with USB Mass Storage device");
+   else if ((status.status || err) && read_write)
+     return grub_error (GRUB_ERR_WRITE_ERROR,
+                      "error communication with USB Mass Storage device");
+   return GRUB_ERR_NONE;
+ }
+ static grub_err_t
+ grub_usbms_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                grub_size_t size, char *buf)
+ {
+   return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 0);
+ }
+ static grub_err_t
+ grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
+                 grub_size_t size, char *buf)
+ {
+   return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 1);
+ }
+ static grub_err_t
 -    .name = "usb",
 -    .id = GRUB_SCSI_SUBSYSTEM_USBMS,
++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])
+     return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+                      "unknown USB Mass Storage device");
+   scsi->data = grub_usbms_devices[devnum];
+   scsi->luns = grub_usbms_devices[devnum]->luns;
+   return GRUB_ERR_NONE;
+ }
+ static struct grub_scsi_dev grub_usbms_dev =
+   {
+     .iterate = grub_usbms_iterate,
+     .open = grub_usbms_open,
+     .read = grub_usbms_read,
+     .write = grub_usbms_write
+   };
+ struct grub_usb_attach_desc attach_hook =
+ {
+   .class = GRUB_USB_CLASS_MASS_STORAGE,
+   .hook = grub_usbms_attach
+ };
+ GRUB_MOD_INIT(usbms)
+ {
+   grub_usb_register_attach_hook_class (&attach_hook);
+   grub_scsi_dev_register (&grub_usbms_dev);
+ }
+ GRUB_MOD_FINI(usbms)
+ {
+   unsigned i;
+   for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
+     {
+       grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
+       .interf[grub_usbms_devices[i]->interface].detach_hook = 0;
+       grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
+       .interf[grub_usbms_devices[i]->interface].attached = 0;
+     }
+   grub_usb_unregister_attach_hook_class (&attach_hook);
+   grub_scsi_dev_unregister (&grub_usbms_dev);
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5a492dc2f995c7f3dae6a1d7094abf6842fbe81f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++gcc -c -m32 -DELF32 -o efiemu32.o ./efiemu.c -Wall -Werror -nostdlib -O2 -I. -I../../include
++gcc -c -m64 -DELF64 -o efiemu64_c.o ./efiemu.c -Wall -Werror -mcmodel=large -O2 -I. -I../../include
++gcc -c -m64 -DELF64 -o efiemu64_s.o ./efiemu.S -Wall -Werror -mcmodel=large -O2 -I. -I../../include
++ld -o efiemu64.o -r efiemu64_s.o efiemu64_c.o -nostdlib
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..107534e98078680d331b5a4a4aa9160ad7feaf51
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,56 @@@
++/* Memory allocation on the stack.
++
++   Copyright (C) 1995, 1999, 2001-2004, 2006-2010 Free Software Foundation,
++   Inc.
++
++   This program is free software; you can redistribute it and/or modify it
++   under the terms of the GNU General Public License as published
++   by the Free Software Foundation; either version 2, or (at your option)
++   any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   General Public License for more details.
++
++   You should have received a copy of the GNU General Public
++   License along with this program; if not, write to the Free Software
++   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
++   USA.  */
++
++/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
++   means there is a real alloca function.  */
++#ifndef _GL_ALLOCA_H
++#define _GL_ALLOCA_H
++
++/* alloca (N) returns a pointer to N bytes of memory
++   allocated on the stack, which will last until the function returns.
++   Use of alloca should be avoided:
++     - inside arguments of function calls - undefined behaviour,
++     - in inline functions - the allocation may actually last until the
++       calling function returns,
++     - for huge N (say, N >= 65536) - you never know how large (or small)
++       the stack is, and when the stack cannot fulfill the memory allocation
++       request, the program just crashes.
++ */
++
++#ifndef alloca
++# ifdef __GNUC__
++#  define alloca __builtin_alloca
++# elif defined _AIX
++#  define alloca __alloca
++# elif defined _MSC_VER
++#  include <malloc.h>
++#  define alloca _alloca
++# elif defined __DECC && defined __VMS
++#  define alloca __ALLOCA
++# else
++#  include <stddef.h>
++#  ifdef  __cplusplus
++extern "C"
++#  endif
++void *alloca (size_t);
++# endif
++#endif
++
++#endif /* _GL_ALLOCA_H */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f500a8f56146f85c5576c5e481630b6b943d26b2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,38 @@@
++/* Version hook for Argp.
++   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
++
++   This program is free software: you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
++
++#include <config.h>
++#include <version-etc.h>
++#include <argp.h>
++#include <argp-version-etc.h>
++
++static const char *program_canonical_name;
++static const char * const *program_authors;
++
++static void
++version_etc_hook (FILE *stream, struct argp_state *state)
++{
++  version_etc_ar (stream, program_canonical_name, PACKAGE_NAME, VERSION,
++                  program_authors);
++}
++
++void
++argp_version_setup (const char *name, const char * const *authors)
++{
++  argp_program_version_hook = version_etc_hook;
++  program_canonical_name = name;
++  program_authors = authors;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7c12c018124904a40801aeea7cd30f2b881d9738
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,40 @@@
++/* Version hook for Argp.
++   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
++
++   This program is free software: you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
++
++#ifndef _ARGP_VERSION_ETC_H
++#define _ARGP_VERSION_ETC_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Setup standard display of the version information for the `--version'
++   option.  NAME is the canonical program name, and AUTHORS is a NULL-
++   terminated array of author names. At least one author name must be
++   given.
++
++   If NAME is NULL, the package name (as given by the PACKAGE macro)
++   is asumed to be the name of the program.
++
++   This function is intended to be called before argp_parse().
++*/
++extern void argp_version_setup (const char *name, const char * const *authors);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _ARGP_VERSION_ETC_H */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b086b45aacf8a77e1eaf787533c00e3bcc515eaf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999, 2001, 2002, 2003,
++   2005, 2007 Free Software Foundation, Inc.
++
++   This file is part of the GNU C Library.
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 2, or (at your option)
++   any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program; if not, write to the Free Software Foundation,
++   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
++
++#ifndef       _FNMATCH_H
++#define       _FNMATCH_H      1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* We #undef these before defining them because some losing systems
++   (HP-UX A.08.07 for example) define these in <unistd.h>.  */
++#undef        FNM_PATHNAME
++#undef        FNM_NOESCAPE
++#undef        FNM_PERIOD
++
++/* Bits set in the FLAGS argument to `fnmatch'.  */
++#define       FNM_PATHNAME    (1 << 0) /* No wildcard can ever match `/'.  */
++#define       FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
++#define       FNM_PERIOD      (1 << 2) /* Leading `.' is matched only explicitly.  */
++
++#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
++# define FNM_FILE_NAME         FNM_PATHNAME   /* Preferred GNU name.  */
++# define FNM_LEADING_DIR (1 << 3)     /* Ignore `/...' after a match.  */
++# define FNM_CASEFOLD  (1 << 4)       /* Compare without regard to case.  */
++# define FNM_EXTMATCH  (1 << 5)       /* Use ksh-like extended matching. */
++#endif
++
++/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
++#define       FNM_NOMATCH     1
++
++/* This value is returned if the implementation does not support
++   `fnmatch'.  Since this is not the case here it will never be
++   returned but the conformance test suites still require the symbol
++   to be defined.  */
++#ifdef _XOPEN_SOURCE
++# define FNM_NOSYS    (-1)
++#endif
++
++/* Match NAME against the file name pattern PATTERN,
++   returning zero if it matches, FNM_NOMATCH if not.  */
++extern int fnmatch (const char *__pattern, const char *__name,
++                  int __flags);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* fnmatch.h */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d2d3e6e63bb484f2554713e2269972c752330aa4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,225 @@@
++/* Declarations for getopt.
++   Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2005,2006,2007
++   Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   This program is free software: you can redistribute it and/or modify
++   it under the terms of the GNU General Public License as published by
++   the Free Software Foundation; either version 3 of the License, or
++   (at your option) any later version.
++
++   This program is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++   GNU General Public License for more details.
++
++   You should have received a copy of the GNU General Public License
++   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
++
++#ifndef _GETOPT_H
++
++#ifndef __need_getopt
++# define _GETOPT_H 1
++#endif
++
++/* Standalone applications should #define __GETOPT_PREFIX to an
++   identifier that prefixes the external functions and variables
++   defined in this header.  When this happens, include the
++   headers that might declare getopt so that they will not cause
++   confusion if included after this file.  Then systematically rename
++   identifiers so that they do not collide with the system functions
++   and variables.  Renaming avoids problems with some compilers and
++   linkers.  */
++#if defined __GETOPT_PREFIX && !defined __need_getopt
++# include <stdlib.h>
++# include <stdio.h>
++# include <unistd.h>
++# undef __need_getopt
++# undef getopt
++# undef getopt_long
++# undef getopt_long_only
++# undef optarg
++# undef opterr
++# undef optind
++# undef optopt
++# define __GETOPT_CONCAT(x, y) x ## y
++# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y)
++# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y)
++# define getopt __GETOPT_ID (getopt)
++# define getopt_long __GETOPT_ID (getopt_long)
++# define getopt_long_only __GETOPT_ID (getopt_long_only)
++# define optarg __GETOPT_ID (optarg)
++# define opterr __GETOPT_ID (opterr)
++# define optind __GETOPT_ID (optind)
++# define optopt __GETOPT_ID (optopt)
++#endif
++
++/* Standalone applications get correct prototypes for getopt_long and
++   getopt_long_only; they declare "char **argv".  libc uses prototypes
++   with "char *const *argv" that are incorrect because getopt_long and
++   getopt_long_only can permute argv; this is required for backward
++   compatibility (e.g., for LSB 2.0.1).
++
++   This used to be `#if defined __GETOPT_PREFIX && !defined __need_getopt',
++   but it caused redefinition warnings if both unistd.h and getopt.h were
++   included, since unistd.h includes getopt.h having previously defined
++   __need_getopt.
++
++   The only place where __getopt_argv_const is used is in definitions
++   of getopt_long and getopt_long_only below, but these are visible
++   only if __need_getopt is not defined, so it is quite safe to rewrite
++   the conditional as follows:
++*/
++#if !defined __need_getopt
++# if defined __GETOPT_PREFIX
++#  define __getopt_argv_const /* empty */
++# else
++#  define __getopt_argv_const const
++# endif
++#endif
++
++/* If __GNU_LIBRARY__ is not already defined, either we are being used
++   standalone, or this is the first header included in the source file.
++   If we are being used with glibc, we need to include <features.h>, but
++   that does not exist if we are standalone.  So: if __GNU_LIBRARY__ is
++   not defined, include <ctype.h>, which will pull in <features.h> for us
++   if it's from glibc.  (Why ctype.h?  It's guaranteed to exist and it
++   doesn't flood the namespace with stuff the way some other headers do.)  */
++#if !defined __GNU_LIBRARY__
++# include <ctype.h>
++#endif
++
++#ifndef __THROW
++# ifndef __GNUC_PREREQ
++#  define __GNUC_PREREQ(maj, min) (0)
++# endif
++# if defined __cplusplus && __GNUC_PREREQ (2,8)
++#  define __THROW     throw ()
++# else
++#  define __THROW
++# endif
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* For communication from `getopt' to the caller.
++   When `getopt' finds an option that takes an argument,
++   the argument value is returned here.
++   Also, when `ordering' is RETURN_IN_ORDER,
++   each non-option ARGV-element is returned here.  */
++
++extern char *optarg;
++
++/* Index in ARGV of the next element to be scanned.
++   This is used for communication to and from the caller
++   and for communication between successive calls to `getopt'.
++
++   On entry to `getopt', zero means this is the first call; initialize.
++
++   When `getopt' returns -1, this is the index of the first of the
++   non-option elements that the caller should itself scan.
++
++   Otherwise, `optind' communicates from one call to the next
++   how much of ARGV has been scanned so far.  */
++
++extern int optind;
++
++/* Callers store zero here to inhibit the error message `getopt' prints
++   for unrecognized options.  */
++
++extern int opterr;
++
++/* Set to an option character which was unrecognized.  */
++
++extern int optopt;
++
++#ifndef __need_getopt
++/* Describe the long-named options requested by the application.
++   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
++   of `struct option' terminated by an element containing a name which is
++   zero.
++
++   The field `has_arg' is:
++   no_argument                (or 0) if the option does not take an argument,
++   required_argument  (or 1) if the option requires an argument,
++   optional_argument  (or 2) if the option takes an optional argument.
++
++   If the field `flag' is not NULL, it points to a variable that is set
++   to the value given in the field `val' when the option is found, but
++   left unchanged if the option is not found.
++
++   To have a long-named option do something other than set an `int' to
++   a compiled-in constant, such as set a value from `optarg', set the
++   option's `flag' field to zero and its `val' field to a nonzero
++   value (the equivalent single-letter option character, if there is
++   one).  For long options that have a zero `flag' field, `getopt'
++   returns the contents of the `val' field.  */
++
++struct option
++{
++  const char *name;
++  /* has_arg can't be an enum because some compilers complain about
++     type mismatches in all the code that assumes it is an int.  */
++  int has_arg;
++  int *flag;
++  int val;
++};
++
++/* Names for the values of the `has_arg' field of `struct option'.  */
++
++# define no_argument          0
++# define required_argument    1
++# define optional_argument    2
++#endif        /* need getopt */
++
++
++/* Get definitions and prototypes for functions to process the
++   arguments in ARGV (ARGC of them, minus the program name) for
++   options given in OPTS.
++
++   Return the option character from OPTS just read.  Return -1 when
++   there are no more options.  For unrecognized options, or options
++   missing arguments, `optopt' is set to the option letter, and '?' is
++   returned.
++
++   The OPTS string is a list of characters which are recognized option
++   letters, optionally followed by colons, specifying that that letter
++   takes an argument, to be placed in `optarg'.
++
++   If a letter in OPTS is followed by two colons, its argument is
++   optional.  This behavior is specific to the GNU `getopt'.
++
++   The argument `--' causes premature termination of argument
++   scanning, explicitly telling `getopt' that there are no more
++   options.
++
++   If OPTS begins with `-', then non-option arguments are treated as
++   arguments to the option '\1'.  This behavior is specific to the GNU
++   `getopt'.  If OPTS begins with `+', or POSIXLY_CORRECT is set in
++   the environment, then do not permute arguments.  */
++
++extern int getopt (int ___argc, char *const *___argv, const char *__shortopts)
++       __THROW;
++
++#ifndef __need_getopt
++extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv,
++                      const char *__shortopts,
++                      const struct option *__longopts, int *__longind)
++       __THROW;
++extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv,
++                           const char *__shortopts,
++                           const struct option *__longopts, int *__longind)
++       __THROW;
++
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++/* Make sure we later can get all the definitions and declarations.  */
++#undef __need_getopt
++
++#endif /* getopt.h */
index 0000000000000000000000000000000000000000,807ee4277b1048b4901f5b6fb76d9f46230ad9c4..600b7f1857bdc2e3326581b77a09ccda2347e0b0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,604 +1,600 @@@
 -grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t,
 -          struct grub_disk_ata_pass_through_parms *);
 -
 -
+ /*
+  *  GRUB  --  GRand Unified Bootloader
+  *  Copyright (C) 2002,2003,2004,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 <http://www.gnu.org/licenses/>.
+  */
+ #include <grub/disk.h>
+ #include <grub/err.h>
+ #include <grub/mm.h>
+ #include <grub/types.h>
+ #include <grub/partition.h>
+ #include <grub/misc.h>
+ #include <grub/time.h>
+ #include <grub/file.h>
+ #define       GRUB_CACHE_TIMEOUT      2
+ /* The last time the disk was used.  */
+ static grub_uint64_t grub_last_time = 0;
+ /* Disk cache.  */
+ struct grub_disk_cache
+ {
+   enum grub_disk_dev_id dev_id;
+   unsigned long disk_id;
+   grub_disk_addr_t sector;
+   char *data;
+   int lock;
+ };
+ 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;
+ #if 0
+ static unsigned long grub_disk_cache_hits;
+ static unsigned long grub_disk_cache_misses;
+ void
+ grub_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
+ {
+   *hits = grub_disk_cache_hits;
+   *misses = grub_disk_cache_misses;
+ }
+ #endif
+ static unsigned
+ grub_disk_cache_get_index (unsigned long dev_id, unsigned long disk_id,
+                          grub_disk_addr_t sector)
+ {
+   return ((dev_id * 524287UL + disk_id * 2606459UL
+          + ((unsigned) (sector >> GRUB_DISK_CACHE_BITS)))
+         % GRUB_DISK_CACHE_NUM);
+ }
+ static void
+ grub_disk_cache_invalidate (unsigned long dev_id, unsigned long disk_id,
+                           grub_disk_addr_t sector)
+ {
+   unsigned index;
+   struct grub_disk_cache *cache;
+   sector &= ~(GRUB_DISK_CACHE_SIZE - 1);
+   index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+   cache = grub_disk_cache_table + index;
+   if (cache->dev_id == dev_id && cache->disk_id == disk_id
+       && cache->sector == sector && cache->data)
+     {
+       cache->lock = 1;
+       grub_free (cache->data);
+       cache->data = 0;
+       cache->lock = 0;
+     }
+ }
+ void
+ grub_disk_cache_invalidate_all (void)
+ {
+   unsigned i;
+   for (i = 0; i < GRUB_DISK_CACHE_NUM; i++)
+     {
+       struct grub_disk_cache *cache = grub_disk_cache_table + i;
+       if (cache->data && ! cache->lock)
+       {
+         grub_free (cache->data);
+         cache->data = 0;
+       }
+     }
+ }
+ static char *
+ grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
+                      grub_disk_addr_t sector)
+ {
+   struct grub_disk_cache *cache;
+   unsigned index;
+   index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+   cache = grub_disk_cache_table + index;
+   if (cache->dev_id == dev_id && cache->disk_id == disk_id
+       && cache->sector == sector)
+     {
+       cache->lock = 1;
+ #if 0
+       grub_disk_cache_hits++;
+ #endif
+       return cache->data;
+     }
+ #if 0
+   grub_disk_cache_misses++;
+ #endif
+   return 0;
+ }
+ static void
+ grub_disk_cache_unlock (unsigned long dev_id, unsigned long disk_id,
+                       grub_disk_addr_t sector)
+ {
+   struct grub_disk_cache *cache;
+   unsigned index;
+   index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+   cache = grub_disk_cache_table + index;
+   if (cache->dev_id == dev_id && cache->disk_id == disk_id
+       && cache->sector == sector)
+     cache->lock = 0;
+ }
+ static grub_err_t
+ grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
+                      grub_disk_addr_t sector, const char *data)
+ {
+   unsigned index;
+   struct grub_disk_cache *cache;
+   index = grub_disk_cache_get_index (dev_id, disk_id, sector);
+   cache = grub_disk_cache_table + index;
+   cache->lock = 1;
+   grub_free (cache->data);
+   cache->data = 0;
+   cache->lock = 0;
+   cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+   if (! cache->data)
+     return grub_errno;
+   grub_memcpy (cache->data, data,
+              GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+   cache->dev_id = dev_id;
+   cache->disk_id = disk_id;
+   cache->sector = sector;
+   return GRUB_ERR_NONE;
+ }
\f
+ static grub_disk_dev_t grub_disk_dev_list;
+ void
+ grub_disk_dev_register (grub_disk_dev_t dev)
+ {
+   dev->next = grub_disk_dev_list;
+   grub_disk_dev_list = dev;
+ }
+ void
+ grub_disk_dev_unregister (grub_disk_dev_t dev)
+ {
+   grub_disk_dev_t *p, q;
+   for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
+     if (q == dev)
+       {
+         *p = q->next;
+       break;
+       }
+ }
+ int
+ grub_disk_dev_iterate (int (*hook) (const char *name))
+ {
+   grub_disk_dev_t p;
+   for (p = grub_disk_dev_list; p; p = p->next)
+     if (p->iterate && (p->iterate) (hook))
+       return 1;
+   return 0;
+ }
+ /* Return the location of the first ',', if any, which is not
+    escaped by a '\'.  */
+ static const char *
+ find_part_sep (const char *name)
+ {
+   const char *p = name;
+   char c;
+   while ((c = *p++) != '\0')
+     {
+       if (c == '\\' && *p == ',')
+       p++;
+       else if (c == ',')
+       return p - 1;
+     }
+   return NULL;
+ }
+ grub_disk_t
+ grub_disk_open (const char *name)
+ {
+   const char *p;
+   grub_disk_t disk;
+   grub_disk_dev_t dev;
+   char *raw = (char *) name;
+   grub_uint64_t current_time;
+   grub_dprintf ("disk", "Opening `%s'...\n", name);
+   disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
+   if (! disk)
+     return 0;
+   p = find_part_sep (name);
+   if (p)
+     {
+       grub_size_t len = p - name;
+       raw = grub_malloc (len + 1);
+       if (! raw)
+       goto fail;
+       grub_memcpy (raw, name, len);
+       raw[len] = '\0';
+       disk->name = grub_strdup (raw);
+     }
+   else
+     disk->name = grub_strdup (name);
+   if (! disk->name)
+     goto fail;
+   for (dev = grub_disk_dev_list; dev; dev = dev->next)
+     {
+       if ((dev->open) (raw, disk) == GRUB_ERR_NONE)
+       break;
+       else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+       grub_errno = GRUB_ERR_NONE;
+       else
+       goto fail;
+     }
+   if (! dev)
+     {
+       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk");
+       goto fail;
+     }
+   disk->dev = dev;
+   if (p)
+     {
+       disk->partition = grub_partition_probe (disk, p + 1);
+       if (! disk->partition)
+       {
+         grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such partition");
+         goto fail;
+       }
+     }
+   /* The cache will be invalidated about 2 seconds after a device was
+      closed.  */
+   current_time = grub_get_time_ms ();
+   if (current_time > (grub_last_time
+                     + GRUB_CACHE_TIMEOUT * 1000))
+     grub_disk_cache_invalidate_all ();
+   grub_last_time = current_time;
+  fail:
+   if (raw && raw != name)
+     grub_free (raw);
+   if (grub_errno != GRUB_ERR_NONE)
+     {
+       grub_error_push ();
+       grub_dprintf ("disk", "Opening `%s' failed.\n", name);
+       grub_error_pop ();
+       grub_disk_close (disk);
+       return 0;
+     }
+   return disk;
+ }
+ void
+ grub_disk_close (grub_disk_t disk)
+ {
+   grub_partition_t part;
+   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
+   if (disk->dev && disk->dev->close)
+     (disk->dev->close) (disk);
+   /* Reset the timer.  */
+   grub_last_time = grub_get_time_ms ();
+   while (disk->partition)
+     {
+       part = disk->partition->parent;
+       grub_free (disk->partition);
+       disk->partition = part;
+     }
+   grub_free ((void *) disk->name);
+   grub_free (disk);
+ }
+ /* This function performs three tasks:
+    - Make sectors disk relative from partition relative.
+    - Normalize offset to be less than the sector size.
+    - Verify that the range is inside the partition.  */
+ static grub_err_t
+ grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
+                       grub_off_t *offset, grub_size_t size)
+ {
+   grub_partition_t part;
+   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
+   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
+   for (part = disk->partition; part; part = part->parent)
+     {
+       grub_disk_addr_t start;
+       grub_uint64_t len;
+       start = part->start;
+       len = part->len;
+       if (*sector >= len
+         || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+                             >> GRUB_DISK_SECTOR_BITS))
+       return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of partition");
+       *sector += start;
+     }
+   if (disk->total_sectors <= *sector
+       || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+         >> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector)
+     return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk");
+   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;
+   /* First of all, check if the region is within the disk.  */
+   if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
+     {
+       grub_error_push ();
+       grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
+                   (unsigned long long) sector, grub_errmsg);
+       grub_error_pop ();
+       return grub_errno;
+     }
+   real_offset = offset;
+   /* 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)
+     {
+       char *data;
+       grub_disk_addr_t start_sector;
+       grub_size_t len;
+       grub_size_t pos;
+       /* 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);
+       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;
+       buf = (char *) buf + len;
+       size -= len;
+       real_offset = 0;
+     }
+  finish:
+   grub_free (tmp_buf);
+   return grub_errno;
+ }
+ grub_err_t
+ 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_dprintf ("disk", "Writing `%s'...\n", disk->name);
+   if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
+     return -1;
+   real_offset = offset;
+   while (size)
+     {
+       if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
+       {
+         char tmp_buf[GRUB_DISK_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)
+             != GRUB_ERR_NONE)
+           {
+             disk->partition = part;
+             goto finish;
+           }
+         disk->partition = part;
+         len = GRUB_DISK_SECTOR_SIZE - real_offset;
+         if (len > size)
+           len = size;
+         grub_memcpy (tmp_buf + real_offset, buf, len);
+         grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
+         if ((disk->dev->write) (disk, sector, 1, tmp_buf) != GRUB_ERR_NONE)
+           goto finish;
+         sector++;
+         buf = (char *) buf + len;
+         size -= len;
+         real_offset = 0;
+       }
+       else
+       {
+         grub_size_t len;
+         grub_size_t n;
+         len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
+         n = size >> GRUB_DISK_SECTOR_BITS;
+         if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
+           goto finish;
+         while (n--)
+           grub_disk_cache_invalidate (disk->dev->id, disk->id, sector++);
+         buf = (char *) buf + len;
+         size -= len;
+       }
+     }
+  finish:
+   return grub_errno;
+ }
+ grub_uint64_t
+ grub_disk_get_size (grub_disk_t disk)
+ {
+   if (disk->partition)
+     return grub_partition_get_len (disk->partition);
+   else
+     return disk->total_sectors;
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9fb98739bbe4945ca24d3060c3646eae7390150d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,28 @@@
++/*  init.c -- Initialize GRUB on Open Firmware.  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/types.h>
++#include <grub/cache.h>
++
++void grub_stop_floppy (void);
++
++void
++grub_stop_floppy (void)
++{
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ed57c43ca36ab3f1764d3b0b8f18d41d5ff6cad9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,120 @@@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++
++/*
++ * Note: These functions defined in this file may be called from C.
++ *       Be careful of that you must not modify some registers. Quote
++ *       from gcc-2.95.2/gcc/config/i386/i386.h:
++
++   1 for registers not available across function calls.
++   These must include the FIXED_REGISTERS and also any
++   registers that can be used without being saved.
++   The latter must include the registers where values are returned
++   and the register where structure-value addresses are passed.
++   Aside from that, you can include as many other registers as you like.
++
++  ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
++{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1 }
++ */
++
++/*
++ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
++ *       So the first three arguments are passed in %eax, %edx, and %ecx,
++ *       respectively, and if a function has a fixed number of arguments
++ *       and the number if greater than three, the function must return
++ *       with "ret $N" where N is ((the number of arguments) - 3) * 4.
++ */
++
++/*
++ *  This is the area for all of the special variables.
++ */
++
++      .p2align        2       /* force 4-byte alignment */
++
++/*
++ * void grub_linux_boot_zimage (void)
++ */
++VARIABLE(grub_linux_prot_size)
++      .long   0
++VARIABLE(grub_linux_tmp_addr)
++      .long   0
++VARIABLE(grub_linux_real_addr)
++      .long   0
++VARIABLE(grub_linux_is_bzimage)
++      .long   0
++
++FUNCTION(grub_linux16_real_boot)
++      /* Must be done before zImage copy.  */
++      call    EXT_C(grub_dl_unload_all)
++
++      movl    EXT_C(grub_linux_is_bzimage), %ebx
++      test    %ebx, %ebx
++      jne bzimage
++
++      /* copy the kernel */
++      movl    EXT_C(grub_linux_prot_size), %ecx
++      addl    $3, %ecx
++      shrl    $2, %ecx
++      movl    $GRUB_LINUX_BZIMAGE_ADDR, %esi
++      movl    $GRUB_LINUX_ZIMAGE_ADDR, %edi
++      cld
++      rep
++      movsl
++
++bzimage:
++      movl    EXT_C(grub_linux_real_addr), %ebx
++
++      /* copy the real mode code */
++      movl    EXT_C(grub_linux_tmp_addr), %esi
++      movl    %ebx, %edi
++      movl    $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx
++      cld
++      rep
++      movsb
++
++      /* change %ebx to the segment address */
++      shrl    $4, %ebx
++      movl    %ebx, %eax
++      addl    $0x20, %eax
++      movw    %ax, linux_setup_seg
++
++      /* XXX new stack pointer in safe area for calling functions */
++      movl    $0x4000, %esp
++      call    EXT_C(grub_stop_floppy)
++
++      /* final setup for linux boot */
++      call    prot_to_real
++      .code16
++
++      cli
++      movw    %bx, %ss
++      movw    $GRUB_LINUX_SETUP_STACK, %sp
++
++      movw    %bx, %ds
++      movw    %bx, %es
++      movw    %bx, %fs
++      movw    %bx, %gs
++
++      /* ljmp */
++      .byte   0xea
++      .word   0
++linux_setup_seg:
++      .word   0
++      .code32
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7d57df9b9541f4d9a77beba52b30dd63c30c8c43
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,29 @@@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/symbol.h>
++
++      .text
++/*
++ *  This call is special...  it never returns...  in fact it should simply
++ *  hang at this point!
++ */
++FUNCTION(grub_stop)
++      cli
++1:    hlt
++      jmp     1b
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bc0d8aa8d0d4d96dfefd73c7acc46deb1312f382
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,75 @@@
++/* crc.c - crc function  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2008  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/types.h>
++#include <grub/lib/crc.h>
++
++static grub_uint32_t crc32_table [256];
++
++static void
++init_crc32_table (void)
++{
++  auto grub_uint32_t reflect (grub_uint32_t ref, int len);
++  grub_uint32_t reflect (grub_uint32_t ref, int len)
++    {
++      grub_uint32_t result = 0;
++      int i;
++
++      for (i = 1; i <= len; i++)
++        {
++          if (ref & 1)
++            result |= 1 << (len - i);
++          ref >>= 1;
++        }
++
++      return result;
++    }
++
++  grub_uint32_t polynomial = 0x04c11db7;
++  int i, j;
++
++  for(i = 0; i < 256; i++)
++    {
++      crc32_table[i] = reflect(i, 8) << 24;
++      for (j = 0; j < 8; j++)
++        crc32_table[i] = (crc32_table[i] << 1) ^
++            (crc32_table[i] & (1 << 31) ? polynomial : 0);
++      crc32_table[i] = reflect(crc32_table[i], 32);
++    }
++}
++
++grub_uint32_t
++grub_getcrc32 (grub_uint32_t crc, void *buf, int size)
++{
++  int i;
++  grub_uint8_t *data = buf;
++
++  if (! crc32_table[1])
++    init_crc32_table ();
++
++  crc^= 0xffffffff;
++
++  for (i = 0; i < size; i++)
++    {
++      crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data];
++      data++;
++    }
++
++  return crc ^ 0xffffffff;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..25aee3a8051be06101e64ff611fab3ab3a99fdaf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,45 @@@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,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 <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/symbol.h>
++
++      .p2align        2
++
++
++      .code32
++
++/*
++ * Use cdecl calling convention for *BSD kernels.
++ */
++
++FUNCTION(grub_unix_real_boot)
++
++      /* Interrupts should be disabled.  */
++        cli
++
++      /* Discard `grub_unix_real_boot' return address.  */
++        popl    %eax
++
++        /* Fetch `entry' address ...  */
++        popl  %eax
++
++        /*
++         * ... and put our return address in its place. The kernel will
++         * ignore it, but it expects %esp to point to it.
++         */
++        call  *%eax
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a568fff4d25fbd292aac64b1d7aa48668d90021d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,124 @@@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (c) 2003  Peter Wemm <peter@FreeBSD.org>
++ *  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 <http://www.gnu.org/licenses/>.
++ */
++
++/* Based on the code from FreeBSD originally distributed under the
++   following terms: */
++
++/*-
++ * Copyright (c) 2003  Peter Wemm <peter@FreeBSD.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * $FreeBSD$
++ */
++
++
++#define MSR_EFER      0xc0000080
++#define EFER_LME      0x00000100
++#define CR4_PAE               0x00000020
++#define CR4_PSE               0x00000010
++#define CR0_PG                0x80000000
++
++#include <grub/symbol.h>
++
++      .p2align        2
++
++      .code32
++
++
++VARIABLE(grub_bsd64_trampoline_start)
++
++      /* Discard `grub_unix_real_boot' return address.  */
++        popl    %eax
++
++        /* entry  */
++        popl  %edi
++
++        /* entry_hi  */
++        popl  %esi
++
++      cli
++
++      /* Turn on EFER.LME.  */
++      movl    $MSR_EFER, %ecx
++      rdmsr
++      orl     $EFER_LME, %eax
++        wrmsr
++
++      /* Turn on PAE.  */
++      movl    %cr4, %eax
++      orl     $(CR4_PAE | CR4_PSE), %eax
++      movl    %eax, %cr4
++
++      /* Set %cr3 for PT4.  */
++      popl    %eax
++      movl    %eax, %cr3
++
++      /* Push a dummy return address.  */
++      pushl   %eax
++
++      /* Turn on paging (implicitly sets EFER.LMA).  */
++      movl    %cr0, %eax
++      orl     $CR0_PG, %eax
++      movl    %eax, %cr0
++
++      /* Now we're in compatibility mode. set %cs for long mode.  */
++      /* lgdt */
++      .byte 0x0f
++      .byte 0x01
++      .byte 0x15
++VARIABLE (grub_bsd64_trampoline_gdt)
++      .long 0x0
++
++      /* ljmp */
++      .byte 0xea
++VARIABLE (grub_bsd64_trampoline_selfjump)
++      .long 0x0
++      .word 0x08
++
++      .code64
++
++bsd64_longmode:
++         /* We're still running V=P, jump to entry point.  */
++      movl    %esi, %eax
++      salq    $32, %rax
++      orq     %rdi, %rax
++      pushq   %rax
++      ret
++VARIABLE(grub_bsd64_trampoline_end)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d37feb983364a18b412757a22637cf92defc3d8c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,945 @@@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/loader.h>
++#include <grub/machine/loader.h>
++#include <grub/file.h>
++#include <grub/disk.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/cpu/linux.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/command.h>
++#include <grub/memory.h>
++#include <grub/env.h>
++#include <grub/video.h>
++#include <grub/time.h>
++#include <grub/i18n.h>
++
++#define GRUB_LINUX_CL_OFFSET          0x1000
++#define GRUB_LINUX_CL_END_OFFSET      0x2000
++
++#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
++  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
++
++static grub_dl_t my_mod;
++
++static grub_size_t linux_mem_size;
++static int loaded;
++static void *real_mode_mem;
++static void *prot_mode_mem;
++static void *initrd_mem;
++static grub_efi_uintn_t real_mode_pages;
++static grub_efi_uintn_t prot_mode_pages;
++static grub_efi_uintn_t initrd_pages;
++static void *mmap_buf;
++
++static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
++  {
++    /* NULL.  */
++    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++    /* Reserved.  */
++    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++    /* Code segment.  */
++    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
++    /* Data segment.  */
++    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
++  };
++
++struct gdt_descriptor
++{
++  grub_uint16_t limit;
++  void *base;
++} __attribute__ ((packed));
++
++static struct gdt_descriptor gdt_desc =
++  {
++    sizeof (gdt) - 1,
++    gdt
++  };
++
++struct idt_descriptor
++{
++  grub_uint16_t limit;
++  void *base;
++} __attribute__ ((packed));
++
++static struct idt_descriptor idt_desc =
++  {
++    0,
++    0
++  };
++
++static inline grub_size_t
++page_align (grub_size_t size)
++{
++  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
++}
++
++/* Find the optimal number of pages for the memory map. Is it better to
++   move this code to efi/mm.c?  */
++static grub_efi_uintn_t
++find_mmap_size (void)
++{
++  static grub_efi_uintn_t mmap_size = 0;
++
++  if (mmap_size != 0)
++    return mmap_size;
++
++  mmap_size = (1 << 12);
++  while (1)
++    {
++      int ret;
++      grub_efi_memory_descriptor_t *mmap;
++      grub_efi_uintn_t desc_size;
++
++      mmap = grub_malloc (mmap_size);
++      if (! mmap)
++      return 0;
++
++      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
++      grub_free (mmap);
++
++      if (ret < 0)
++      grub_fatal ("cannot get memory map");
++      else if (ret > 0)
++      break;
++
++      mmap_size += (1 << 12);
++    }
++
++  /* Increase the size a bit for safety, because GRUB allocates more on
++     later, and EFI itself may allocate more.  */
++  mmap_size += (1 << 12);
++
++  return page_align (mmap_size);
++}
++
++static void
++free_pages (void)
++{
++  if (real_mode_mem)
++    {
++      grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages);
++      real_mode_mem = 0;
++    }
++
++  if (prot_mode_mem)
++    {
++      grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages);
++      prot_mode_mem = 0;
++    }
++
++  if (initrd_mem)
++    {
++      grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
++      initrd_mem = 0;
++    }
++}
++
++/* Allocate pages for the real mode code and the protected mode code
++   for linux as well as a memory map buffer.  */
++static int
++allocate_pages (grub_size_t prot_size)
++{
++  grub_efi_uintn_t desc_size;
++  grub_efi_memory_descriptor_t *mmap, *mmap_end;
++  grub_efi_uintn_t mmap_size, tmp_mmap_size;
++  grub_efi_memory_descriptor_t *desc;
++  grub_size_t real_size;
++
++  /* Make sure that each size is aligned to a page boundary.  */
++  real_size = GRUB_LINUX_CL_END_OFFSET;
++  prot_size = page_align (prot_size);
++  mmap_size = find_mmap_size ();
++
++  grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
++              (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
++
++  /* Calculate the number of pages; Combine the real mode code with
++     the memory map buffer for simplicity.  */
++  real_mode_pages = ((real_size + mmap_size) >> 12);
++  prot_mode_pages = (prot_size >> 12);
++
++  /* Initialize the memory pointers with NULL for convenience.  */
++  real_mode_mem = 0;
++  prot_mode_mem = 0;
++
++  /* Read the memory map temporarily, to find free space.  */
++  mmap = grub_malloc (mmap_size);
++  if (! mmap)
++    return 0;
++
++  tmp_mmap_size = mmap_size;
++  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
++    grub_fatal ("cannot get memory map");
++
++  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
++
++  /* First, find free pages for the real mode code
++     and the memory map buffer.  */
++  for (desc = mmap;
++       desc < mmap_end;
++       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
++    {
++      /* Probably it is better to put the real mode code in the traditional
++       space for safety.  */
++      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
++        && desc->physical_start <= 0x90000
++        && desc->num_pages >= real_mode_pages)
++      {
++        grub_efi_physical_address_t physical_end;
++        grub_efi_physical_address_t addr;
++
++        physical_end = desc->physical_start + (desc->num_pages << 12);
++        if (physical_end > 0x90000)
++          physical_end = 0x90000;
++
++        grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
++                      (unsigned) desc->physical_start,
++                      (unsigned) physical_end);
++        addr = physical_end - real_size - mmap_size;
++        if (addr < 0x10000)
++          continue;
++
++        grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
++                      (unsigned) real_mode_pages, (unsigned long) addr);
++        real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
++        if (! real_mode_mem)
++          grub_fatal ("cannot allocate pages");
++
++        desc->num_pages -= real_mode_pages;
++        break;
++      }
++    }
++
++  if (! real_mode_mem)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
++      goto fail;
++    }
++
++  mmap_buf = (void *) ((char *) real_mode_mem + real_size);
++
++  /* Next, find free pages for the protected mode code.  */
++  /* XXX what happens if anything is using this address?  */
++  prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1);
++  if (! prot_mode_mem)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY,
++                "cannot allocate protected mode pages");
++      goto fail;
++    }
++
++  grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
++              "prot_mode_mem = %lx, prot_mode_pages = %x\n",
++              (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
++              (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
++
++  grub_free (mmap);
++  return 1;
++
++ fail:
++  grub_free (mmap);
++  free_pages ();
++  return 0;
++}
++
++static void
++grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
++                    grub_uint64_t start, grub_uint64_t size,
++                    grub_uint32_t type)
++{
++  int n = *e820_num;
++
++  if (n >= GRUB_E820_MAX_ENTRY)
++    grub_fatal ("Too many e820 memory map entries");
++
++  if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
++      (e820_map[n - 1].type == type))
++      e820_map[n - 1].size += size;
++  else
++    {
++      e820_map[n].addr = start;
++      e820_map[n].size = size;
++      e820_map[n].type = type;
++      (*e820_num)++;
++    }
++}
++
++static grub_err_t
++grub_linux_setup_video (struct linux_kernel_params *params)
++{
++  struct grub_video_mode_info mode_info;
++  void *framebuffer;
++  grub_err_t err;
++
++  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
++
++  if (err)
++    return err;
++
++  params->lfb_width = mode_info.width;
++  params->lfb_height = mode_info.height;
++  params->lfb_depth = mode_info.bpp;
++  params->lfb_line_len = mode_info.pitch;
++
++  params->lfb_base = (grub_size_t) framebuffer;
++  params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height,
++                             65536);
++
++  params->red_mask_size = mode_info.red_mask_size;
++  params->red_field_pos = mode_info.red_field_pos;
++  params->green_mask_size = mode_info.green_mask_size;
++  params->green_field_pos = mode_info.green_field_pos;
++  params->blue_mask_size = mode_info.blue_mask_size;
++  params->blue_field_pos = mode_info.blue_field_pos;
++  params->reserved_mask_size = mode_info.reserved_mask_size;
++  params->reserved_field_pos = mode_info.reserved_field_pos;
++
++  params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
++
++#ifdef GRUB_MACHINE_PCBIOS
++  /* VESA packed modes may come with zeroed mask sizes, which need
++     to be set here according to DAC Palette width.  If we don't,
++     this results in Linux displaying a black screen.  */
++  if (mode_info.bpp <= 8)
++    {
++      struct grub_vbe_info_block controller_info;
++      int status;
++      int width = 8;
++
++      status = grub_vbe_bios_get_controller_info (&controller_info);
++
++      if (status == GRUB_VBE_STATUS_OK &&
++        (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
++      status = grub_vbe_bios_set_dac_palette_width (&width);
++
++      if (status != GRUB_VBE_STATUS_OK)
++      /* 6 is default after mode reset.  */
++      width = 6;
++
++      params->red_mask_size = params->green_mask_size
++      = params->blue_mask_size = width;
++      params->reserved_mask_size = 0;
++    }
++#endif
++
++  return 0;
++}
++
++#ifdef __x86_64__
++extern grub_uint8_t grub_linux_trampoline_start[];
++extern grub_uint8_t grub_linux_trampoline_end[];
++#endif
++
++static grub_err_t
++grub_linux_boot (void)
++{
++  struct linux_kernel_params *params;
++  grub_efi_uintn_t mmap_size;
++  grub_efi_uintn_t map_key;
++  grub_efi_uintn_t desc_size;
++  grub_efi_uint32_t desc_version;
++  int e820_num;
++  const char *modevar;
++  char *tmp;
++  grub_err_t err;
++
++  params = real_mode_mem;
++
++  grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
++              (unsigned) params->code32_start,
++              (unsigned long) &(idt_desc.limit),
++              (unsigned long) &(gdt_desc.limit));
++  grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
++              (unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
++              (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
++
++  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
++  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
++    {
++      switch (type)
++        {
++        case GRUB_MACHINE_MEMORY_AVAILABLE:
++        grub_e820_add_region (params->e820_map, &e820_num,
++                              addr, size, GRUB_E820_RAM);
++        break;
++
++#ifdef GRUB_MACHINE_MEMORY_ACPI
++        case GRUB_MACHINE_MEMORY_ACPI:
++        grub_e820_add_region (params->e820_map, &e820_num,
++                              addr, size, GRUB_E820_ACPI);
++        break;
++#endif
++
++#ifdef GRUB_MACHINE_MEMORY_NVS
++        case GRUB_MACHINE_MEMORY_NVS:
++        grub_e820_add_region (params->e820_map, &e820_num,
++                              addr, size, GRUB_E820_NVS);
++        break;
++#endif
++
++#ifdef GRUB_MACHINE_MEMORY_CODE
++        case GRUB_MACHINE_MEMORY_CODE:
++        grub_e820_add_region (params->e820_map, &e820_num,
++                              addr, size, GRUB_E820_EXEC_CODE);
++        break;
++#endif
++
++        default:
++          grub_e820_add_region (params->e820_map, &e820_num,
++                                addr, size, GRUB_E820_RESERVED);
++        }
++      return 0;
++    }
++
++  e820_num = 0;
++  grub_mmap_iterate (hook);
++  params->mmap_size = e820_num;
++
++  grub_dprintf ("linux", "Trampoline at %p. code32=%x, real_mode_mem=%p\n",
++              ((char *) prot_mode_mem + (prot_mode_pages << 12)),
++              (unsigned) params->code32_start, real_mode_mem);
++
++  modevar = grub_env_get ("gfxpayload");
++
++  /* Now all graphical modes are acceptable.
++     May change in future if we have modes without framebuffer.  */
++  if (modevar && *modevar != 0)
++    {
++      tmp = grub_xasprintf ("%s;auto", modevar);
++      if (! tmp)
++      return grub_errno;
++      err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
++      grub_free (tmp);
++    }
++  else
++    err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
++
++  if (!err)
++    err = grub_linux_setup_video (params);
++
++  if (err)
++    {
++      grub_print_error ();
++      grub_printf ("Booting however\n");
++      grub_errno = GRUB_ERR_NONE;
++    }
++
++  mmap_size = find_mmap_size ();
++  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
++                             &desc_size, &desc_version) <= 0)
++    grub_fatal ("cannot get memory map");
++
++  if (! grub_efi_exit_boot_services (map_key))
++     grub_fatal ("cannot exit boot services");
++
++  /* Note that no boot services are available from here.  */
++
++  /* Pass EFI parameters.  */
++  if (grub_le_to_cpu16 (params->version) >= 0x0206)
++    {
++      params->v0206.efi_mem_desc_size = desc_size;
++      params->v0206.efi_mem_desc_version = desc_version;
++      params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
++      params->v0206.efi_mmap_size = mmap_size;
++#ifdef __x86_64__
++      params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32);
++#endif
++    }
++  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
++    {
++      params->v0204.efi_mem_desc_size = desc_size;
++      params->v0204.efi_mem_desc_version = desc_version;
++      params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
++      params->v0204.efi_mmap_size = mmap_size;
++    }
++
++#ifdef __x86_64__
++
++  grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12),
++             grub_linux_trampoline_start,
++             grub_linux_trampoline_end - grub_linux_trampoline_start);
++
++  ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
++                                     + (prot_mode_pages << 12)))
++    (params->code32_start, real_mode_mem);
++
++#else
++
++  /* Hardware interrupts are not safe any longer.  */
++  asm volatile ("cli" : : );
++
++  /* Load the IDT and the GDT for the bootstrap.  */
++  asm volatile ("lidt %0" : : "m" (idt_desc));
++  asm volatile ("lgdt %0" : : "m" (gdt_desc));
++
++  /* Pass parameters.  */
++  asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start));
++  asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
++
++  asm volatile ("xorl %%ebx, %%ebx" : : );
++
++  /* Enter Linux.  */
++  asm volatile ("jmp *%%ecx" : : );
++
++#endif
++
++  /* Never reach here.  */
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_linux_unload (void)
++{
++  free_pages ();
++  grub_dl_unref (my_mod);
++  loaded = 0;
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
++              int argc, char *argv[])
++{
++  grub_file_t file = 0;
++  struct linux_kernel_header lh;
++  struct linux_kernel_params *params;
++  grub_uint8_t setup_sects;
++  grub_size_t real_size, prot_size;
++  grub_ssize_t len;
++  int i;
++  char *dest;
++
++  grub_dl_ref (my_mod);
++
++  if (argc == 0)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
++      goto fail;
++    }
++
++  file = grub_file_open (argv[0]);
++  if (! file)
++    goto fail;
++
++  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++    {
++      grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
++      goto fail;
++    }
++
++  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
++    {
++      grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
++      goto fail;
++    }
++
++  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
++    {
++      grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
++      goto fail;
++    }
++
++  /* EFI support is quite new, so reject old versions.  */
++  if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
++      || grub_le_to_cpu16 (lh.version) < 0x0203)
++    {
++      grub_error (GRUB_ERR_BAD_OS, "too old version");
++      goto fail;
++    }
++
++  /* I'm not sure how to support zImage on EFI.  */
++  if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
++    {
++      grub_error (GRUB_ERR_BAD_OS, "zImage is not supported");
++      goto fail;
++    }
++
++  setup_sects = lh.setup_sects;
++
++  /* If SETUP_SECTS is not set, set it to the default (4).  */
++  if (! setup_sects)
++    setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
++
++  real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
++  prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
++
++  if (! allocate_pages (prot_size))
++    goto fail;
++
++  params = (struct linux_kernel_params *) real_mode_mem;
++  grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
++  grub_memcpy (&params->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
++
++  params->ps_mouse = params->padding10 =  0;
++
++  len = 0x400 - sizeof (lh);
++  if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
++    {
++      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++      goto fail;
++    }
++
++  params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4);
++
++  params->cl_magic = GRUB_LINUX_CL_MAGIC;
++  params->cl_offset = 0x1000;
++  params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
++  params->ramdisk_image = 0;
++  params->ramdisk_size = 0;
++
++  params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
++  params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
++
++  /* These are not needed to be precise, because Linux uses these values
++     only to raise an error when the decompression code cannot find good
++     space.  */
++  params->ext_mem = ((32 * 0x100000) >> 10);
++  params->alt_mem = ((32 * 0x100000) >> 10);
++
++  {
++    grub_term_output_t term;
++    int found = 0;
++    FOR_ACTIVE_TERM_OUTPUTS(term)
++      if (grub_strcmp (term->name, "vga_text") == 0
++        || grub_strcmp (term->name, "console") == 0)
++      {
++        grub_uint16_t pos = grub_term_getxy (term);
++        params->video_cursor_x = pos >> 8;
++        params->video_cursor_y = pos & 0xff;
++        params->video_width = grub_term_width (term);
++        params->video_height = grub_term_height (term);
++        found = 1;
++        break;
++      }
++    if (!found)
++      {
++      params->video_cursor_x = 0;
++      params->video_cursor_y = 0;
++      params->video_width = 80;
++      params->video_height = 25;
++      }
++  }
++  params->video_page = 0; /* ??? */
++  params->video_mode = grub_efi_system_table->con_out->mode->mode;
++  params->video_ega_bx = 0;
++  params->have_vga = 0;
++  params->font_size = 16; /* XXX */
++
++  if (grub_le_to_cpu16 (params->version) >= 0x0206)
++    {
++      params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
++      params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
++#ifdef __x86_64__
++      params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
++#endif
++    }
++  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
++    {
++      params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
++      params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
++    }
++
++#if 0
++  /* The structure is zeroed already.  */
++
++  /* No VBE on EFI.  */
++  params->lfb_width = 0;
++  params->lfb_height = 0;
++  params->lfb_depth = 0;
++  params->lfb_base = 0;
++  params->lfb_size = 0;
++  params->lfb_line_len = 0;
++  params->red_mask_size = 0;
++  params->red_field_pos = 0;
++  params->green_mask_size = 0;
++  params->green_field_pos = 0;
++  params->blue_mask_size = 0;
++  params->blue_field_pos = 0;
++  params->reserved_mask_size = 0;
++  params->reserved_field_pos = 0;
++  params->vesapm_segment = 0;
++  params->vesapm_offset = 0;
++  params->lfb_pages = 0;
++  params->vesa_attrib = 0;
++
++  /* No APM on EFI.  */
++  params->apm_version = 0;
++  params->apm_code_segment = 0;
++  params->apm_entry = 0;
++  params->apm_16bit_code_segment = 0;
++  params->apm_data_segment = 0;
++  params->apm_flags = 0;
++  params->apm_code_len = 0;
++  params->apm_data_len = 0;
++
++  /* XXX is there any way to use SpeedStep on EFI?  */
++  params->ist_signature = 0;
++  params->ist_command = 0;
++  params->ist_event = 0;
++  params->ist_perf_level = 0;
++
++  /* Let the kernel probe the information.  */
++  grub_memset (params->hd0_drive_info, 0, sizeof (params->hd0_drive_info));
++  grub_memset (params->hd1_drive_info, 0, sizeof (params->hd1_drive_info));
++
++  /* No MCA on EFI.  */
++  params->rom_config_len = 0;
++
++  /* No need to fake the BIOS's memory map.  */
++  params->mmap_size = 0;
++
++  /* Let the kernel probe the information.  */
++  params->ps_mouse = 0;
++
++  /* Clear padding for future compatibility.  */
++  grub_memset (params->padding1, 0, sizeof (params->padding1));
++  grub_memset (params->padding2, 0, sizeof (params->padding2));
++  grub_memset (params->padding3, 0, sizeof (params->padding3));
++  grub_memset (params->padding4, 0, sizeof (params->padding4));
++  grub_memset (params->padding5, 0, sizeof (params->padding5));
++  grub_memset (params->padding6, 0, sizeof (params->padding6));
++  grub_memset (params->padding7, 0, sizeof (params->padding7));
++  grub_memset (params->padding8, 0, sizeof (params->padding8));
++  grub_memset (params->padding9, 0, sizeof (params->padding9));
++
++#endif
++
++  /* The other EFI parameters are filled when booting.  */
++
++  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
++
++  /* XXX there is no way to know if the kernel really supports EFI.  */
++  grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
++              (unsigned) real_size, (unsigned) prot_size);
++
++  /* Detect explicitly specified memory size, if any.  */
++  linux_mem_size = 0;
++  for (i = 1; i < argc; i++)
++    if (grub_memcmp (argv[i], "mem=", 4) == 0)
++      {
++      char *val = argv[i] + 4;
++
++      linux_mem_size = grub_strtoul (val, &val, 0);
++
++      if (grub_errno)
++        {
++          grub_errno = GRUB_ERR_NONE;
++          linux_mem_size = 0;
++        }
++      else
++        {
++          int shift = 0;
++
++          switch (grub_tolower (val[0]))
++            {
++            case 'g':
++              shift += 10;
++            case 'm':
++              shift += 10;
++            case 'k':
++              shift += 10;
++            default:
++              break;
++            }
++
++          /* Check an overflow.  */
++          if (linux_mem_size > (~0UL >> shift))
++            linux_mem_size = 0;
++          else
++            linux_mem_size <<= shift;
++        }
++      }
++    else if (grub_memcmp (argv[i], "video=efifb", 11) == 0)
++      {
++      if (params->have_vga)
++        params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
++      }
++
++  /* Specify the boot file.  */
++  dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
++                    "BOOT_IMAGE=");
++  dest = grub_stpcpy (dest, argv[0]);
++
++  /* Copy kernel parameters.  */
++  for (i = 1;
++       i < argc
++       && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
++                                              + GRUB_LINUX_CL_END_OFFSET);
++       i++)
++    {
++      *dest++ = ' ';
++      dest = grub_stpcpy (dest, argv[i]);
++    }
++
++  len = prot_size;
++  if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
++    grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++
++  if (grub_errno == GRUB_ERR_NONE)
++    {
++      grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
++      loaded = 1;
++    }
++
++ fail:
++
++  if (file)
++    grub_file_close (file);
++
++  if (grub_errno != GRUB_ERR_NONE)
++    {
++      grub_dl_unref (my_mod);
++      loaded = 0;
++    }
++
++  return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
++               int argc, char *argv[])
++{
++  grub_file_t file = 0;
++  grub_ssize_t size;
++  grub_addr_t addr_min, addr_max;
++  grub_addr_t addr;
++  grub_efi_uintn_t mmap_size;
++  grub_efi_memory_descriptor_t *desc;
++  grub_efi_uintn_t desc_size;
++  struct linux_kernel_header *lh;
++
++  if (argc == 0)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
++      goto fail;
++    }
++
++  if (! loaded)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
++      goto fail;
++    }
++
++  file = grub_file_open (argv[0]);
++  if (! file)
++    goto fail;
++
++  size = grub_file_size (file);
++  initrd_pages = (page_align (size) >> 12);
++
++  lh = (struct linux_kernel_header *) real_mode_mem;
++
++  addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
++  if (linux_mem_size != 0 && linux_mem_size < addr_max)
++    addr_max = linux_mem_size;
++
++  /* Linux 2.3.xx has a bug in the memory range check, so avoid
++     the last page.
++     Linux 2.2.xx has a bug in the memory range check, which is
++     worse than that of Linux 2.3.xx, so avoid the last 64kb.  */
++  addr_max -= 0x10000;
++
++  /* Usually, the compression ratio is about 50%.  */
++  addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
++           + page_align (size);
++
++  /* Find the highest address to put the initrd.  */
++  mmap_size = find_mmap_size ();
++  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
++    grub_fatal ("cannot get memory map");
++
++  addr = 0;
++  for (desc = mmap_buf;
++       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
++       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
++    {
++      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
++        && desc->num_pages >= initrd_pages)
++      {
++        grub_efi_physical_address_t physical_end;
++
++        physical_end = desc->physical_start + (desc->num_pages << 12);
++        if (physical_end > addr_max)
++          physical_end = addr_max;
++
++        if (physical_end < page_align (size))
++          continue;
++
++        physical_end -= page_align (size);
++
++        if ((physical_end >= addr_min) &&
++            (physical_end >= desc->physical_start) &&
++            (physical_end > addr))
++          addr = physical_end;
++      }
++    }
++
++  if (addr == 0)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available");
++      goto fail;
++    }
++
++  initrd_mem = grub_efi_allocate_pages (addr, initrd_pages);
++  if (! initrd_mem)
++    grub_fatal ("cannot allocate pages");
++
++  if (grub_file_read (file, initrd_mem, size) != size)
++    {
++      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++      goto fail;
++    }
++
++  grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
++              (unsigned) addr, (unsigned) size);
++
++  lh->ramdisk_image = addr;
++  lh->ramdisk_size = size;
++  lh->root_dev = 0x0100; /* XXX */
++
++ fail:
++  if (file)
++    grub_file_close (file);
++
++  return grub_errno;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT(linux)
++{
++  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
++                                   0, N_("Load Linux."));
++  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
++                                    0, N_("Load initrd."));
++  my_mod = mod;
++}
++
++GRUB_MOD_FINI(linux)
++{
++  grub_unregister_command (cmd_linux);
++  grub_unregister_command (cmd_initrd);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9f7556ffa4b22713fa0fc96932129d198971d093
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,311 @@@
++/* linux.c - boot Linux zImage or bzImage */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/loader.h>
++#include <grub/machine/loader.h>
++#include <grub/machine/memory.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/disk.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/dl.h>
++#include <grub/env.h>
++#include <grub/term.h>
++#include <grub/cpu/linux.h>
++#include <grub/ieee1275/ieee1275.h>
++#include <grub/command.h>
++#include <grub/i18n.h>
++
++#define GRUB_OFW_LINUX_PARAMS_ADDR    0x90000
++#define GRUB_OFW_LINUX_KERNEL_ADDR    0x100000
++#define GRUB_OFW_LINUX_INITRD_ADDR    0x800000
++
++#define GRUB_OFW_LINUX_CL_OFFSET      0x1e00
++#define GRUB_OFW_LINUX_CL_LENGTH      0x100
++
++static grub_dl_t my_mod;
++
++static grub_size_t kernel_size;
++static char *kernel_addr, *kernel_cmdline;
++static grub_size_t initrd_size;
++
++static grub_err_t
++grub_linux_unload (void)
++{
++  grub_free (kernel_cmdline);
++  grub_free (kernel_addr);
++  kernel_cmdline = 0;
++  kernel_addr = 0;
++  initrd_size = 0;
++
++  grub_dl_unref (my_mod);
++
++  return GRUB_ERR_NONE;
++}
++
++/*
++static int
++grub_ieee1275_debug (void)
++{
++  struct enter_args
++  {
++    struct grub_ieee1275_common_hdr common;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0);
++
++  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
++    return -1;
++
++  return 0;
++}
++*/
++
++static grub_err_t
++grub_linux_boot (void)
++{
++  struct linux_kernel_params *params;
++  struct linux_kernel_header *lh;
++  char *prot_code;
++  char *bootpath;
++  grub_ssize_t len;
++
++  bootpath = grub_env_get ("root");
++  if (bootpath)
++    grub_ieee1275_set_property (grub_ieee1275_chosen,
++                                "bootpath", bootpath,
++                                grub_strlen (bootpath) + 1,
++                                &len);
++
++  params = (struct linux_kernel_params *) GRUB_OFW_LINUX_PARAMS_ADDR;
++  lh = (struct linux_kernel_header *) params;
++
++  grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
++
++  params->alt_mem = grub_mmap_get_upper () >> 10;
++  params->ext_mem = params->alt_mem;
++
++  lh->cmd_line_ptr = (char *)
++        (GRUB_OFW_LINUX_PARAMS_ADDR + GRUB_OFW_LINUX_CL_OFFSET);
++
++  params->cl_magic = GRUB_LINUX_CL_MAGIC;
++  params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET;
++
++  {
++    grub_term_output_t term;
++    int found = 0;
++    FOR_ACTIVE_TERM_OUTPUTS(term)
++      if (grub_strcmp (term->name, "ofconsole") == 0)
++        {
++          grub_uint16_t pos = grub_term_getxy (term);
++          params->video_cursor_x = pos >> 8;
++          params->video_cursor_y = pos & 0xff;
++          params->video_width = grub_term_width (term);
++          params->video_height = grub_term_height (term);
++          found = 1;
++          break;
++        }
++    if (!found)
++      {
++        params->video_cursor_x = 0;
++        params->video_cursor_y = 0;
++        params->video_width = 80;
++        params->video_height = 25;
++      }
++  }
++
++  params->font_size = 16;
++
++  params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
++  params->ofw_num_items = 1;
++  params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
++  params->ofw_idt = 0;
++
++  if (initrd_size)
++    {
++      lh->type_of_loader = 1;
++      lh->ramdisk_image = GRUB_OFW_LINUX_INITRD_ADDR;
++      lh->ramdisk_size = initrd_size;
++    }
++
++  if (kernel_cmdline)
++    grub_strcpy (lh->cmd_line_ptr, kernel_cmdline);
++
++  prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR;
++  grub_memcpy (prot_code, kernel_addr, kernel_size);
++
++  asm volatile ("movl %0, %%esi" : : "m" (params));
++  asm volatile ("movl %%esi, %%esp" : : );
++  asm volatile ("movl %0, %%ecx" : : "m" (prot_code));
++  asm volatile ("xorl %%ebx, %%ebx" : : );
++  asm volatile ("jmp *%%ecx" : : );
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
++              int argc, char *argv[])
++{
++  grub_file_t file = 0;
++  struct linux_kernel_header lh;
++  grub_uint8_t setup_sects;
++  grub_size_t real_size, prot_size;
++  int i;
++  char *dest;
++
++  grub_dl_ref (my_mod);
++
++  if (argc == 0)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
++      goto fail;
++    }
++
++  file = grub_file_open (argv[0]);
++  if (! file)
++    goto fail;
++
++  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++    {
++      grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header");
++      goto fail;
++    }
++
++  if ((lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ||
++      (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)))
++    {
++      grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
++      goto fail;
++    }
++
++  setup_sects = lh.setup_sects;
++  if (! setup_sects)
++    setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
++
++  real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
++  prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
++
++  grub_dprintf ("linux", "Linux-%s, setup=0x%x, size=0x%x\n",
++              "bzImage", real_size, prot_size);
++
++  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
++  if (grub_errno)
++    goto fail;
++
++  kernel_cmdline = grub_malloc (GRUB_OFW_LINUX_CL_LENGTH);
++  if (! kernel_cmdline)
++    goto fail;
++
++  dest = kernel_cmdline;
++  for (i = 1;
++       i < argc
++       && dest + grub_strlen (argv[i]) + 1 < (kernel_cmdline
++                                              + GRUB_OFW_LINUX_CL_LENGTH);
++       i++)
++    {
++      *dest++ = ' ';
++      dest = grub_stpcpy (dest, argv[i]);
++    }
++
++  kernel_addr = grub_malloc (prot_size);
++  if (! kernel_addr)
++    goto fail;
++
++  kernel_size = prot_size;
++  if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size)
++    grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++
++  if (grub_errno == GRUB_ERR_NONE)
++    grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
++
++fail:
++
++  if (file)
++    grub_file_close (file);
++
++  if (grub_errno != GRUB_ERR_NONE)
++    {
++      grub_free (kernel_cmdline);
++      grub_free (kernel_addr);
++      kernel_cmdline = 0;
++      kernel_addr = 0;
++
++      grub_dl_unref (my_mod);
++    }
++
++  return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
++               int argc, char *argv[])
++{
++  grub_file_t file = 0;
++
++  if (argc == 0)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
++      goto fail;
++    }
++
++  if (! kernel_addr)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
++      goto fail;
++    }
++
++  file = grub_file_open (argv[0]);
++  if (! file)
++    goto fail;
++
++  initrd_size = grub_file_size (file);
++  if (grub_file_read (file, (void *) GRUB_OFW_LINUX_INITRD_ADDR,
++                      initrd_size) != (int) initrd_size)
++    {
++      grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++      goto fail;
++    }
++
++fail:
++  if (file)
++    grub_file_close (file);
++
++  return grub_errno;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT(linux)
++{
++  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
++                                   0, N_("Load Linux."));
++  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
++                                    0, N_("Load initrd."));
++  my_mod = mod;
++}
++
++GRUB_MOD_FINI(linux)
++{
++  grub_unregister_command (cmd_linux);
++  grub_unregister_command (cmd_initrd);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4acea7b1161a2cd415e976760f6815ef307f249a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,129 @@@
++/*
++ *  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 <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/symbol.h>
++
++
++      .p2align        4       /* force 16-byte alignment */
++VARIABLE(grub_linux_trampoline_start)
++      cli
++      /* %rdi contains protected memory start and %rsi
++      contains real memory start. */
++
++      mov %rsi, %rbx
++
++      call base
++base:
++      pop %rsi
++
++#ifdef APPLE_CC
++      lea (cont1 - base) (%esi, 1), %rax
++      mov %eax, (jump_vector - base) (%esi, 1)
++
++      lea (gdt - base) (%esi, 1), %rax
++      mov %rax, (gdtaddr - base) (%esi, 1)
++
++      /* Switch to compatibility mode. */
++
++      lidt (idtdesc - base) (%esi, 1)
++      lgdt (gdtdesc - base) (%esi, 1)
++
++      /* Update %cs. Thanks to David Miller for pointing this mistake out. */
++      ljmp *(jump_vector - base) (%esi, 1)
++#else
++      lea (cont1 - base) (%rsi, 1), %rax
++      mov %eax, (jump_vector - base) (%rsi, 1)
++
++      lea (gdt - base) (%rsi, 1), %rax
++      mov %rax, (gdtaddr - base) (%rsi, 1)
++
++      /* Switch to compatibility mode. */
++
++      lidt (idtdesc - base) (%rsi, 1)
++      lgdt (gdtdesc - base) (%rsi, 1)
++
++      /* Update %cs. Thanks to David Miller for pointing this mistake out. */
++      ljmp *(jump_vector - base) (%rsi, 1)
++#endif
++
++cont1:
++      .code32
++
++      /* Update other registers. */
++      mov $0x18, %eax
++      mov %eax, %ds
++      mov %eax, %es
++      mov %eax, %fs
++      mov %eax, %gs
++      mov %eax, %ss
++
++      /* Disable paging. */
++      mov %cr0, %eax
++      and $0x7fffffff, %eax
++      mov %eax, %cr0
++
++      /* Disable amd64. */
++      mov $0xc0000080, %ecx
++      rdmsr
++      and $0xfffffeff, %eax
++      wrmsr
++
++      /* Turn off PAE. */
++      movl %cr4, %eax
++      and $0xffffffcf, %eax
++      mov %eax, %cr4
++
++      jmp cont2
++cont2:
++      .code32
++
++      mov %ebx, %esi
++
++      jmp *%edi
++
++      /* GDT. */
++      .p2align 4
++gdt:
++      /* NULL.  */
++      .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++
++      /* Reserved.  */
++      .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++
++      /* Code segment.  */
++      .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
++
++      /* Data segment.  */
++      .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
++
++gdtdesc:
++      .word 31
++gdtaddr:
++      .quad gdt
++
++idtdesc:
++      .word 0
++idtaddr:
++      .quad 0
++
++      .p2align 4
++jump_vector:
++      /* Jump location. Is filled by the code */
++      .long 0
++      .long 0x10
++VARIABLE(grub_linux_trampoline_end)
index ac3fb649703e7986080ce78d2bb0a5ed98c658fb,66db1149a4394810d29ebce9c35cbfb5169a2341..a127a817449bf72a9fc5f6d133a71570c3502e28
@@@ -165,5 -163,27 +163,16 @@@ grub_uint64_t EXPORT_FUNC(grub_disk_get
  
  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);
+ void grub_mdraid1x_init (void);
+ void grub_raid_init (void);
+ void grub_lvm_fini (void);
+ void grub_mdraid09_fini (void);
+ void grub_mdraid1x_fini (void);
+ void grub_raid_fini (void);
+ #endif
  #endif /* ! GRUB_DISK_HEADER */
Simple merge