merge mainline into hints
This commit is contained in:
commit
17785932df
448 changed files with 43023 additions and 10176 deletions
|
@ -1,4 +1,4 @@
|
|||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
AUTOMAKE_OPTIONS = subdir-objects -Wno-portability
|
||||
|
||||
DEPDIR=.deps-core
|
||||
|
||||
|
@ -78,12 +78,11 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h
|
|||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
|
||||
|
||||
if COND_i386_pc
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h
|
||||
|
@ -99,10 +98,12 @@ endif
|
|||
|
||||
if COND_i386_coreboot
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/i386/pc/int.h
|
||||
endif
|
||||
|
||||
if COND_i386_multiboot
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/i386/pc/int.h
|
||||
endif
|
||||
|
||||
if COND_i386_qemu
|
||||
|
@ -141,7 +142,20 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arc/arc.h
|
|||
endif
|
||||
|
||||
if COND_mips_qemu_mips
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
|
||||
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bitmap.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bitmap_scale.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/serial.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
|
||||
endif
|
||||
|
||||
if COND_mips_loongson
|
||||
|
@ -187,6 +201,7 @@ endif
|
|||
if COND_emu
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/export.h
|
||||
if COND_GRUB_EMU_SDL
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h
|
||||
endif
|
||||
|
|
|
@ -18,6 +18,18 @@ script = {
|
|||
common = modinfo.sh.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
installdir = noinst;
|
||||
name = gmodule.pl;
|
||||
common = gmodule.pl.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
installdir = noinst;
|
||||
name = gdb_grub;
|
||||
common = gdb_grub.in;
|
||||
};
|
||||
|
||||
kernel = {
|
||||
name = kernel;
|
||||
|
||||
|
@ -34,7 +46,7 @@ kernel = {
|
|||
ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment';
|
||||
|
||||
i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
|
||||
i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200';
|
||||
i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000';
|
||||
|
||||
i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)';
|
||||
i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200';
|
||||
|
@ -102,6 +114,7 @@ kernel = {
|
|||
ieee1275 = kern/ieee1275/mmap.c;
|
||||
ieee1275 = kern/ieee1275/openfw.c;
|
||||
ieee1275 = term/ieee1275/ofconsole.c;
|
||||
ieee1275 = kern/ieee1275/init.c;
|
||||
|
||||
terminfoinkernel = term/terminfo.c;
|
||||
terminfoinkernel = term/tparm.c;
|
||||
|
@ -143,7 +156,7 @@ kernel = {
|
|||
i386_pc = term/i386/pc/console.c;
|
||||
|
||||
i386_qemu = bus/pci.c;
|
||||
i386_qemu = kern/i386/qemu/init.c;
|
||||
i386_qemu = kern/vga_init.c;
|
||||
i386_qemu = kern/i386/qemu/mmap.c;
|
||||
i386_qemu = kern/i386/tsc.c;
|
||||
|
||||
|
@ -153,8 +166,6 @@ kernel = {
|
|||
i386_multiboot = kern/i386/multiboot_mmap.c;
|
||||
i386_multiboot = kern/i386/tsc.c;
|
||||
|
||||
i386_ieee1275 = kern/ieee1275/init.c;
|
||||
|
||||
mips = kern/mips/cache.S;
|
||||
mips = kern/mips/dl.c;
|
||||
mips = kern/mips/init.c;
|
||||
|
@ -162,6 +173,11 @@ kernel = {
|
|||
mips_qemu_mips = kern/mips/qemu_mips/init.c;
|
||||
mips_qemu_mips = term/ns8250.c;
|
||||
mips_qemu_mips = term/serial.c;
|
||||
mips_qemu_mips = term/at_keyboard.c;
|
||||
mips_qemu_mips = commands/keylayouts.c;
|
||||
mips_qemu_mips = term/i386/pc/vga_text.c;
|
||||
mips_qemu_mips = term/i386/vga_common.c;
|
||||
mips_qemu_mips = kern/vga_init.c;
|
||||
|
||||
mips_arc = kern/mips/arc/init.c;
|
||||
mips_arc = term/arc/console.c;
|
||||
|
@ -176,24 +192,22 @@ kernel = {
|
|||
mips_loongson = term/serial.c;
|
||||
mips_loongson = video/sm712.c;
|
||||
mips_loongson = video/sis315pro.c;
|
||||
mips_loongson = video/radeon_fuloong2e.c;
|
||||
extra_dist = video/sm712_init.c;
|
||||
mips_loongson = commands/keylayouts.c;
|
||||
|
||||
powerpc_ieee1275 = kern/ieee1275/init.c;
|
||||
powerpc_ieee1275 = kern/powerpc/cache.S;
|
||||
powerpc_ieee1275 = kern/powerpc/dl.c;
|
||||
|
||||
sparc64_ieee1275 = kern/sparc64/cache.S;
|
||||
sparc64_ieee1275 = kern/sparc64/dl.c;
|
||||
sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c;
|
||||
sparc64_ieee1275 = kern/sparc64/ieee1275/init.c;
|
||||
|
||||
emu = disk/host.c;
|
||||
emu = gnulib/progname.c;
|
||||
emu = gnulib/error.c;
|
||||
emu = kern/emu/cache_s.S;
|
||||
emu = kern/emu/console.c;
|
||||
emu = kern/emu/getroot.c;
|
||||
emu = kern/emu/hostdisk.c;
|
||||
emu = kern/emu/hostfs.c;
|
||||
emu = kern/emu/main.c;
|
||||
|
@ -217,6 +231,7 @@ kernel = {
|
|||
|
||||
videoinkernel = commands/boot.c;
|
||||
|
||||
extra_dist = kern/i386/int.S;
|
||||
extra_dist = kern/i386/realmode.S;
|
||||
extra_dist = kern/i386/pc/lzma_decode.S;
|
||||
extra_dist = kern/mips/cache_flush.S;
|
||||
|
@ -353,6 +368,15 @@ image = {
|
|||
enable = mips;
|
||||
};
|
||||
|
||||
image = {
|
||||
name = lzma_decompress;
|
||||
i386_pc = boot/i386/pc/startup_raw.S;
|
||||
|
||||
objcopyflags = '-O binary';
|
||||
ldflags = '$(TARGET_IMG_LDFLAGS) -Wl,-Ttext,0x8200';
|
||||
enable = i386_pc;
|
||||
};
|
||||
|
||||
image = {
|
||||
name = fwstart;
|
||||
mips_loongson = boot/mips/loongson/fwstart.S;
|
||||
|
@ -362,8 +386,8 @@ image = {
|
|||
};
|
||||
|
||||
image = {
|
||||
name = fwstart_fuloong;
|
||||
mips_loongson = boot/mips/loongson/fuloong.S;
|
||||
name = fwstart_fuloong2f;
|
||||
mips_loongson = boot/mips/loongson/fuloong2f.S;
|
||||
objcopyflags = '-O binary';
|
||||
ldflags = '-static-libgcc -lgcc -Wl,-N,-S,-Ttext,0xbfc00000,-Bstatic';
|
||||
enable = mips_loongson;
|
||||
|
@ -397,11 +421,15 @@ module = {
|
|||
module = {
|
||||
name = usb;
|
||||
common = bus/usb/usb.c;
|
||||
noemu = bus/usb/usbtrans.c;
|
||||
noemu = bus/usb/usbhub.c;
|
||||
enable = emu;
|
||||
common = bus/usb/usbtrans.c;
|
||||
common = bus/usb/usbhub.c;
|
||||
enable = usb;
|
||||
emu_condition = COND_GRUB_EMU_USB;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = emuusb;
|
||||
common = bus/usb/usb.c;
|
||||
condition = COND_GRUB_EMU_USB;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -436,18 +464,22 @@ module = {
|
|||
|
||||
module = {
|
||||
name = pci;
|
||||
noemu = bus/pci.c;
|
||||
emu = bus/emu/pci.c;
|
||||
emu = commands/lspci.c;
|
||||
common = bus/pci.c;
|
||||
|
||||
enable = emu;
|
||||
enable = i386_pc;
|
||||
enable = i386_efi;
|
||||
enable = x86_64_efi;
|
||||
enable = i386_ieee1275;
|
||||
enable = i386_coreboot;
|
||||
enable = i386_multiboot;
|
||||
emu_condition = COND_GRUB_EMU_PCI;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = emupci;
|
||||
common = bus/emu/pci.c;
|
||||
common = commands/lspci.c;
|
||||
|
||||
condition = COND_GRUB_EMU_PCI;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -622,6 +654,20 @@ module = {
|
|||
emu = lib/emu/halt.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = reboot;
|
||||
i386 = lib/i386/reboot.c;
|
||||
i386 = lib/i386/reboot_trampoline.S;
|
||||
ia64_efi = lib/efi/reboot.c;
|
||||
x86_64_efi = lib/efi/reboot.c;
|
||||
powerpc_ieee1275 = lib/ieee1275/reboot.c;
|
||||
sparc64_ieee1275 = lib/ieee1275/reboot.c;
|
||||
mips_arc = lib/mips/arc/reboot.c;
|
||||
mips_loongson = lib/mips/loongson/reboot.c;
|
||||
mips_qemu_mips = lib/mips/qemu_mips/reboot.c;
|
||||
common = commands/reboot.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = hashsum;
|
||||
common = commands/hashsum.c;
|
||||
|
@ -717,22 +763,11 @@ module = {
|
|||
common = commands/probe.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = pxecmd;
|
||||
i386_pc = commands/i386/pc/pxecmd.c;
|
||||
enable = i386_pc;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = read;
|
||||
common = commands/read.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = reboot;
|
||||
common = commands/reboot.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = search;
|
||||
common = commands/search_wrap.c;
|
||||
|
@ -791,8 +826,6 @@ module = {
|
|||
name = usbtest;
|
||||
common = commands/usbtest.c;
|
||||
enable = usb;
|
||||
enable = emu;
|
||||
emu_condition = COND_GRUB_EMU_USB;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -820,6 +853,22 @@ module = {
|
|||
common = disk/loopback.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = cryptodisk;
|
||||
common = disk/cryptodisk.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = luks;
|
||||
common = disk/luks.c;
|
||||
common = disk/AFSplitter.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = geli;
|
||||
common = disk/geli.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = lvm;
|
||||
common = disk/lvm.c;
|
||||
|
@ -868,8 +917,14 @@ module = {
|
|||
};
|
||||
|
||||
module = {
|
||||
name = ata_pthru;
|
||||
common = disk/ata_pthru.c;
|
||||
name = ahci;
|
||||
common = disk/ahci.c;
|
||||
enable = pci;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = pata;
|
||||
common = disk/pata.c;
|
||||
enable = pci;
|
||||
enable = mips_qemu_mips;
|
||||
};
|
||||
|
@ -884,8 +939,6 @@ module = {
|
|||
name = usbms;
|
||||
common = disk/usbms.c;
|
||||
enable = usb;
|
||||
enable = emu;
|
||||
emu_condition = COND_GRUB_EMU_USB;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -944,24 +997,16 @@ module = {
|
|||
};
|
||||
|
||||
module = {
|
||||
name = afs_be;
|
||||
common = fs/afs_be.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = befs;
|
||||
common = fs/befs.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = befs_be;
|
||||
common = fs/befs_be.c;
|
||||
name = bfs;
|
||||
common = fs/bfs.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = btrfs;
|
||||
common = fs/btrfs.c;
|
||||
common = lib/crc.c;
|
||||
cflags = '$(CFLAGS_POSIX) -Wno-undef';
|
||||
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -969,6 +1014,21 @@ module = {
|
|||
common = fs/cpio.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = cpio_be;
|
||||
common = fs/cpio_be.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = newc;
|
||||
common = fs/newc.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = odc;
|
||||
common = fs/odc.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = ext2;
|
||||
common = fs/ext2.c;
|
||||
|
@ -979,6 +1039,11 @@ module = {
|
|||
common = fs/fat.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = exfat;
|
||||
common = fs/exfat.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = fshelp;
|
||||
common = fs/fshelp.c;
|
||||
|
@ -1087,6 +1152,11 @@ module = {
|
|||
common = fs/zfs/zfs_fletcher.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = zfscrypt;
|
||||
common = fs/zfs/zfscrypt.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = zfsinfo;
|
||||
common = fs/zfs/zfsinfo.c;
|
||||
|
@ -1094,7 +1164,7 @@ module = {
|
|||
|
||||
module = {
|
||||
name = pxe;
|
||||
i386_pc = fs/i386/pc/pxe.c;
|
||||
i386_pc = net/drivers/i386/pc/pxe.c;
|
||||
enable = i386_pc;
|
||||
};
|
||||
|
||||
|
@ -1186,6 +1256,9 @@ module = {
|
|||
efi = lib/efi/datetime.c;
|
||||
sparc64_ieee1275 = lib/ieee1275/datetime.c;
|
||||
powerpc_ieee1275 = lib/ieee1275/datetime.c;
|
||||
sparc64_ieee1275 = lib/ieee1275/cmos.c;
|
||||
powerpc_ieee1275 = lib/ieee1275/cmos.c;
|
||||
|
||||
mips_arc = lib/arc/datetime.c;
|
||||
enable = noemu;
|
||||
};
|
||||
|
@ -1219,6 +1292,13 @@ module = {
|
|||
enable = x86;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = plan9;
|
||||
i386_pc = loader/i386/pc/plan9.c;
|
||||
enable = i386_pc;
|
||||
};
|
||||
|
||||
|
||||
module = {
|
||||
name = linux16;
|
||||
i386_pc = loader/i386/pc/linux.c;
|
||||
|
@ -1292,7 +1372,9 @@ module = {
|
|||
name = chain;
|
||||
efi = loader/efi/chainloader.c;
|
||||
i386_pc = loader/i386/pc/chainloader.c;
|
||||
i386_coreboot = loader/i386/coreboot/chainloader.c;
|
||||
enable = i386_pc;
|
||||
enable = i386_coreboot;
|
||||
enable = efi;
|
||||
};
|
||||
|
||||
|
@ -1351,7 +1433,7 @@ module = {
|
|||
extra_dist = script/yylex.l;
|
||||
extra_dist = script/parser.y;
|
||||
|
||||
cflags = '$(CFLAGS_POSIX) -Wno-error';
|
||||
cflags = '$(CFLAGS_POSIX)';
|
||||
cppflags = '$(CPPFLAGS_POSIX)';
|
||||
};
|
||||
|
||||
|
@ -1385,6 +1467,11 @@ module = {
|
|||
common = partmap/sun.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = part_plan;
|
||||
common = partmap/plan.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = part_dvh;
|
||||
common = partmap/dvh.c;
|
||||
|
@ -1422,9 +1509,7 @@ module = {
|
|||
common = term/serial.c;
|
||||
x86 = term/ns8250.c;
|
||||
|
||||
enable = emu;
|
||||
enable = x86;
|
||||
emu_condition = COND_GRUB_EMU_USB;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -1448,8 +1533,10 @@ module = {
|
|||
|
||||
module = {
|
||||
name = vga;
|
||||
i386_pc = video/i386/pc/vga.c;
|
||||
common = video/i386/pc/vga.c;
|
||||
enable = i386_pc;
|
||||
enable = i386_coreboot;
|
||||
enable = i386_multiboot;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -1527,8 +1614,10 @@ module = {
|
|||
|
||||
module = {
|
||||
name = vbe;
|
||||
i386_pc = video/i386/pc/vbe.c;
|
||||
common = video/i386/pc/vbe.c;
|
||||
enable = i386_pc;
|
||||
enable = i386_coreboot;
|
||||
enable = i386_multiboot;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -1565,6 +1654,49 @@ module = {
|
|||
common = hook/datehook.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = net;
|
||||
common = net/net.c;
|
||||
common = net/dns.c;
|
||||
common = net/bootp.c;
|
||||
common = net/ip.c;
|
||||
common = net/udp.c;
|
||||
common = net/tcp.c;
|
||||
common = net/icmp.c;
|
||||
common = net/icmp6.c;
|
||||
common = net/ethernet.c;
|
||||
common = net/arp.c;
|
||||
common = net/netbuff.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = tftp;
|
||||
common = net/tftp.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = http;
|
||||
common = net/http.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = ofnet;
|
||||
common = net/drivers/ieee1275/ofnet.c;
|
||||
enable = ieee1275;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = efinet;
|
||||
common = net/drivers/efi/efinet.c;
|
||||
enable = efi;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = emunet;
|
||||
emu = net/drivers/emu/emunet.c;
|
||||
enable = emu;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = legacycfg;
|
||||
common = commands/legacycfg.c;
|
||||
|
@ -1588,6 +1720,14 @@ module = {
|
|||
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = lzopio;
|
||||
common = io/lzopio.c;
|
||||
common = lib/minilzo/minilzo.c;
|
||||
cflags = '$(CFLAGS_POSIX) -Wno-undef';
|
||||
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = testload;
|
||||
common = commands/testload.c;
|
||||
|
@ -1604,3 +1744,29 @@ module = {
|
|||
common = commands/keylayouts.c;
|
||||
enable = videomodules;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = priority_queue;
|
||||
common = lib/priority_queue.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = time;
|
||||
common = commands/time.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = cacheinfo;
|
||||
common = commands/cacheinfo.c;
|
||||
condition = COND_ENABLE_CACHE_STATS;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = adler32;
|
||||
common = lib/adler32.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = crc64;
|
||||
common = lib/crc64.c;
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/boot.h>
|
||||
#include <grub/machine/boot.h>
|
||||
|
||||
/*
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/boot.h>
|
||||
#include <grub/machine/boot.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <multiboot.h>
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include <config.h>
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/boot.h>
|
||||
#include <grub/machine/boot.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
#include <multiboot.h>
|
||||
|
@ -200,21 +199,12 @@ real_code_2:
|
|||
|
||||
1:
|
||||
|
||||
movl %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE), %ecx
|
||||
#if GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4 < 0x200
|
||||
addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - 0x200), %ecx
|
||||
#else
|
||||
addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4)), %ecx
|
||||
#endif
|
||||
movl %ss:(DATA_ADDR + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE), %ecx
|
||||
addl $((0x9000 - 0x8200) - (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4)), %ecx
|
||||
|
||||
2:
|
||||
call LOCAL(move_memory)
|
||||
|
||||
movsbl %dh, %eax
|
||||
movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART)
|
||||
movsbl (reg_edx + 2 - start), %eax
|
||||
movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART)
|
||||
|
||||
movb $0xFF, %dh
|
||||
|
||||
ljmp $(DATA_ADDR >> 4), $0
|
||||
|
|
351
grub-core/boot/i386/pc/startup_raw.S
Normal file
351
grub-core/boot/i386/pc/startup_raw.S
Normal file
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/offsets.h>
|
||||
#include <grub/machine/boot.h>
|
||||
#include <grub/machine/memory.h>
|
||||
#include <grub/machine/kernel.h>
|
||||
|
||||
#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
|
||||
|
||||
.file "startup_raw.S"
|
||||
|
||||
.text
|
||||
|
||||
/* Tell GAS to generate 16-bit instructions so that this code works
|
||||
in real mode. */
|
||||
.code16
|
||||
|
||||
.globl start, _start
|
||||
start:
|
||||
_start:
|
||||
LOCAL (base):
|
||||
/*
|
||||
* Guarantee that "main" is loaded at 0x0:0x8200.
|
||||
*/
|
||||
#ifdef __APPLE__
|
||||
ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
|
||||
#else
|
||||
ljmp $0, $ABS(LOCAL (codestart))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is a special data area.
|
||||
*/
|
||||
|
||||
. = _start + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE
|
||||
LOCAL(compressed_size):
|
||||
.long 0
|
||||
. = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE
|
||||
LOCAL(uncompressed_size):
|
||||
.long 0
|
||||
|
||||
. = _start + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY
|
||||
reed_solomon_redundancy:
|
||||
.long 0
|
||||
|
||||
/*
|
||||
* This is the area for all of the special variables.
|
||||
*/
|
||||
|
||||
LOCAL(boot_dev):
|
||||
.byte 0xFF, 0xFF, 0xFF
|
||||
LOCAL(boot_drive):
|
||||
.byte 0x00
|
||||
|
||||
/* the real mode code continues... */
|
||||
LOCAL (codestart):
|
||||
cli /* we're not safe here! */
|
||||
|
||||
/* set up %ds, %ss, and %es */
|
||||
xorw %ax, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
movw %ax, %es
|
||||
|
||||
/* set up the real mode/BIOS stack */
|
||||
movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
|
||||
movl %ebp, %esp
|
||||
|
||||
sti /* we're safe again */
|
||||
|
||||
/* save the boot drive */
|
||||
ADDR32 movb %dl, LOCAL(boot_drive)
|
||||
|
||||
/* reset disk system (%ah = 0) */
|
||||
int $0x13
|
||||
|
||||
/* transition to protected mode */
|
||||
DATA32 call real_to_prot
|
||||
|
||||
/* The ".code32" directive takes GAS out of 16-bit mode. */
|
||||
.code32
|
||||
|
||||
incl %eax
|
||||
cld
|
||||
call grub_gate_a20
|
||||
|
||||
movl LOCAL(compressed_size), %edx
|
||||
addl $(LOCAL(decompressor_end) - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART - _start), %edx
|
||||
movl reed_solomon_redundancy, %ecx
|
||||
leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax
|
||||
cld
|
||||
call EXT_C (grub_reed_solomon_recover)
|
||||
jmp post_reed_solomon
|
||||
|
||||
#include "../../../kern/i386/realmode.S"
|
||||
|
||||
#include <rs_decoder.S>
|
||||
|
||||
.text
|
||||
|
||||
. = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART
|
||||
/*
|
||||
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
|
||||
* This uses the a.out kludge to load raw binary to the area starting at 1MB,
|
||||
* and relocates itself after loaded.
|
||||
*/
|
||||
.p2align 2 /* force 4-byte alignment */
|
||||
multiboot_header:
|
||||
/* magic */
|
||||
.long 0x1BADB002
|
||||
/* flags */
|
||||
.long (1 << 16)
|
||||
/* checksum */
|
||||
.long -0x1BADB002 - (1 << 16)
|
||||
/* header addr */
|
||||
.long multiboot_header - _start + 0x100000 + 0x200
|
||||
/* load addr */
|
||||
.long 0x100000
|
||||
/* load end addr */
|
||||
.long 0
|
||||
/* bss end addr */
|
||||
.long 0
|
||||
/* entry addr */
|
||||
.long multiboot_entry - _start + 0x100000 + 0x200
|
||||
|
||||
multiboot_entry:
|
||||
.code32
|
||||
/* obtain the boot device */
|
||||
movl 12(%ebx), %edx
|
||||
|
||||
movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
|
||||
movl %ebp, %esp
|
||||
|
||||
/* relocate the code */
|
||||
movl $(LOCAL(decompressor_end) + 0x200), %ecx
|
||||
addl LOCAL(compressed_size) - _start + 0x100000 + 0x200, %ecx
|
||||
movl $0x100000, %esi
|
||||
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
|
||||
cld
|
||||
rep
|
||||
movsb
|
||||
/* jump to the real address */
|
||||
movl $multiboot_trampoline, %eax
|
||||
jmp *%eax
|
||||
|
||||
multiboot_trampoline:
|
||||
/* fill the boot information */
|
||||
movl %edx, LOCAL(boot_dev)
|
||||
shrl $24, %edx
|
||||
/* enter the usual booting */
|
||||
call prot_to_real
|
||||
.code16
|
||||
jmp LOCAL (codestart)
|
||||
.code32
|
||||
|
||||
post_reed_solomon:
|
||||
|
||||
#ifdef ENABLE_LZMA
|
||||
movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
|
||||
movl $LOCAL(decompressor_end), %esi
|
||||
pushl %edi
|
||||
movl LOCAL (uncompressed_size), %ecx
|
||||
leal (%edi, %ecx), %ebx
|
||||
/* Don't remove this push: it's an argument. */
|
||||
push %ecx
|
||||
call _LzmaDecodeA
|
||||
pop %ecx
|
||||
/* _LzmaDecodeA clears DF, so no need to run cld */
|
||||
popl %esi
|
||||
#endif
|
||||
|
||||
movl LOCAL(boot_dev), %edx
|
||||
movl $prot_to_real, %edi
|
||||
movl $real_to_prot, %ecx
|
||||
jmp *%esi
|
||||
|
||||
/*
|
||||
* grub_gate_a20(int on)
|
||||
*
|
||||
* Gate address-line 20 for high memory.
|
||||
*
|
||||
* This routine is probably overconservative in what it does, but so what?
|
||||
*
|
||||
* It also eats any keystrokes in the keyboard buffer. :-(
|
||||
*/
|
||||
|
||||
grub_gate_a20:
|
||||
movl %eax, %edx
|
||||
|
||||
gate_a20_test_current_state:
|
||||
/* first of all, test if already in a good state */
|
||||
call gate_a20_check_state
|
||||
cmpb %al, %dl
|
||||
jnz gate_a20_try_bios
|
||||
ret
|
||||
|
||||
gate_a20_try_bios:
|
||||
/* second, try a BIOS call */
|
||||
pushl %ebp
|
||||
call prot_to_real
|
||||
|
||||
.code16
|
||||
movw $0x2400, %ax
|
||||
testb %dl, %dl
|
||||
jz 1f
|
||||
incw %ax
|
||||
1: int $0x15
|
||||
|
||||
DATA32 call real_to_prot
|
||||
.code32
|
||||
|
||||
popl %ebp
|
||||
call gate_a20_check_state
|
||||
cmpb %al, %dl
|
||||
jnz gate_a20_try_system_control_port_a
|
||||
ret
|
||||
|
||||
gate_a20_try_system_control_port_a:
|
||||
/*
|
||||
* In macbook, the keyboard test would hang the machine, so we move
|
||||
* this forward.
|
||||
*/
|
||||
/* fourth, try the system control port A */
|
||||
inb $0x92
|
||||
andb $(~0x03), %al
|
||||
testb %dl, %dl
|
||||
jz 6f
|
||||
orb $0x02, %al
|
||||
6: outb $0x92
|
||||
|
||||
/* When turning off Gate A20, do not check the state strictly,
|
||||
because a failure is not fatal usually, and Gate A20 is always
|
||||
on some modern machines. */
|
||||
testb %dl, %dl
|
||||
jz 7f
|
||||
call gate_a20_check_state
|
||||
cmpb %al, %dl
|
||||
jnz gate_a20_try_keyboard_controller
|
||||
7: ret
|
||||
|
||||
gate_a20_flush_keyboard_buffer:
|
||||
inb $0x64
|
||||
andb $0x02, %al
|
||||
jnz gate_a20_flush_keyboard_buffer
|
||||
2:
|
||||
inb $0x64
|
||||
andb $0x01, %al
|
||||
jz 3f
|
||||
inb $0x60
|
||||
jmp 2b
|
||||
3:
|
||||
ret
|
||||
|
||||
gate_a20_try_keyboard_controller:
|
||||
/* third, try the keyboard controller */
|
||||
call gate_a20_flush_keyboard_buffer
|
||||
|
||||
movb $0xd1, %al
|
||||
outb $0x64
|
||||
4:
|
||||
inb $0x64
|
||||
andb $0x02, %al
|
||||
jnz 4b
|
||||
|
||||
movb $0xdd, %al
|
||||
testb %dl, %dl
|
||||
jz 5f
|
||||
orb $0x02, %al
|
||||
5: outb $0x60
|
||||
call gate_a20_flush_keyboard_buffer
|
||||
|
||||
/* output a dummy command (USB keyboard hack) */
|
||||
movb $0xff, %al
|
||||
outb $0x64
|
||||
call gate_a20_flush_keyboard_buffer
|
||||
|
||||
call gate_a20_check_state
|
||||
cmpb %al, %dl
|
||||
/* everything failed, so restart from the beginning */
|
||||
jnz gate_a20_try_bios
|
||||
ret
|
||||
|
||||
gate_a20_check_state:
|
||||
/* iterate the checking for a while */
|
||||
movl $100, %ecx
|
||||
1:
|
||||
call 3f
|
||||
cmpb %al, %dl
|
||||
jz 2f
|
||||
loop 1b
|
||||
2:
|
||||
ret
|
||||
3:
|
||||
pushl %ebx
|
||||
pushl %ecx
|
||||
xorl %eax, %eax
|
||||
/* compare the byte at 0x8000 with that at 0x108000 */
|
||||
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
|
||||
pushl %ebx
|
||||
/* save the original byte in CL */
|
||||
movb (%ebx), %cl
|
||||
/* store the value at 0x108000 in AL */
|
||||
addl $0x100000, %ebx
|
||||
movb (%ebx), %al
|
||||
/* try to set one less value at 0x8000 */
|
||||
popl %ebx
|
||||
movb %al, %ch
|
||||
decb %ch
|
||||
movb %ch, (%ebx)
|
||||
/* serialize */
|
||||
outb %al, $0x80
|
||||
outb %al, $0x80
|
||||
/* obtain the value at 0x108000 in CH */
|
||||
pushl %ebx
|
||||
addl $0x100000, %ebx
|
||||
movb (%ebx), %ch
|
||||
/* this result is 1 if A20 is on or 0 if it is off */
|
||||
subb %ch, %al
|
||||
xorb $1, %al
|
||||
/* restore the original */
|
||||
popl %ebx
|
||||
movb %cl, (%ebx)
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
ret
|
||||
|
||||
#ifdef ENABLE_LZMA
|
||||
#include "lzma_decode.S"
|
||||
#endif
|
||||
|
||||
.p2align 4
|
||||
|
||||
LOCAL(decompressor_end):
|
|
@ -1,2 +1,2 @@
|
|||
#define FULOONG 1
|
||||
#define FULOONG2F 1
|
||||
#include "fwstart.S"
|
|
@ -26,7 +26,7 @@
|
|||
#include <grub/cs5536.h>
|
||||
#include <grub/smbus.h>
|
||||
|
||||
#ifdef FULOONG
|
||||
#ifdef FULOONG2F
|
||||
#define GRUB_MACHINE_SERIAL_PORT GRUB_MACHINE_SERIAL_PORT2
|
||||
#define GRUB_MACHINE_SERIAL_DIVISOR_115200 GRUB_MACHINE_SERIAL_PORT2_DIVISOR_115200
|
||||
#else
|
||||
|
@ -43,10 +43,10 @@
|
|||
start:
|
||||
_start:
|
||||
__start:
|
||||
/* Put serial init as soon as possible. But on Fuloong serial is past
|
||||
Geode, so on Fuloong we need Geode first.
|
||||
/* Put serial init as soon as possible. But on Fuloong2f serial is past
|
||||
Geode, so on Fuloong2f we need Geode first.
|
||||
*/
|
||||
#ifndef FULOONG
|
||||
#ifndef FULOONG2F
|
||||
bal serial_hw_init
|
||||
nop
|
||||
#endif
|
||||
|
@ -72,7 +72,7 @@ retry_cs5536:
|
|||
bnel $t2, $t3, 1b
|
||||
sll $t4, $t4, 1
|
||||
|
||||
#ifndef FULOONG
|
||||
#ifndef FULOONG2F
|
||||
bal message
|
||||
addiu $a0, $a0, %lo(cs5536_found)
|
||||
bal printhex
|
||||
|
@ -95,7 +95,7 @@ retry_cs5536:
|
|||
bal gpio_init
|
||||
nop
|
||||
|
||||
#ifdef FULOONG
|
||||
#ifdef FULOONG2F
|
||||
bal serial_hw_init
|
||||
nop
|
||||
#endif
|
||||
|
@ -130,7 +130,7 @@ retry_cs5536:
|
|||
sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL3) ($t0)
|
||||
sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0)
|
||||
|
||||
/* Yeeloong and Fuloong have only one memory slot. */
|
||||
/* Yeeloong and Fuloong2f have only one memory slot. */
|
||||
/* Output first byte on serial for debugging. */
|
||||
ori $a1, $zero, GRUB_SMB_RAM_START_ADDR
|
||||
bal read_spd
|
||||
|
@ -252,7 +252,7 @@ gpio_init:
|
|||
/* In: none. Out: none. Clobbered: $t0, $t1, $t2, $a0, $a1, $a2. */
|
||||
serial_hw_init:
|
||||
move $t2, $ra
|
||||
#ifdef FULOONG
|
||||
#ifdef FULOONG2F
|
||||
lui $a0, %hi(GRUB_CS5536_MSR_DIVIL_LEG_IO)
|
||||
addiu $a0, $a0, %lo(GRUB_CS5536_MSR_DIVIL_LEG_IO)
|
||||
lui $a1, %hi (GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3 \
|
||||
|
@ -471,7 +471,7 @@ regdump:
|
|||
.quad 0x0100020200010101 /* 4 */
|
||||
.quad 0x0a04030603050203 /* 6 */
|
||||
.quad 0x0f0e040000010a0b /* 7 */
|
||||
#ifdef FULOONG
|
||||
#ifdef FULOONG2F
|
||||
.quad 0x0000000100000001 /* 8 */
|
||||
#else
|
||||
.quad 0x0000010200000102 /* 8 */
|
||||
|
@ -482,7 +482,7 @@ regdump:
|
|||
.quad 0x002a3c0615000000 /* c */
|
||||
.quad 0x002a002a002a002a /* d */
|
||||
.quad 0x002a002a002a002a /* e */
|
||||
#ifdef FULOONG
|
||||
#ifdef FULOONG2F
|
||||
.quad 0x00b40020005b0004 /* f */
|
||||
#else
|
||||
.quad 0x00b40020006d0004 /* f */
|
||||
|
@ -503,7 +503,7 @@ regdump:
|
|||
|
||||
/* Dump of GPIO connections. FIXME: Remove useless and macroify. */
|
||||
gpio_dump:
|
||||
#ifdef FULOONG
|
||||
#ifdef FULOONG2F
|
||||
.long 0xffff0000, 0x2eefd110, 0xffff0000, 0xffff0000
|
||||
.long 0x2eefd110, 0xffff0000, 0x1000efff, 0xefff1000
|
||||
.long 0x3df3c20c, 0xffff0000, 0xffff0000, 0xffff0000
|
||||
|
@ -740,8 +740,8 @@ continue:
|
|||
lui $t0, %hi(cached_continue - 0x20000000)
|
||||
addiu $t0, $t0, %lo(cached_continue - 0x20000000)
|
||||
jr $t0
|
||||
#ifdef FULOONG
|
||||
addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_FULOONG)
|
||||
#ifdef FULOONG2F
|
||||
addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_FULOONG2F)
|
||||
#else
|
||||
addiu $a2, $zero, -(1 + GRUB_ARCH_MACHINE_YEELOONG)
|
||||
#endif
|
||||
|
|
|
@ -38,13 +38,13 @@ start:
|
|||
bal codestart
|
||||
nop
|
||||
base:
|
||||
. = _start + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE
|
||||
. = _start + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE
|
||||
compressed_size:
|
||||
.long 0
|
||||
. = _start + GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE
|
||||
. = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE
|
||||
uncompressed_size:
|
||||
.long 0
|
||||
. = _start + GRUB_KERNEL_MACHINE_UNCOMPRESSED_ADDR
|
||||
. = _start + GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR
|
||||
uncompressed_addr:
|
||||
.long 0
|
||||
codestart:
|
||||
|
@ -54,8 +54,22 @@ codestart:
|
|||
/* Parse arguments. Has to be done before relocation.
|
||||
So need to do it in asm. */
|
||||
#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS
|
||||
lui $t0, %hi (((16 << 20) - 264 + 4) | 0x80000000)
|
||||
lw $t1, %lo (((16 << 20) - 264 + 4) | 0x80000000) ($t0)
|
||||
|
||||
lui $t2, 0x1234
|
||||
ori $t2, 0x5678
|
||||
|
||||
bne $t1, $t2, 1f
|
||||
nop
|
||||
|
||||
lui $t0, %hi (((16 << 20) - 264) | 0x80000000)
|
||||
lw $s4, %lo (((16 << 20) - 264) | 0x80000000) ($t0)
|
||||
b 2f
|
||||
lw $s4, %lo (((16 << 20) - 264) | 0x80000000) ($t0)
|
||||
|
||||
1:
|
||||
li $s4, 0
|
||||
2:
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
||||
|
@ -95,7 +109,7 @@ argcont:
|
|||
DO_PARSE (memsizestr, $s4)
|
||||
DO_PARSE (highmemsizestr, $s5)
|
||||
DO_CHECKT1 (pmon_yeeloong_verstr, GRUB_ARCH_MACHINE_YEELOONG)
|
||||
DO_CHECKT1 (pmon_fuloong_verstr, GRUB_ARCH_MACHINE_FULOONG)
|
||||
DO_CHECKT1 (pmon_fuloong2f_verstr, GRUB_ARCH_MACHINE_FULOONG2F)
|
||||
2:
|
||||
b argcont
|
||||
addiu $t0, $t0, 4
|
||||
|
@ -141,11 +155,12 @@ memsizestr: .asciiz "memsize="
|
|||
highmemsizestr: .asciiz "highmemsize="
|
||||
machtype_yeeloong_str1: .asciiz "machtype=8.9"
|
||||
machtype_yeeloong_str2: .asciiz "machtype=lemote-yeeloong-"
|
||||
machtype_fuloong_str: .asciiz "machtype=lemote-fuloong-"
|
||||
machtype_fuloong2f_str: .asciiz "machtype=lemote-fuloong-2f"
|
||||
machtype_fuloong2e_str: .asciiz "machtype=lemote-fuloong-2e"
|
||||
pmon_yeeloong_str: .asciiz "PMON_VER=LM8"
|
||||
pmon_fuloong_str: .asciiz "PMON_VER=LM6"
|
||||
pmon_fuloong2f_str: .asciiz "PMON_VER=LM6"
|
||||
pmon_yeeloong_verstr: .asciiz "Version=LM8"
|
||||
pmon_fuloong_verstr: .asciiz "Version=LM6"
|
||||
pmon_fuloong2f_verstr: .asciiz "Version=LM6"
|
||||
.p2align 2
|
||||
|
||||
argdone:
|
||||
|
@ -159,8 +174,9 @@ argdone:
|
|||
DO_CHECKA1 (machtype_yeeloong_str1, GRUB_ARCH_MACHINE_YEELOONG)
|
||||
DO_CHECKA1 (machtype_yeeloong_str2, GRUB_ARCH_MACHINE_YEELOONG)
|
||||
DO_CHECKA1 (pmon_yeeloong_str, GRUB_ARCH_MACHINE_YEELOONG)
|
||||
DO_CHECKA1 (machtype_fuloong_str, GRUB_ARCH_MACHINE_FULOONG)
|
||||
DO_CHECKA1 (pmon_fuloong_str, GRUB_ARCH_MACHINE_FULOONG)
|
||||
DO_CHECKA1 (machtype_fuloong2f_str, GRUB_ARCH_MACHINE_FULOONG2F)
|
||||
DO_CHECKA1 (machtype_fuloong2e_str, GRUB_ARCH_MACHINE_FULOONG2E)
|
||||
DO_CHECKA1 (pmon_fuloong2f_str, GRUB_ARCH_MACHINE_FULOONG2F)
|
||||
addiu $a0, $a0, -1
|
||||
b argdone
|
||||
addiu $a1, $a1, 4
|
||||
|
@ -224,9 +240,9 @@ cmdlinedone:
|
|||
subu $a0, $a0, $t0
|
||||
addu $a0, $a0, $s0
|
||||
|
||||
lw $a1, (GRUB_KERNEL_MACHINE_UNCOMPRESSED_ADDR - BASE_ADDR)($s0)
|
||||
lw $a2, (GRUB_KERNEL_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0)
|
||||
lw $a3, (GRUB_KERNEL_MACHINE_UNCOMPRESSED_SIZE - BASE_ADDR)($s0)
|
||||
lw $a1, (GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_ADDR - BASE_ADDR)($s0)
|
||||
lw $a2, (GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE - BASE_ADDR)($s0)
|
||||
lw $a3, (GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE - BASE_ADDR)($s0)
|
||||
move $s1, $a1
|
||||
|
||||
/* $a0 contains source compressed address, $a1 is destination,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/boot.h>
|
||||
#include <grub/machine/boot.h>
|
||||
|
||||
.text
|
||||
|
@ -29,9 +28,6 @@ pic_base:
|
|||
call boot_continue
|
||||
mov %o4, CIF_REG
|
||||
|
||||
. = _start + GRUB_BOOT_MACHINE_VER_MAJ
|
||||
boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
|
||||
|
||||
/* The offsets to these locations are defined by the
|
||||
* GRUB_BOOT_MACHINE_foo macros in include/grub/sparc/ieee1275/boot.h,
|
||||
* and grub-setup uses this to patch these next three values as needed.
|
||||
|
@ -44,6 +40,7 @@ boot_version: .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
|
|||
* After loading in that block we will execute it by jumping to the
|
||||
* load address plus the size of the prepended A.OUT header (32 bytes).
|
||||
*/
|
||||
. = _start + GRUB_BOOT_MACHINE_BOOT_DEVPATH
|
||||
boot_path:
|
||||
. = _start + GRUB_BOOT_MACHINE_KERNEL_BYTE
|
||||
boot_path_end:
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/boot.h>
|
||||
#include <grub/machine/boot.h>
|
||||
#include <grub/offsets.h>
|
||||
|
||||
|
|
|
@ -97,8 +97,6 @@ grub_cs5536_smbus_wait (grub_port_t smbbase)
|
|||
if (grub_get_time_ms () > start + 40)
|
||||
return grub_error (GRUB_ERR_IO, "SM stalled");
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
|
@ -281,7 +279,7 @@ grub_cs5536_init_geode (grub_pci_device_t dev)
|
|||
| GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0
|
||||
| GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1);
|
||||
break;
|
||||
case GRUB_ARCH_MACHINE_FULOONG:
|
||||
case GRUB_ARCH_MACHINE_FULOONG2F:
|
||||
grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LEG_IO,
|
||||
GRUB_CS5536_MSR_DIVIL_LEG_IO_UART2_COM3
|
||||
| GRUB_CS5536_MSR_DIVIL_LEG_IO_UART1_COM1
|
||||
|
|
|
@ -115,16 +115,6 @@ grub_pci_iterate (grub_pci_iteratefunc_t hook)
|
|||
continue;
|
||||
}
|
||||
|
||||
#ifdef GRUB_MACHINE_MIPS_LOONGSON
|
||||
/* Skip ghosts. */
|
||||
if (id == GRUB_LOONGSON_OHCI_PCIID
|
||||
&& dev.function == GRUB_LOONGSON_OHCI_GHOST_FUNCTION)
|
||||
continue;
|
||||
if (id == GRUB_LOONGSON_EHCI_PCIID
|
||||
&& dev.function == GRUB_LOONGSON_EHCI_GHOST_FUNCTION)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (hook (dev, id))
|
||||
return;
|
||||
|
||||
|
|
|
@ -454,10 +454,12 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
|
|||
|
||||
fail:
|
||||
if (o)
|
||||
grub_dma_free (o->td_chunk);
|
||||
grub_dma_free (o->ed_bulk_chunk);
|
||||
grub_dma_free (o->ed_ctrl_chunk);
|
||||
grub_dma_free (o->hcca_chunk);
|
||||
{
|
||||
grub_dma_free (o->td_chunk);
|
||||
grub_dma_free (o->ed_bulk_chunk);
|
||||
grub_dma_free (o->ed_ctrl_chunk);
|
||||
grub_dma_free (o->hcca_chunk);
|
||||
}
|
||||
grub_free (o);
|
||||
|
||||
return 0;
|
||||
|
@ -1150,8 +1152,8 @@ grub_ohci_check_transfer (grub_usb_controller_t dev,
|
|||
return parse_halt (dev, transfer, actual);
|
||||
|
||||
/* Finished ED detection */
|
||||
if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf) ==
|
||||
(grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf) ) /* Empty ED */
|
||||
if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xfU) ==
|
||||
(grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xfU) ) /* Empty ED */
|
||||
{
|
||||
/* Check the HALT bit */
|
||||
/* It looks like nonsense - it was tested previously...
|
||||
|
@ -1424,18 +1426,22 @@ static struct grub_usb_controller_dev usb_controller =
|
|||
.detect_dev = grub_ohci_detect_dev
|
||||
};
|
||||
|
||||
static struct grub_preboot *fini_hnd;
|
||||
|
||||
GRUB_MOD_INIT(ohci)
|
||||
{
|
||||
COMPILE_TIME_ASSERT (sizeof (struct grub_ohci_td) == 32);
|
||||
COMPILE_TIME_ASSERT (sizeof (struct grub_ohci_ed) == 16);
|
||||
grub_ohci_inithw ();
|
||||
grub_usb_controller_dev_register (&usb_controller);
|
||||
grub_loader_register_preboot_hook (grub_ohci_fini_hw, grub_ohci_restore_hw,
|
||||
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
|
||||
fini_hnd = grub_loader_register_preboot_hook (grub_ohci_fini_hw,
|
||||
grub_ohci_restore_hw,
|
||||
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(ohci)
|
||||
{
|
||||
grub_ohci_fini_hw (0);
|
||||
grub_loader_unregister_preboot_hook (fini_hnd);
|
||||
grub_usb_controller_dev_unregister (&usb_controller);
|
||||
}
|
||||
|
|
|
@ -36,11 +36,33 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
typedef enum
|
||||
{
|
||||
GRUB_UHCI_REG_USBCMD = 0x00,
|
||||
GRUB_UHCI_REG_USBINTR = 0x04,
|
||||
GRUB_UHCI_REG_FLBASEADD = 0x08,
|
||||
GRUB_UHCI_REG_PORTSC1 = 0x10,
|
||||
GRUB_UHCI_REG_PORTSC2 = 0x12
|
||||
GRUB_UHCI_REG_PORTSC2 = 0x12,
|
||||
GRUB_UHCI_REG_USBLEGSUP = 0xc0
|
||||
} grub_uhci_reg_t;
|
||||
|
||||
/* R/WC legacy support bits */
|
||||
#define GRUB_UHCI_LEGSUP_END_A20GATE (1 << 15)
|
||||
#define GRUB_UHCI_TRAP_BY_64H_WSTAT (1 << 11)
|
||||
#define GRUB_UHCI_TRAP_BY_64H_RSTAT (1 << 10)
|
||||
#define GRUB_UHCI_TRAP_BY_60H_WSTAT (1 << 9)
|
||||
#define GRUB_UHCI_TRAP_BY_60H_RSTAT (1 << 8)
|
||||
|
||||
/* Reset all legacy support - clear all R/WC bits and all R/W bits */
|
||||
#define GRUB_UHCI_RESET_LEGSUP_SMI ( GRUB_UHCI_LEGSUP_END_A20GATE \
|
||||
| GRUB_UHCI_TRAP_BY_64H_WSTAT \
|
||||
| GRUB_UHCI_TRAP_BY_64H_RSTAT \
|
||||
| GRUB_UHCI_TRAP_BY_60H_WSTAT \
|
||||
| GRUB_UHCI_TRAP_BY_60H_RSTAT )
|
||||
|
||||
/* Some UHCI commands */
|
||||
#define GRUB_UHCI_CMD_RUN_STOP (1 << 0)
|
||||
#define GRUB_UHCI_CMD_HCRESET (1 << 1)
|
||||
#define GRUB_UHCI_CMD_MAXP (1 << 7)
|
||||
|
||||
/* Important bits in structures */
|
||||
#define GRUB_UHCI_LINK_TERMINATE 1
|
||||
#define GRUB_UHCI_LINK_QUEUE_HEAD 2
|
||||
|
||||
|
@ -181,6 +203,11 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
|
|||
if (class != 0x0c || subclass != 0x03 || interf != 0x00)
|
||||
return 0;
|
||||
|
||||
/* Set bus master - needed for coreboot or broken BIOSes */
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
|
||||
grub_pci_write_word(addr,
|
||||
GRUB_PCI_COMMAND_BUS_MASTER | grub_pci_read_word(addr));
|
||||
|
||||
/* Determine IO base address. */
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4);
|
||||
base = grub_pci_read (addr);
|
||||
|
@ -195,6 +222,19 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
|
|||
|
||||
u->iobase = base & GRUB_UHCI_IOMASK;
|
||||
|
||||
/* Reset PIRQ and SMI */
|
||||
addr = grub_pci_make_address (dev, GRUB_UHCI_REG_USBLEGSUP);
|
||||
grub_pci_write_word(addr, GRUB_UHCI_RESET_LEGSUP_SMI);
|
||||
/* Reset the HC */
|
||||
grub_uhci_writereg16(u, GRUB_UHCI_REG_USBCMD, GRUB_UHCI_CMD_HCRESET);
|
||||
grub_millisleep(5);
|
||||
/* Disable interrupts and commands (just to be safe) */
|
||||
grub_uhci_writereg16(u, GRUB_UHCI_REG_USBINTR, 0);
|
||||
/* Finish HC reset, HC remains disabled */
|
||||
grub_uhci_writereg16(u, GRUB_UHCI_REG_USBCMD, 0);
|
||||
/* Read back to be sure PCI write is done */
|
||||
grub_uhci_readreg16(u, GRUB_UHCI_REG_USBCMD);
|
||||
|
||||
/* Reserve a page for the frame list. */
|
||||
u->framelist = grub_memalign (4096, 4096);
|
||||
if (! u->framelist)
|
||||
|
@ -252,9 +292,6 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
|
|||
u->td[N_TD - 2].linkptr = 0;
|
||||
u->tdfree = u->td;
|
||||
|
||||
/* Make sure UHCI is disabled! */
|
||||
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
|
||||
|
||||
/* Setup the frame list pointers. Since no isochronous transfers
|
||||
are and will be supported, they all point to the (same!) queue
|
||||
head. */
|
||||
|
@ -285,7 +322,8 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
|
|||
u->qh[N_QH - 1].linkptr = 1;
|
||||
|
||||
/* Enable UHCI again. */
|
||||
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7));
|
||||
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD,
|
||||
GRUB_UHCI_CMD_RUN_STOP | GRUB_UHCI_CMD_MAXP);
|
||||
|
||||
/* UHCI is initialized and ready for transfers. */
|
||||
grub_dprintf ("uhci", "UHCI initialized\n");
|
||||
|
@ -506,8 +544,11 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev,
|
|||
{
|
||||
grub_size_t actual = 0;
|
||||
/* Terminate and free. */
|
||||
td_prev->linkptr2 = 0;
|
||||
td_prev->linkptr = 1;
|
||||
if (td_prev)
|
||||
{
|
||||
td_prev->linkptr2 = 0;
|
||||
td_prev->linkptr = 1;
|
||||
}
|
||||
|
||||
if (cdata->td_first)
|
||||
grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual);
|
||||
|
|
|
@ -138,6 +138,7 @@ iszero (grub_uint8_t *reg, int size)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
grub_err_t
|
||||
grub_acpi_create_ebda (void)
|
||||
{
|
||||
|
@ -165,7 +166,7 @@ grub_acpi_create_ebda (void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ebda = (grub_uint8_t *) UINT_TO_PTR ((*((grub_uint16_t *)0x40e)) << 4);
|
||||
ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4);
|
||||
ebda_kb_len = *(grub_uint16_t *) ebda;
|
||||
if (! ebda || ebda_kb_len > 16)
|
||||
ebda_kb_len = 0;
|
||||
|
@ -173,14 +174,14 @@ grub_acpi_create_ebda (void)
|
|||
|
||||
/* FIXME: use low-memory mm allocation once it's available. */
|
||||
grub_mmap_iterate (find_hook);
|
||||
targetebda = (grub_uint8_t *) UINT_TO_PTR (highestlow);
|
||||
targetebda = (grub_uint8_t *) (grub_addr_t) highestlow;
|
||||
grub_dprintf ("acpi", "creating ebda @%llx\n",
|
||||
(unsigned long long) highestlow);
|
||||
if (! highestlow)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"couldn't find space for the new EBDA");
|
||||
|
||||
mmapregion = grub_mmap_register (PTR_TO_UINT64 (targetebda), ebda_len,
|
||||
mmapregion = grub_mmap_register ((grub_addr_t) targetebda, ebda_len,
|
||||
GRUB_MEMORY_RESERVED);
|
||||
if (! mmapregion)
|
||||
return grub_errno;
|
||||
|
@ -297,6 +298,7 @@ grub_acpi_create_ebda (void)
|
|||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Create tables common to ACPIv1 and ACPIv2+ */
|
||||
static void
|
||||
|
@ -328,13 +330,13 @@ setup_common_tables (void)
|
|||
if (grub_memcmp (fadt->hdr.signature, GRUB_ACPI_FADT_SIGNATURE,
|
||||
sizeof (fadt->hdr.signature)) == 0)
|
||||
{
|
||||
fadt->dsdt_addr = PTR_TO_UINT32 (table_dsdt);
|
||||
fadt->dsdt_addr = (grub_addr_t) table_dsdt;
|
||||
fadt->facs_addr = facs_addr;
|
||||
|
||||
/* Does a revision 2 exist at all? */
|
||||
if (fadt->hdr.revision >= 3)
|
||||
{
|
||||
fadt->dsdt_xaddr = PTR_TO_UINT64 (table_dsdt);
|
||||
fadt->dsdt_xaddr = (grub_addr_t) table_dsdt;
|
||||
fadt->facs_xaddr = facs_addr;
|
||||
}
|
||||
|
||||
|
@ -365,7 +367,7 @@ setup_common_tables (void)
|
|||
rsdt->creator_rev = root_creator_rev;
|
||||
|
||||
for (cur = acpi_tables; cur; cur = cur->next)
|
||||
*(rsdt_entry++) = PTR_TO_UINT32 (cur->addr);
|
||||
*(rsdt_entry++) = (grub_addr_t) cur->addr;
|
||||
|
||||
/* Recompute checksum. */
|
||||
rsdt->checksum = 0;
|
||||
|
@ -383,7 +385,7 @@ setv1table (void)
|
|||
sizeof (rsdpv1_new->signature));
|
||||
grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid));
|
||||
rsdpv1_new->revision = 0;
|
||||
rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
|
||||
rsdpv1_new->rsdt_addr = (grub_addr_t) rsdt_addr;
|
||||
rsdpv1_new->checksum = 0;
|
||||
rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new,
|
||||
sizeof (*rsdpv1_new));
|
||||
|
@ -408,7 +410,7 @@ setv2table (void)
|
|||
|
||||
xsdt_entry = (grub_uint64_t *)(xsdt + 1);
|
||||
for (cur = acpi_tables; cur; cur = cur->next)
|
||||
*(xsdt_entry++) = PTR_TO_UINT64 (cur->addr);
|
||||
*(xsdt_entry++) = (grub_addr_t) cur->addr;
|
||||
grub_memcpy (&(xsdt->signature), "XSDT", 4);
|
||||
xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables;
|
||||
xsdt->revision = 1;
|
||||
|
@ -428,12 +430,12 @@ setv2table (void)
|
|||
grub_memcpy (&(rsdpv2_new->rsdpv1.oemid), root_oemid,
|
||||
sizeof (rsdpv2_new->rsdpv1.oemid));
|
||||
rsdpv2_new->rsdpv1.revision = rev2;
|
||||
rsdpv2_new->rsdpv1.rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
|
||||
rsdpv2_new->rsdpv1.rsdt_addr = (grub_addr_t) rsdt_addr;
|
||||
rsdpv2_new->rsdpv1.checksum = 0;
|
||||
rsdpv2_new->rsdpv1.checksum = 1 + ~grub_byte_checksum
|
||||
(&(rsdpv2_new->rsdpv1), sizeof (rsdpv2_new->rsdpv1));
|
||||
rsdpv2_new->length = sizeof (*rsdpv2_new);
|
||||
rsdpv2_new->xsdt_addr = PTR_TO_UINT64 (xsdt);
|
||||
rsdpv2_new->xsdt_addr = (grub_addr_t) xsdt;
|
||||
rsdpv2_new->checksum = 0;
|
||||
rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new,
|
||||
rsdpv2_new->length);
|
||||
|
@ -463,7 +465,6 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
|
|||
struct grub_arg_list *state = ctxt->state;
|
||||
struct grub_acpi_rsdp_v10 *rsdp;
|
||||
struct efiemu_acpi_table *cur, *t;
|
||||
grub_err_t err;
|
||||
int i, mmapregion;
|
||||
int numoftables;
|
||||
|
||||
|
@ -506,7 +507,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
|
|||
/* Set revision variables to replicate the same version as host. */
|
||||
rev1 = ! rsdp->revision;
|
||||
rev2 = rsdp->revision;
|
||||
rsdt = (struct grub_acpi_table_header *) UINT_TO_PTR (rsdp->rsdt_addr);
|
||||
rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp->rsdt_addr;
|
||||
/* Load host tables. */
|
||||
for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
|
||||
entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
|
||||
|
@ -516,7 +517,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
|
|||
char signature[5];
|
||||
struct efiemu_acpi_table *table;
|
||||
struct grub_acpi_table_header *curtable
|
||||
= (struct grub_acpi_table_header *) UINT_TO_PTR (*entry_ptr);
|
||||
= (struct grub_acpi_table_header *) (grub_addr_t) *entry_ptr;
|
||||
signature[4] = 0;
|
||||
for (i = 0; i < 4;i++)
|
||||
signature[i] = grub_tolower (curtable->signature[i]);
|
||||
|
@ -540,7 +541,7 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
|
|||
|
||||
/* Load DSDT if not excluded. */
|
||||
dsdt = (struct grub_acpi_table_header *)
|
||||
UINT_TO_PTR (fadt->dsdt_addr);
|
||||
(grub_addr_t) fadt->dsdt_addr;
|
||||
if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt"))
|
||||
&& (! load_only || grub_strword (load_only, "dsdt"))
|
||||
&& dsdt->length >= sizeof (*dsdt))
|
||||
|
@ -732,13 +733,20 @@ grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
|
|||
}
|
||||
acpi_tables = 0;
|
||||
|
||||
if (! state[9].set && (err = grub_acpi_create_ebda ()))
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
if (! state[9].set)
|
||||
{
|
||||
rsdpv1_new = 0;
|
||||
rsdpv2_new = 0;
|
||||
grub_mmap_free_and_unregister (mmapregion);
|
||||
return err;
|
||||
grub_err_t err;
|
||||
err = grub_acpi_create_ebda ();
|
||||
if (err)
|
||||
{
|
||||
rsdpv1_new = 0;
|
||||
rsdpv2_new = 0;
|
||||
grub_mmap_free_and_unregister (mmapregion);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@ typedef uint8_t grub_uint8_t;
|
|||
#endif
|
||||
|
||||
#include <grub/acpi.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
#ifndef GRUB_DSDT_TEST
|
||||
#include <grub/misc.h>
|
||||
|
@ -327,6 +328,6 @@ grub_acpi_halt (void)
|
|||
|
||||
grub_millisleep (1500);
|
||||
|
||||
grub_printf ("ACPI shutdown failed\n");
|
||||
grub_puts_ (N_("ACPI shutdown failed"));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -31,17 +31,17 @@ static grub_err_t (*grub_loader_boot_func) (void);
|
|||
static grub_err_t (*grub_loader_unload_func) (void);
|
||||
static int grub_loader_noreturn;
|
||||
|
||||
struct grub_preboot_t
|
||||
struct grub_preboot
|
||||
{
|
||||
grub_err_t (*preboot_func) (int);
|
||||
grub_err_t (*preboot_rest_func) (void);
|
||||
grub_loader_preboot_hook_prio_t prio;
|
||||
struct grub_preboot_t *next;
|
||||
struct grub_preboot_t *prev;
|
||||
struct grub_preboot *next;
|
||||
struct grub_preboot *prev;
|
||||
};
|
||||
|
||||
static int grub_loader_loaded;
|
||||
static struct grub_preboot_t *preboots_head = 0,
|
||||
static struct grub_preboot *preboots_head = 0,
|
||||
*preboots_tail = 0;
|
||||
|
||||
int
|
||||
|
@ -51,18 +51,18 @@ grub_loader_is_loaded (void)
|
|||
}
|
||||
|
||||
/* Register a preboot hook. */
|
||||
void *
|
||||
struct grub_preboot *
|
||||
grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn),
|
||||
grub_err_t (*preboot_rest_func) (void),
|
||||
grub_loader_preboot_hook_prio_t prio)
|
||||
{
|
||||
struct grub_preboot_t *cur, *new_preboot;
|
||||
struct grub_preboot *cur, *new_preboot;
|
||||
|
||||
if (! preboot_func && ! preboot_rest_func)
|
||||
return 0;
|
||||
|
||||
new_preboot = (struct grub_preboot_t *)
|
||||
grub_malloc (sizeof (struct grub_preboot_t));
|
||||
new_preboot = (struct grub_preboot *)
|
||||
grub_malloc (sizeof (struct grub_preboot));
|
||||
if (! new_preboot)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, "hook not added");
|
||||
|
@ -96,9 +96,9 @@ grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn),
|
|||
}
|
||||
|
||||
void
|
||||
grub_loader_unregister_preboot_hook (void *hnd)
|
||||
grub_loader_unregister_preboot_hook (struct grub_preboot *hnd)
|
||||
{
|
||||
struct grub_preboot_t *preb = hnd;
|
||||
struct grub_preboot *preb = hnd;
|
||||
|
||||
if (preb->next)
|
||||
preb->next->prev = preb->prev;
|
||||
|
@ -143,7 +143,7 @@ grub_err_t
|
|||
grub_loader_boot (void)
|
||||
{
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
struct grub_preboot_t *cur;
|
||||
struct grub_preboot *cur;
|
||||
|
||||
if (! grub_loader_loaded)
|
||||
return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
|
||||
|
|
58
grub-core/commands/cacheinfo.c
Normal file
58
grub-core/commands/cacheinfo.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* cacheinfo.c - disk cache statistics */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/disk.h>
|
||||
|
||||
static grub_err_t
|
||||
grub_rescue_cmd_info (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
unsigned long hits, misses;
|
||||
|
||||
grub_disk_cache_get_performance (&hits, &misses);
|
||||
grub_printf_ (N_("Disk cache: hits = %lu, misses = %lu "), hits, misses);
|
||||
if (hits + misses)
|
||||
{
|
||||
unsigned long ratio = hits * 10000 / (hits + misses);
|
||||
grub_printf ("(%lu.%lu%%)\n", ratio / 100, ratio % 100);
|
||||
}
|
||||
else
|
||||
grub_puts_ (N_("(N/A)"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_command_t cmd_cacheinfo;
|
||||
|
||||
GRUB_MOD_INIT(cacheinfo)
|
||||
{
|
||||
cmd_cacheinfo =
|
||||
grub_register_command ("cacheinfo", grub_rescue_cmd_info,
|
||||
0, N_("Get disk cache info."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(cacheinfo)
|
||||
{
|
||||
grub_unregister_command (cmd_cacheinfo);
|
||||
}
|
|
@ -42,8 +42,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (argc != 2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required");
|
||||
|
||||
grub_printf ("Compare file `%s' with `%s':\n", args[0],
|
||||
args[1]);
|
||||
grub_printf_ (N_("Compare file `%s' with `%s':\n"), args[0],
|
||||
args[1]);
|
||||
|
||||
file1 = grub_file_open (args[0]);
|
||||
file2 = grub_file_open (args[1]);
|
||||
|
@ -51,9 +51,9 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
|
|||
goto cleanup;
|
||||
|
||||
if (grub_file_size (file1) != grub_file_size (file2))
|
||||
grub_printf ("Files differ in size: %llu [%s], %llu [%s]\n",
|
||||
(unsigned long long) grub_file_size (file1), args[0],
|
||||
(unsigned long long) grub_file_size (file2), args[1]);
|
||||
grub_printf_ (N_("Files differ in size: %llu [%s], %llu [%s]\n"),
|
||||
(unsigned long long) grub_file_size (file1), args[0],
|
||||
(unsigned long long) grub_file_size (file2), args[1]);
|
||||
else
|
||||
{
|
||||
pos = 0;
|
||||
|
@ -78,9 +78,9 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
|
|||
{
|
||||
if (buf1[i] != buf2[i])
|
||||
{
|
||||
grub_printf ("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n",
|
||||
(unsigned long long) (i + pos), buf1[i], args[0],
|
||||
buf2[i], args[1]);
|
||||
grub_printf_ (N_("Files differ at the offset %llu: 0x%x [%s], 0x%x [%s]\n"),
|
||||
(unsigned long long) (i + pos), buf1[i],
|
||||
args[0], buf2[i], args[1]);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -89,15 +89,14 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
|
|||
}
|
||||
while (rd2);
|
||||
|
||||
grub_printf ("The files are identical.\n");
|
||||
/* TRANSLATORS: it's always exactly 2 files. */
|
||||
grub_printf_ (N_("The files are identical.\n"));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
if (buf1)
|
||||
grub_free (buf1);
|
||||
if (buf2)
|
||||
grub_free (buf2);
|
||||
grub_free (buf1);
|
||||
grub_free (buf2);
|
||||
if (file1)
|
||||
grub_file_close (file1);
|
||||
if (file2)
|
||||
|
|
|
@ -56,24 +56,24 @@ scan_card (grub_pci_device_t dev, grub_pci_id_t pciid)
|
|||
{
|
||||
grub_target_addr_t base;
|
||||
|
||||
grub_printf ("Found graphic card: %s\n", p->name);
|
||||
grub_dprintf ("fixvideo", "Found graphic card: %s\n", p->name);
|
||||
addr += 8 + p->mmio_bar * 4;
|
||||
base = grub_pci_read (addr);
|
||||
if ((! base) || (base & GRUB_PCI_ADDR_SPACE_IO) ||
|
||||
(base & GRUB_PCI_ADDR_MEM_PREFETCH))
|
||||
grub_printf ("Invalid MMIO bar %d\n", p->mmio_bar);
|
||||
grub_dprintf ("fixvideo", "Invalid MMIO bar %d\n", p->mmio_bar);
|
||||
else
|
||||
{
|
||||
base &= GRUB_PCI_ADDR_MEM_MASK;
|
||||
base += p->mmio_reg;
|
||||
|
||||
if (*((volatile grub_uint32_t *) base) != p->mmio_old)
|
||||
grub_printf ("Old value don't match\n");
|
||||
grub_dprintf ("fixvideo", "Old value doesn't match\n");
|
||||
else
|
||||
{
|
||||
*((volatile grub_uint32_t *) base) = 0;
|
||||
if (*((volatile grub_uint32_t *) base))
|
||||
grub_printf ("Set MMIO fails\n");
|
||||
grub_dprintf ("fixvideo", "Setting MMIO fails\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ scan_card (grub_pci_device_t dev, grub_pci_id_t pciid)
|
|||
p++;
|
||||
}
|
||||
|
||||
grub_printf ("Unknown graphic card: %x\n", pciid);
|
||||
grub_dprintf ("fixvideo", "Unknown graphic card: %x\n", pciid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -49,7 +49,7 @@ enable_rom_area (void)
|
|||
rom_ptr = (grub_uint32_t *) VBIOS_ADDR;
|
||||
if (*rom_ptr != BLANK_MEM)
|
||||
{
|
||||
grub_printf ("ROM image is present.\n");
|
||||
grub_puts_ (N_("ROM image is present."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ enable_rom_area (void)
|
|||
*rom_ptr = 0;
|
||||
if (*rom_ptr != 0)
|
||||
{
|
||||
grub_printf ("Can\'t enable ROM area.\n");
|
||||
grub_puts_ (N_("Can\'t enable ROM area."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,7 @@ GRUB_MOD_INIT(loadbios)
|
|||
0, N_("Fake BIOS."));
|
||||
|
||||
cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios,
|
||||
"BIOS_DUMP [INT10_DUMP]",
|
||||
N_("BIOS_DUMP [INT10_DUMP]"),
|
||||
N_("Load BIOS dump."));
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_printf ("New MBR is written to '%s'\n", args[0]);
|
||||
grub_printf_ (N_("New MBR is written to '%s'\n"), args[0]);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -24,13 +24,12 @@
|
|||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_err_t
|
||||
static grub_err_t __attribute__ ((noreturn))
|
||||
grub_cmd_halt (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
grub_halt ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
|
|
@ -141,7 +141,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
|
|||
grub_file_close (file);
|
||||
if (err)
|
||||
{
|
||||
grub_printf ("%s: READ ERROR\n", p);
|
||||
grub_printf_ (N_("%s: READ ERROR\n"), p);
|
||||
if (!keep)
|
||||
{
|
||||
grub_file_close (hashlist);
|
||||
|
@ -155,7 +155,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
|
|||
}
|
||||
if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0)
|
||||
{
|
||||
grub_printf ("%s: HASH MISMATCH\n", p);
|
||||
grub_printf_ (N_("%s: HASH MISMATCH\n"), p);
|
||||
if (!keep)
|
||||
{
|
||||
grub_file_close (hashlist);
|
||||
|
@ -166,7 +166,7 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
|
|||
mismatch++;
|
||||
continue;
|
||||
}
|
||||
grub_printf ("%s: OK\n", p);
|
||||
grub_printf_ (N_("%s: OK\n"), p);
|
||||
}
|
||||
if (mismatch || unread)
|
||||
return grub_error (GRUB_ERR_TEST_FAILURE,
|
||||
|
@ -257,8 +257,8 @@ static grub_extcmd_t cmd, cmd_md5, cmd_sha1, cmd_sha256, cmd_sha512, cmd_crc;
|
|||
GRUB_MOD_INIT(hashsum)
|
||||
{
|
||||
cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, 0,
|
||||
"hashsum -h HASH [-c FILE [-p PREFIX]] "
|
||||
"[FILE1 [FILE2 ...]]",
|
||||
N_("-h HASH [-c FILE [-p PREFIX]] "
|
||||
"[FILE1 [FILE2 ...]]"),
|
||||
N_("Compute or check hash checksum."),
|
||||
options);
|
||||
cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <grub/ata.h>
|
||||
#include <grub/scsi.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
|
@ -63,60 +64,64 @@ enum grub_ata_smart_commands
|
|||
static int quiet = 0;
|
||||
|
||||
static grub_err_t
|
||||
grub_hdparm_do_ata_cmd (grub_disk_t disk, grub_uint8_t cmd,
|
||||
grub_hdparm_do_ata_cmd (grub_ata_t ata, grub_uint8_t cmd,
|
||||
grub_uint8_t features, grub_uint8_t sectors,
|
||||
void * buffer, int size)
|
||||
{
|
||||
struct grub_disk_ata_pass_through_parms apt;
|
||||
grub_memset (&apt, 0, sizeof (apt));
|
||||
|
||||
apt.taskfile[GRUB_ATA_REG_CMD] = cmd;
|
||||
apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
|
||||
apt.taskfile[GRUB_ATA_REG_SECTORS] = sectors;
|
||||
apt.taskfile.cmd = cmd;
|
||||
apt.taskfile.features = features;
|
||||
apt.taskfile.sectors = sectors;
|
||||
apt.taskfile.disk = 0xE0;
|
||||
|
||||
apt.buffer = buffer;
|
||||
apt.size = size;
|
||||
|
||||
if (grub_disk_ata_pass_through (disk, &apt))
|
||||
if (ata->dev->readwrite (ata, &apt, 0))
|
||||
return grub_errno;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_hdparm_do_check_powermode_cmd (grub_disk_t disk)
|
||||
grub_hdparm_do_check_powermode_cmd (grub_ata_t ata)
|
||||
{
|
||||
struct grub_disk_ata_pass_through_parms apt;
|
||||
grub_memset (&apt, 0, sizeof (apt));
|
||||
|
||||
apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_CHECK_POWER_MODE;
|
||||
apt.taskfile.cmd = GRUB_ATA_CMD_CHECK_POWER_MODE;
|
||||
apt.taskfile.disk = 0xE0;
|
||||
|
||||
if (grub_disk_ata_pass_through (disk, &apt))
|
||||
if (ata->dev->readwrite (ata, &apt, 0))
|
||||
return -1;
|
||||
|
||||
return apt.taskfile[GRUB_ATA_REG_SECTORS];
|
||||
return apt.taskfile.sectors;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
|
||||
grub_hdparm_do_smart_cmd (grub_ata_t ata, grub_uint8_t features)
|
||||
{
|
||||
struct grub_disk_ata_pass_through_parms apt;
|
||||
grub_memset (&apt, 0, sizeof (apt));
|
||||
|
||||
apt.taskfile[GRUB_ATA_REG_CMD] = GRUB_ATA_CMD_SMART;
|
||||
apt.taskfile[GRUB_ATA_REG_FEATURES] = features;
|
||||
apt.taskfile[GRUB_ATA_REG_LBAMID] = 0x4f;
|
||||
apt.taskfile[GRUB_ATA_REG_LBAHIGH] = 0xc2;
|
||||
apt.taskfile.cmd = GRUB_ATA_CMD_SMART;
|
||||
apt.taskfile.features = features;
|
||||
apt.taskfile.lba_mid = 0x4f;
|
||||
apt.taskfile.lba_high = 0xc2;
|
||||
apt.taskfile.disk = 0xE0;
|
||||
|
||||
if (grub_disk_ata_pass_through (disk, &apt))
|
||||
if (ata->dev->readwrite (ata, &apt, 0))
|
||||
return -1;
|
||||
|
||||
if (features == GRUB_ATA_FEAT_SMART_STATUS)
|
||||
{
|
||||
if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0x4f
|
||||
&& apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2)
|
||||
if ( apt.taskfile.lba_mid == 0x4f
|
||||
&& apt.taskfile.lba_high == 0xc2)
|
||||
return 0; /* Good SMART status. */
|
||||
else if ( apt.taskfile[GRUB_ATA_REG_LBAMID] == 0xf4
|
||||
&& apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c)
|
||||
else if ( apt.taskfile.lba_mid == 0xf4
|
||||
&& apt.taskfile.lba_high == 0x2c)
|
||||
return 1; /* Bad SMART status. */
|
||||
else
|
||||
return -1;
|
||||
|
@ -126,12 +131,12 @@ grub_hdparm_do_smart_cmd (grub_disk_t disk, grub_uint8_t features)
|
|||
|
||||
static grub_err_t
|
||||
grub_hdparm_simple_cmd (const char * msg,
|
||||
grub_disk_t disk, grub_uint8_t cmd)
|
||||
grub_ata_t ata, grub_uint8_t cmd)
|
||||
{
|
||||
if (! quiet && msg)
|
||||
grub_printf ("%s", msg);
|
||||
|
||||
grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, 0, 0, NULL, 0);
|
||||
grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, 0, 0, NULL, 0);
|
||||
|
||||
if (! quiet && msg)
|
||||
grub_printf ("%s\n", ! err ? "" : ": not supported");
|
||||
|
@ -140,7 +145,7 @@ grub_hdparm_simple_cmd (const char * msg,
|
|||
|
||||
static grub_err_t
|
||||
grub_hdparm_set_val_cmd (const char * msg, int val,
|
||||
grub_disk_t disk, grub_uint8_t cmd,
|
||||
grub_ata_t ata, grub_uint8_t cmd,
|
||||
grub_uint8_t features, grub_uint8_t sectors)
|
||||
{
|
||||
if (! quiet && msg && *msg)
|
||||
|
@ -151,7 +156,7 @@ grub_hdparm_set_val_cmd (const char * msg, int val,
|
|||
grub_printf ("Disable %s", msg);
|
||||
}
|
||||
|
||||
grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors,
|
||||
grub_err_t err = grub_hdparm_do_ata_cmd (ata, cmd, features, sectors,
|
||||
NULL, 0);
|
||||
|
||||
if (! quiet && msg)
|
||||
|
@ -160,22 +165,20 @@ grub_hdparm_set_val_cmd (const char * msg, int val,
|
|||
}
|
||||
|
||||
static const char *
|
||||
le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes)
|
||||
le16_to_char (grub_uint16_t *dest, const grub_uint16_t * src16, unsigned bytes)
|
||||
{
|
||||
grub_uint16_t * dest16 = (grub_uint16_t *) dest;
|
||||
unsigned i;
|
||||
for (i = 0; i < bytes / 2; i++)
|
||||
dest16[i] = grub_be_to_cpu16 (src16[i]);
|
||||
return dest;
|
||||
dest[i] = grub_be_to_cpu16 (src16[i]);
|
||||
dest[i] = 0;
|
||||
return (char *) dest;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_hdparm_print_identify (const char * idbuf)
|
||||
grub_hdparm_print_identify (const grub_uint16_t * idw)
|
||||
{
|
||||
const grub_uint16_t * idw = (const grub_uint16_t *) idbuf;
|
||||
|
||||
/* Print identity strings. */
|
||||
char tmp[40];
|
||||
grub_uint16_t tmp[21];
|
||||
grub_printf ("Model: \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40));
|
||||
grub_printf ("Firmware: \"%.8s\"\n", le16_to_char (tmp, &idw[23], 8));
|
||||
grub_printf ("Serial: \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20));
|
||||
|
@ -275,6 +278,7 @@ static grub_err_t
|
|||
grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
struct grub_ata *ata;
|
||||
|
||||
/* Check command line. */
|
||||
if (argc != 1)
|
||||
|
@ -285,9 +289,6 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name");
|
||||
args[0][len - 1] = 0;
|
||||
|
||||
if (! grub_disk_ata_pass_through)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "ATA pass through not available");
|
||||
|
||||
int i = 0;
|
||||
int apm = get_int_arg (&state[i++]);
|
||||
int power = state[i++].set;
|
||||
|
@ -313,15 +314,37 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed");
|
||||
}
|
||||
|
||||
switch (disk->dev->id)
|
||||
{
|
||||
case GRUB_DISK_DEVICE_ATA_ID:
|
||||
ata = disk->data;
|
||||
break;
|
||||
case GRUB_DISK_DEVICE_SCSI_ID:
|
||||
if (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF)
|
||||
== GRUB_SCSI_SUBSYSTEM_PATA
|
||||
|| (((disk->id >> GRUB_SCSI_ID_SUBSYSTEM_SHIFT) & 0xFF)
|
||||
== GRUB_SCSI_SUBSYSTEM_AHCI))
|
||||
{
|
||||
ata = ((struct grub_scsi *) disk->data)->data;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return grub_error (GRUB_ERR_IO, "not an ATA device");
|
||||
}
|
||||
|
||||
|
||||
/* Change settings. */
|
||||
if (aam >= 0)
|
||||
grub_hdparm_set_val_cmd ("Automatic Acoustic Management", (aam ? aam : -1),
|
||||
disk, GRUB_ATA_CMD_SET_FEATURES, (aam ? 0x42 : 0xc2), aam);
|
||||
ata, GRUB_ATA_CMD_SET_FEATURES,
|
||||
(aam ? 0x42 : 0xc2), aam);
|
||||
|
||||
if (apm >= 0)
|
||||
grub_hdparm_set_val_cmd ("Advanced Power Management",
|
||||
(apm != 255 ? apm : -1), disk, GRUB_ATA_CMD_SET_FEATURES,
|
||||
(apm != 255 ? 0x05 : 0x85), (apm != 255 ? apm : 0));
|
||||
(apm != 255 ? apm : -1), ata,
|
||||
GRUB_ATA_CMD_SET_FEATURES,
|
||||
(apm != 255 ? 0x05 : 0x85),
|
||||
(apm != 255 ? apm : 0));
|
||||
|
||||
if (standby_tout >= 0)
|
||||
{
|
||||
|
@ -332,28 +355,28 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
grub_printf (")");
|
||||
}
|
||||
/* The IDLE cmd sets disk to idle mode and configures standby timer. */
|
||||
grub_hdparm_set_val_cmd ("", -1, disk, GRUB_ATA_CMD_IDLE, 0, standby_tout);
|
||||
grub_hdparm_set_val_cmd ("", -1, ata, GRUB_ATA_CMD_IDLE, 0, standby_tout);
|
||||
}
|
||||
|
||||
if (enable_smart >= 0)
|
||||
{
|
||||
if (! quiet)
|
||||
grub_printf ("%sable SMART operations", (enable_smart ? "En" : "Dis"));
|
||||
int err = grub_hdparm_do_smart_cmd (disk, (enable_smart ?
|
||||
int err = grub_hdparm_do_smart_cmd (ata, (enable_smart ?
|
||||
GRUB_ATA_FEAT_SMART_ENABLE : GRUB_ATA_FEAT_SMART_DISABLE));
|
||||
if (! quiet)
|
||||
grub_printf ("%s\n", err ? ": not supported" : "");
|
||||
}
|
||||
|
||||
if (sec_freeze)
|
||||
grub_hdparm_simple_cmd ("Freeze security settings", disk,
|
||||
grub_hdparm_simple_cmd ("Freeze security settings", ata,
|
||||
GRUB_ATA_CMD_SECURITY_FREEZE_LOCK);
|
||||
|
||||
/* Print/dump IDENTIFY. */
|
||||
if (ident || dumpid)
|
||||
{
|
||||
char buf[GRUB_DISK_SECTOR_SIZE];
|
||||
if (grub_hdparm_do_ata_cmd (disk, GRUB_ATA_CMD_IDENTIFY_DEVICE,
|
||||
grub_uint16_t buf[GRUB_DISK_SECTOR_SIZE / 2];
|
||||
if (grub_hdparm_do_ata_cmd (ata, GRUB_ATA_CMD_IDENTIFY_DEVICE,
|
||||
0, 0, buf, sizeof (buf)))
|
||||
grub_printf ("Cannot read ATA IDENTIFY data\n");
|
||||
else
|
||||
|
@ -361,7 +384,7 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
if (ident)
|
||||
grub_hdparm_print_identify (buf);
|
||||
if (dumpid)
|
||||
hexdump (0, buf, sizeof (buf));
|
||||
hexdump (0, (char *) buf, sizeof (buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +392,7 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
if (power)
|
||||
{
|
||||
grub_printf ("Disk power mode is: ");
|
||||
int mode = grub_hdparm_do_check_powermode_cmd (disk);
|
||||
int mode = grub_hdparm_do_check_powermode_cmd (ata);
|
||||
if (mode < 0)
|
||||
grub_printf ("unknown\n");
|
||||
else
|
||||
|
@ -385,7 +408,7 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
{
|
||||
if (! quiet)
|
||||
grub_printf ("SMART status is: ");
|
||||
int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS);
|
||||
int err = grub_hdparm_do_smart_cmd (ata, GRUB_ATA_FEAT_SMART_STATUS);
|
||||
if (! quiet)
|
||||
grub_printf ("%s\n", (err < 0 ? "unknown" :
|
||||
err == 0 ? "OK" : "*BAD*"));
|
||||
|
@ -394,11 +417,11 @@ grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
|
|||
|
||||
/* Change power mode. */
|
||||
if (standby_now)
|
||||
grub_hdparm_simple_cmd ("Set disk to standby mode", disk,
|
||||
grub_hdparm_simple_cmd ("Set disk to standby mode", ata,
|
||||
GRUB_ATA_CMD_STANDBY_IMMEDIATE);
|
||||
|
||||
if (sleep_now)
|
||||
grub_hdparm_simple_cmd ("Set disk to sleep mode", disk,
|
||||
grub_hdparm_simple_cmd ("Set disk to sleep mode", ata,
|
||||
GRUB_ATA_CMD_SLEEP);
|
||||
|
||||
grub_disk_close (disk);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <grub/command.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/cmos.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -46,12 +47,17 @@ grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)),
|
|||
{
|
||||
int byte, bit;
|
||||
grub_err_t err;
|
||||
grub_uint8_t value;
|
||||
|
||||
err = parse_args (argc, argv, &byte, &bit);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (grub_cmos_read (byte) & (1 << bit))
|
||||
err = grub_cmos_read (byte, &value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (value & (1 << bit))
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
return grub_error (GRUB_ERR_TEST_FAILURE, "false");
|
||||
|
@ -63,13 +69,16 @@ grub_cmd_cmosclean (struct grub_command *cmd __attribute__ ((unused)),
|
|||
{
|
||||
int byte, bit;
|
||||
grub_err_t err;
|
||||
grub_uint8_t value;
|
||||
|
||||
err = parse_args (argc, argv, &byte, &bit);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_cmos_read (byte, &value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
grub_cmos_write (byte, grub_cmos_read (byte) & (~(1 << bit)));
|
||||
return GRUB_ERR_NONE;
|
||||
return grub_cmos_write (byte, value & (~(1 << bit)));
|
||||
}
|
||||
|
||||
static grub_command_t cmd, cmd_clean;
|
||||
|
@ -78,11 +87,11 @@ static grub_command_t cmd, cmd_clean;
|
|||
GRUB_MOD_INIT(cmostest)
|
||||
{
|
||||
cmd = grub_register_command ("cmostest", grub_cmd_cmostest,
|
||||
"cmostest BYTE:BIT",
|
||||
"Test bit at BYTE:BIT in CMOS.");
|
||||
N_("BYTE:BIT"),
|
||||
N_("Test bit at BYTE:BIT in CMOS."));
|
||||
cmd_clean = grub_register_command ("cmosclean", grub_cmd_cmosclean,
|
||||
"cmosclean BYTE:BIT",
|
||||
"Clean bit at BYTE:BIT in CMOS.");
|
||||
N_("BYTE:BIT"),
|
||||
N_("Clean bit at BYTE:BIT in CMOS."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(cmostest)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */
|
||||
static grub_uint32_t *const int13slot = UINT_TO_PTR (4 * 0x13);
|
||||
static grub_uint32_t *const int13slot = (grub_uint32_t *) (4 * 0x13);
|
||||
|
||||
/* Remember to update enum opt_idxs accordingly. */
|
||||
static const struct grub_arg_option options[] = {
|
||||
|
@ -178,11 +178,11 @@ list_mappings (void)
|
|||
/* Show: list mappings. */
|
||||
if (! map_head)
|
||||
{
|
||||
grub_printf ("No drives have been remapped\n");
|
||||
grub_puts_ (N_("No drives have been remapped"));
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_printf ("OS disk #num ------> GRUB/BIOS device\n");
|
||||
grub_puts_ (N_("OS disk #num ------> GRUB/BIOS device"));
|
||||
drivemap_node_t *curnode = map_head;
|
||||
while (curnode)
|
||||
{
|
||||
|
@ -363,7 +363,7 @@ uninstall_int13_handler (void)
|
|||
static int
|
||||
grub_get_root_biosnumber_drivemap (void)
|
||||
{
|
||||
char *biosnum;
|
||||
const char *biosnum;
|
||||
int ret = -1;
|
||||
grub_device_t dev;
|
||||
|
||||
|
|
|
@ -74,27 +74,27 @@ grub_cmd_lsapm (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (!grub_apm_get_info (&info))
|
||||
return grub_error (GRUB_ERR_IO, "no APM found");
|
||||
|
||||
grub_printf ("Vesion %u.%u\n"
|
||||
"32-bit CS = 0x%x, len = 0x%x, offset = 0x%x\n"
|
||||
"16-bit CS = 0x%x, len = 0x%x\n"
|
||||
"DS = 0x%x, len = 0x%x\n",
|
||||
info.version >> 8, info.version & 0xff,
|
||||
info.cseg, info.cseg_len, info.offset,
|
||||
info.cseg_16, info.cseg_16_len,
|
||||
info.dseg, info.dseg_len);
|
||||
grub_printf_ (N_("Vesion %u.%u\n"
|
||||
"32-bit CS = 0x%x, len = 0x%x, offset = 0x%x\n"
|
||||
"16-bit CS = 0x%x, len = 0x%x\n"
|
||||
"DS = 0x%x, len = 0x%x\n"),
|
||||
info.version >> 8, info.version & 0xff,
|
||||
info.cseg, info.cseg_len, info.offset,
|
||||
info.cseg_16, info.cseg_16_len,
|
||||
info.dseg, info.dseg_len);
|
||||
grub_xputs (info.flags & GRUB_APM_FLAGS_16BITPROTECTED_SUPPORTED
|
||||
? "16-bit protected interface supported\n"
|
||||
: "16-bit protected interface unsupported\n");
|
||||
? _("16-bit protected interface supported\n")
|
||||
: _("16-bit protected interface unsupported\n"));
|
||||
grub_xputs (info.flags & GRUB_APM_FLAGS_32BITPROTECTED_SUPPORTED
|
||||
? "32-bit protected interface supported\n"
|
||||
: "32-bit protected interface unsupported\n");
|
||||
? _("32-bit protected interface supported\n")
|
||||
: _("32-bit protected interface unsupported\n"));
|
||||
grub_xputs (info.flags & GRUB_APM_FLAGS_CPUIDLE_SLOWS_DOWN
|
||||
? "CPU Idle slows down processor\n"
|
||||
: "CPU Idle doesn't slow down processor\n");
|
||||
? _("CPU Idle slows down processor\n")
|
||||
: _("CPU Idle doesn't slow down processor\n"));
|
||||
grub_xputs (info.flags & GRUB_APM_FLAGS_DISABLED
|
||||
? "APM disabled\n" : "APM enabled\n");
|
||||
? _("APM disabled\n") : _("APM enabled\n"));
|
||||
grub_xputs (info.flags & GRUB_APM_FLAGS_DISENGAGED
|
||||
? "APM disengaged\n" : "APM engaged\n");
|
||||
? _("APM disengaged\n") : _("APM engaged\n"));
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)),
|
|||
file = grub_file_open (args[0]);
|
||||
|
||||
if (! file)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", args[0]);
|
||||
|
||||
if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo))
|
||||
{
|
||||
|
@ -227,7 +227,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
if (*end)
|
||||
/* Was not a number either, assume it was supposed to be a file name. */
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", args[0]);
|
||||
|
||||
grub_dprintf ("play","tempo = %d\n", tempo);
|
||||
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/* pxe.c - command to control the pxe driver */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/machine/pxe.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_pxe_unload (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
if (! grub_pxe_pxenv)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "no pxe environment");
|
||||
|
||||
grub_pxe_unload ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(pxecmd)
|
||||
{
|
||||
cmd = grub_register_command ("pxe_unload", grub_cmd_pxe_unload,
|
||||
0,
|
||||
N_("Unload PXE environment."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(pxecmd)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
#include <grub/extcmd.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv2+");
|
||||
|
||||
|
@ -35,23 +36,23 @@ static int keylen = 0;
|
|||
static int noled = 0;
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"num", 'n', 0, "set numlock mode", "[on|off]", ARG_TYPE_STRING},
|
||||
{"caps", 'c', 0, "set capslock mode", "[on|off]", ARG_TYPE_STRING},
|
||||
{"scroll", 's', 0, "set scrolllock mode", "[on|off]", ARG_TYPE_STRING},
|
||||
{"insert", 0, 0, "set insert mode", "[on|off]", ARG_TYPE_STRING},
|
||||
{"pause", 0, 0, "set pause mode", "[on|off]", ARG_TYPE_STRING},
|
||||
{"left-shift", 0, 0, "press left shift", "[on|off]", ARG_TYPE_STRING},
|
||||
{"right-shift", 0, 0, "press right shift", "[on|off]", ARG_TYPE_STRING},
|
||||
{"sysrq", 0, 0, "press SysRq", "[on|off]", ARG_TYPE_STRING},
|
||||
{"numkey", 0, 0, "press NumLock key", "[on|off]", ARG_TYPE_STRING},
|
||||
{"capskey", 0, 0, "press CapsLock key", "[on|off]", ARG_TYPE_STRING},
|
||||
{"scrollkey", 0, 0, "press ScrollLock key", "[on|off]", ARG_TYPE_STRING},
|
||||
{"insertkey", 0, 0, "press Insert key", "[on|off]", ARG_TYPE_STRING},
|
||||
{"left-alt", 0, 0, "press left alt", "[on|off]", ARG_TYPE_STRING},
|
||||
{"right-alt", 0, 0, "press right alt", "[on|off]", ARG_TYPE_STRING},
|
||||
{"left-ctrl", 0, 0, "press left ctrl", "[on|off]", ARG_TYPE_STRING},
|
||||
{"right-ctrl", 0, 0, "press right ctrl", "[on|off]", ARG_TYPE_STRING},
|
||||
{"no-led", 0, 0, "don't update LED state", 0, 0},
|
||||
{"num", 'n', 0, N_("set numlock mode"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"caps", 'c', 0, N_("set capslock mode"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"scroll", 's', 0, N_("set scrolllock mode"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"insert", 0, 0, N_("set insert mode"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"pause", 0, 0, N_("set pause mode"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"left-shift", 0, 0, N_("press left shift"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"right-shift", 0, 0, N_("press right shift"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"sysrq", 0, 0, N_("press SysRq"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"numkey", 0, 0, N_("press NumLock key"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"capskey", 0, 0, N_("press CapsLock key"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"scrollkey", 0, 0, N_("press ScrollLock key"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"insertkey", 0, 0, N_("press Insert key"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"left-alt", 0, 0, N_("press left alt"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"right-alt", 0, 0, N_("press right alt"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"left-ctrl", 0, 0, N_("press left ctrl"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"right-ctrl", 0, 0, N_("press right ctrl"), "[on|off]", ARG_TYPE_STRING},
|
||||
{"no-led", 0, 0, N_("don't update LED state"), 0, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
static int simple_flag_offsets[]
|
||||
|
@ -62,8 +63,8 @@ static grub_uint32_t andmask = 0xffffffff, ormask = 0;
|
|||
struct
|
||||
keysym
|
||||
{
|
||||
char *unshifted_name; /* the name in unshifted state */
|
||||
char *shifted_name; /* the name in shifted state */
|
||||
const char *unshifted_name; /* the name in unshifted state */
|
||||
const char *shifted_name; /* the name in shifted state */
|
||||
unsigned char unshifted_ascii; /* the ascii code in unshifted state */
|
||||
unsigned char shifted_ascii; /* the ascii code in shifted state */
|
||||
unsigned char keycode; /* keyboard scancode */
|
||||
|
@ -364,13 +365,13 @@ grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args)
|
|||
}
|
||||
|
||||
static grub_extcmd_t cmd;
|
||||
static void *preboot_hook;
|
||||
static struct grub_preboot *preboot_hook;
|
||||
|
||||
GRUB_MOD_INIT (sendkey)
|
||||
{
|
||||
cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey, 0,
|
||||
"sendkey [KEYSTROKE1] [KEYSTROKE2] ...",
|
||||
"Emulate a keystroke", options);
|
||||
N_("[KEYSTROKE1] [KEYSTROKE2] ..."),
|
||||
N_("Emulate a keystroke"), options);
|
||||
|
||||
preboot_hook
|
||||
= grub_loader_register_preboot_hook (grub_sendkey_preboot,
|
||||
|
|
|
@ -31,7 +31,7 @@ grub_cmd_suspend (grub_command_t cmd __attribute__ ((unused)),
|
|||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
grub_printf ("Run 'go' to resume GRUB.\n");
|
||||
grub_puts_ (N_("Run 'go' to resume GRUB."));
|
||||
grub_ieee1275_enter ();
|
||||
grub_cls ();
|
||||
return 0;
|
||||
|
|
|
@ -344,7 +344,7 @@ grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)),
|
|||
int bsd_part = -1;
|
||||
{
|
||||
grub_device_t dev;
|
||||
char *hdbiasstr;
|
||||
const char *hdbiasstr;
|
||||
int hdbias = 0;
|
||||
hdbiasstr = grub_env_get ("legacy_hdbias");
|
||||
if (hdbiasstr)
|
||||
|
@ -723,7 +723,7 @@ grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unuse
|
|||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected");
|
||||
grub_printf ("Enter password:");
|
||||
grub_puts_ (N_("Enter password: "));
|
||||
if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
|
||||
return GRUB_ACCESS_DENIED;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ open_envblk_file (char *filename)
|
|||
|
||||
if (! filename)
|
||||
{
|
||||
char *prefix;
|
||||
const char *prefix;
|
||||
|
||||
prefix = grub_env_get ("prefix");
|
||||
if (prefix)
|
||||
|
@ -346,7 +346,7 @@ grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
|
|||
|
||||
while (argc)
|
||||
{
|
||||
char *value;
|
||||
const char *value;
|
||||
|
||||
value = grub_env_get (args[0]);
|
||||
if (value)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <grub/extcmd.h>
|
||||
#include <grub/datetime.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/net.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -60,6 +61,22 @@ grub_ls_list_devices (int longlist)
|
|||
|
||||
grub_device_iterate (grub_ls_print_devices);
|
||||
grub_xputs ("\n");
|
||||
|
||||
#ifndef GRUB_UTIL
|
||||
{
|
||||
grub_net_app_level_t proto;
|
||||
int first = 1;
|
||||
FOR_NET_APP_LEVEL (proto)
|
||||
{
|
||||
if (first)
|
||||
grub_puts_ (N_ ("Network protocols:"));
|
||||
first = 0;
|
||||
grub_printf ("%s ", proto->name);
|
||||
}
|
||||
grub_xputs ("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
grub_refresh ();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -26,13 +26,13 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
|
||||
static const char *names[] =
|
||||
{
|
||||
[GRUB_MEMORY_AVAILABLE] = "available",
|
||||
[GRUB_MEMORY_RESERVED] = "reserved",
|
||||
[GRUB_MEMORY_ACPI] = "ACPI reclamaible",
|
||||
[GRUB_MEMORY_NVS] = "NVS",
|
||||
[GRUB_MEMORY_BADRAM] = "BadRAM",
|
||||
[GRUB_MEMORY_CODE] = "firmware code",
|
||||
[GRUB_MEMORY_HOLE] = "hole"
|
||||
[GRUB_MEMORY_AVAILABLE] = N_("available"),
|
||||
[GRUB_MEMORY_RESERVED] = N_("reserved"),
|
||||
[GRUB_MEMORY_ACPI] = N_("ACPI reclamaible"),
|
||||
[GRUB_MEMORY_NVS] = N_("ACPI non-volatile storage"),
|
||||
[GRUB_MEMORY_BADRAM] = N_("BadRAM"),
|
||||
[GRUB_MEMORY_CODE] = N_("firmware code"),
|
||||
[GRUB_MEMORY_HOLE] = N_("hole")
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
|
@ -46,11 +46,11 @@ grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_memory_type_t type)
|
||||
{
|
||||
if (type < ARRAY_SIZE (names) && names[type])
|
||||
grub_printf ("base_addr = 0x%llx, length = 0x%llx, %s\n",
|
||||
(long long) addr, (long long) size, names[type]);
|
||||
grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, %s\n"),
|
||||
(long long) addr, (long long) size, _(names[type]));
|
||||
else
|
||||
grub_printf ("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n",
|
||||
(long long) addr, (long long) size, type);
|
||||
grub_printf_ (N_("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n"),
|
||||
(long long) addr, (long long) size, type);
|
||||
return 0;
|
||||
}
|
||||
#ifndef GRUB_MACHINE_EMU
|
||||
|
|
|
@ -29,7 +29,7 @@ struct grub_pci_classname
|
|||
{
|
||||
int class;
|
||||
int subclass;
|
||||
char *desc;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
static const struct grub_pci_classname grub_pci_classes[] =
|
||||
|
|
|
@ -31,7 +31,7 @@ static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword;
|
|||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{0, 'v', 0, N_("Save read value into variable VARNAME."),
|
||||
"VARNAME", ARG_TYPE_STRING},
|
||||
N_("VARNAME"), ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
|
|
@ -28,19 +28,19 @@
|
|||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"class", 1, GRUB_ARG_OPTION_REPEATABLE,
|
||||
N_("Menu entry type."), "STRING", ARG_TYPE_STRING},
|
||||
N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
|
||||
{"users", 2, 0,
|
||||
N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
|
||||
N_("Users allowed to boot this entry."), N_("USERNAME"), ARG_TYPE_STRING},
|
||||
{"hotkey", 3, 0,
|
||||
N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
|
||||
N_("Keyboard key for this entry."), N_("KEY"), ARG_TYPE_STRING},
|
||||
{"source", 4, 0,
|
||||
N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING},
|
||||
N_("Menu entry definition as a string."), N_("STRING"), ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
char *name;
|
||||
const char *name;
|
||||
int key;
|
||||
} hotkey_aliases[] =
|
||||
{
|
||||
|
|
|
@ -90,26 +90,6 @@ grub_mini_cmd_help (struct grub_command *cmd __attribute__ ((unused)),
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
grub_rescue_cmd_info (void)
|
||||
{
|
||||
extern void grub_disk_cache_get_performance (unsigned long *,
|
||||
unsigned long *);
|
||||
unsigned long hits, misses;
|
||||
|
||||
grub_disk_cache_get_performance (&hits, &misses);
|
||||
grub_printf ("Disk cache: hits = %u, misses = %u ", hits, misses);
|
||||
if (hits + misses)
|
||||
{
|
||||
unsigned long ratio = hits * 10000 / (hits + misses);
|
||||
grub_printf ("(%u.%u%%)\n", ratio / 100, ratio % 100);
|
||||
}
|
||||
else
|
||||
grub_printf ("(N/A)\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dump ADDRESS [SIZE] */
|
||||
static grub_err_t
|
||||
grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)),
|
||||
|
@ -165,7 +145,7 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)),
|
|||
{
|
||||
grub_dl_t mod;
|
||||
|
||||
grub_printf ("Name\tRef Count\tDependencies\n");
|
||||
grub_printf_ (N_("Name\tRef Count\tDependencies\n"));
|
||||
FOR_DL_MODULES (mod)
|
||||
{
|
||||
grub_dl_dep_t dep;
|
||||
|
@ -185,13 +165,13 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
/* exit */
|
||||
static grub_err_t
|
||||
static grub_err_t __attribute__ ((noreturn))
|
||||
grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char *argv[] __attribute__ ((unused)))
|
||||
{
|
||||
grub_exit ();
|
||||
return 0;
|
||||
/* Not reached. */
|
||||
}
|
||||
|
||||
static grub_command_t cmd_cat, cmd_help;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/cs5536.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -38,43 +39,44 @@ grub_cmd_lsspd (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
if (!grub_cs5536_find (&dev))
|
||||
{
|
||||
grub_printf ("No CS5536 found\n");
|
||||
grub_puts_ (N_("No CS5536 found"));
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
grub_printf ("CS5536 at %d:%d.%d\n", grub_pci_get_bus (dev),
|
||||
grub_pci_get_device (dev), grub_pci_get_function (dev));
|
||||
grub_printf_ (N_("CS5536 at %d:%d.%d\n"), grub_pci_get_bus (dev),
|
||||
grub_pci_get_device (dev), grub_pci_get_function (dev));
|
||||
|
||||
err = grub_cs5536_init_smbus (dev, 0x7fff, &smbbase);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
grub_printf ("SMB base = 0x%x\n", smbbase);
|
||||
grub_printf_ (N_("SMB base = 0x%x\n"), smbbase);
|
||||
|
||||
for (i = GRUB_SMB_RAM_START_ADDR;
|
||||
i < GRUB_SMB_RAM_START_ADDR + GRUB_SMB_RAM_NUM_MAX; i++)
|
||||
{
|
||||
struct grub_smbus_spd spd;
|
||||
grub_memset (&spd, 0, sizeof (spd));
|
||||
grub_printf ("Device %d\n", i);
|
||||
grub_printf_ (N_("Device %d\n"), i);
|
||||
err = grub_cs5536_read_spd (smbbase, i, &spd);
|
||||
if (err)
|
||||
{
|
||||
grub_print_error ();
|
||||
continue;
|
||||
}
|
||||
grub_printf ("Written SPD bytes: %d B.\n", spd.written_size);
|
||||
grub_printf ("Total flash size: %d B.\n", 1 << spd.log_total_flash_size);
|
||||
grub_printf_ (N_("Written SPD bytes: %d B.\n"), spd.written_size);
|
||||
grub_printf_ (N_("Total flash size: %d B.\n"),
|
||||
1 << spd.log_total_flash_size);
|
||||
if (spd.memory_type == GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2)
|
||||
{
|
||||
char str[sizeof (spd.ddr2.part_number) + 1];
|
||||
grub_printf ("Memory type: DDR2.\n");
|
||||
grub_puts_ (N_("Memory type: DDR2."));
|
||||
grub_memcpy (str, spd.ddr2.part_number,
|
||||
sizeof (spd.ddr2.part_number));
|
||||
str[sizeof (spd.ddr2.part_number)] = 0;
|
||||
grub_printf ("Part no: %s.\n", str);
|
||||
grub_printf_ (N_("Part no: %s.\n"), str);
|
||||
}
|
||||
else
|
||||
grub_printf ("Memory type: Unknown.\n");
|
||||
grub_puts_ (N_("Memory type: Unknown."));
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
@ -85,7 +87,7 @@ static grub_command_t cmd;
|
|||
GRUB_MOD_INIT(lsspd)
|
||||
{
|
||||
cmd = grub_register_command ("lsspd", grub_cmd_lsspd, 0,
|
||||
"Print Memory information.");
|
||||
N_("Print Memory information."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(lsspd)
|
||||
|
|
|
@ -37,9 +37,9 @@ static struct grub_parttool *parts = 0;
|
|||
static int curhandle = 0;
|
||||
static grub_dl_t mymod;
|
||||
static char helpmsg[] =
|
||||
"Perform COMMANDS on partition.\n"
|
||||
"Use \"parttool PARTITION help\" for the list "
|
||||
"of available commands.";
|
||||
N_("Perform COMMANDS on partition.\n"
|
||||
"Use \"parttool PARTITION help\" for the list "
|
||||
"of available commands.");
|
||||
|
||||
int
|
||||
grub_parttool_register(const char *part_name,
|
||||
|
@ -128,7 +128,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)),
|
|||
break;
|
||||
|
||||
case GRUB_PARTTOOL_ARG_VAL:
|
||||
grub_printf ("=VAL");
|
||||
grub_xputs (_("=VAL"));
|
||||
spacing -= 4;
|
||||
break;
|
||||
|
||||
|
@ -137,18 +137,18 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)),
|
|||
}
|
||||
while (spacing-- > 0)
|
||||
grub_printf (" ");
|
||||
grub_printf ("%s\n", curarg->desc);
|
||||
grub_puts_ (curarg->desc);
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
grub_printf ("Sorry no parttool is available for %s\n",
|
||||
grub_printf_ (N_("Sorry no parttool is available for %s\n"),
|
||||
dev->disk->partition->partmap->name);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
grub_printf ("%s\n", helpmsg);
|
||||
grub_puts_ (helpmsg);
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments");
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args)
|
|||
{
|
||||
const char *val = "none";
|
||||
if (dev->net)
|
||||
val = dev->net->dev->name;
|
||||
val = dev->net->protocol->name;
|
||||
if (dev->disk)
|
||||
val = dev->disk->dev->name;
|
||||
if (state[0].set)
|
||||
|
@ -136,7 +136,7 @@ grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args)
|
|||
return err;
|
||||
if (! label)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"uuid for this FS isn't supported yet");
|
||||
"label for this FS isn't supported yet");
|
||||
|
||||
if (state[0].set)
|
||||
grub_env_set (state[0].arg, label);
|
||||
|
|
|
@ -24,13 +24,12 @@
|
|||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_err_t
|
||||
static grub_err_t __attribute__ ((noreturn))
|
||||
grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
grub_reboot ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
|
|
@ -66,12 +66,12 @@ static struct pci_register pci_registers[] =
|
|||
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{0, 'd', 0, "Select device by vendor and device IDs.",
|
||||
"[vendor]:[device]", ARG_TYPE_STRING},
|
||||
{0, 's', 0, "Select device by its position on the bus.",
|
||||
"[bus]:[slot][.func]", ARG_TYPE_STRING},
|
||||
{0, 'v', 0, "Save read value into variable VARNAME.",
|
||||
"VARNAME", ARG_TYPE_STRING},
|
||||
{0, 'd', 0, N_("Select device by vendor and device IDs."),
|
||||
N_("[vendor]:[device]"), ARG_TYPE_STRING},
|
||||
{0, 's', 0, N_("Select device by its position on the bus."),
|
||||
N_("[bus]:[slot][.func]"), ARG_TYPE_STRING},
|
||||
{0, 'v', 0, N_("Save read value into variable VARNAME."),
|
||||
N_("VARNAME"), ARG_TYPE_STRING},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -128,7 +128,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
|
|||
|
||||
if (!write_mask)
|
||||
{
|
||||
grub_printf ("Register %x of %d:%d.%d is %x\n", regaddr,
|
||||
grub_printf (N_("Register %x of %d:%d.%d is %x\n"), regaddr,
|
||||
grub_pci_get_bus (dev),
|
||||
grub_pci_get_device (dev),
|
||||
grub_pci_get_function (dev),
|
||||
|
|
68
grub-core/commands/time.c
Normal file
68
grub-core/commands/time.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* echo.c - Command to display a line of text */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/time.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_time (grub_command_t ctxt __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
grub_command_t cmd;
|
||||
grub_uint32_t start;
|
||||
grub_uint32_t end;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "command expected");
|
||||
|
||||
cmd = grub_command_find (args[0]);
|
||||
|
||||
if (!cmd)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_COMMAND, "Unknown command `%s'\n",
|
||||
args[0]);
|
||||
|
||||
start = grub_get_time_ms ();
|
||||
(cmd->func) (cmd, argc - 1, &args[1]);
|
||||
end = grub_get_time_ms ();
|
||||
|
||||
grub_printf_ (N_("Elapsed time: %d.%03d seconds \n"), (end - start) / 1000,
|
||||
(end - start) % 1000);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(time)
|
||||
{
|
||||
cmd = grub_register_command ("time", grub_cmd_time,
|
||||
N_("COMMAND [ARGS]"),
|
||||
N_("Measure time used by COMMAND"));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(time)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static unsigned height, width, depth;
|
||||
static struct grub_video_mode_info *current_mode;
|
||||
|
||||
static int
|
||||
hook (const struct grub_video_mode_info *info)
|
||||
|
@ -41,44 +42,74 @@ hook (const struct grub_video_mode_info *info)
|
|||
if (info->mode_number == GRUB_VIDEO_MODE_NUMBER_INVALID)
|
||||
grub_printf (" ");
|
||||
else
|
||||
grub_printf (" 0x%03x ", info->mode_number);
|
||||
{
|
||||
if (current_mode && info->mode_number == current_mode->mode_number)
|
||||
grub_printf ("*");
|
||||
else
|
||||
grub_printf (" ");
|
||||
grub_printf (" 0x%03x ", info->mode_number);
|
||||
}
|
||||
grub_printf ("%4d x %4d x %2d ", info->width, info->height, info->bpp);
|
||||
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
|
||||
grub_printf ("Text-only ");
|
||||
grub_xputs (_("Text-only "));
|
||||
/* Show mask and position details for direct color modes. */
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_RGB)
|
||||
grub_printf ("Direct, mask: %d/%d/%d/%d pos: %d/%d/%d/%d",
|
||||
info->red_mask_size,
|
||||
info->green_mask_size,
|
||||
info->blue_mask_size,
|
||||
info->reserved_mask_size,
|
||||
info->red_field_pos,
|
||||
info->green_field_pos,
|
||||
info->blue_field_pos,
|
||||
info->reserved_field_pos);
|
||||
grub_printf_ (N_("Direct, mask: %d/%d/%d/%d pos: %d/%d/%d/%d"),
|
||||
info->red_mask_size,
|
||||
info->green_mask_size,
|
||||
info->blue_mask_size,
|
||||
info->reserved_mask_size,
|
||||
info->red_field_pos,
|
||||
info->green_field_pos,
|
||||
info->blue_field_pos,
|
||||
info->reserved_field_pos);
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
|
||||
grub_printf ("Packed ");
|
||||
grub_xputs (_("Packed "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_YUV)
|
||||
grub_printf ("YUV ");
|
||||
grub_xputs (_("YUV "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PLANAR)
|
||||
grub_printf ("Planar ");
|
||||
grub_xputs (_("Planar "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_HERCULES)
|
||||
grub_printf ("Hercules ");
|
||||
grub_xputs (_("Hercules "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_CGA)
|
||||
grub_printf ("CGA ");
|
||||
grub_xputs (_("CGA "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_NONCHAIN4)
|
||||
grub_printf ("Non-chain 4 ");
|
||||
grub_xputs (_("Non-chain 4 "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP)
|
||||
grub_printf ("Monochrome ");
|
||||
grub_xputs (_("Monochrome "));
|
||||
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_UNKNOWN)
|
||||
grub_printf ("Unknown ");
|
||||
grub_xputs (_("Unknown "));
|
||||
|
||||
grub_printf ("\n");
|
||||
grub_xputs ("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
print_edid (struct grub_video_edid_info *edid_info)
|
||||
{
|
||||
unsigned int edid_width, edid_height;
|
||||
|
||||
if (grub_video_edid_checksum (edid_info))
|
||||
{
|
||||
grub_puts_ (N_(" EDID checksum invalid"));
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
grub_printf_ (N_(" EDID version: %u.%u\n"),
|
||||
edid_info->version, edid_info->revision);
|
||||
if (grub_video_edid_preferred_mode (edid_info, &edid_width, &edid_height)
|
||||
== GRUB_ERR_NONE)
|
||||
grub_printf_ (N_(" Preferred mode: %ux%u\n"), edid_width, edid_height);
|
||||
else
|
||||
{
|
||||
grub_printf_ (N_(" No preferred mode available\n"));
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
|
@ -116,25 +147,38 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
id = grub_video_get_driver_id ();
|
||||
|
||||
grub_printf ("List of supported video modes:\n");
|
||||
grub_printf ("Legend: P=Packed pixel, D=Direct color, "
|
||||
"mask/pos=R/G/B/reserved\n");
|
||||
grub_puts_ (N_("List of supported video modes:"));
|
||||
grub_puts_ (N_("Legend: P=Packed pixel, D=Direct color, "
|
||||
"mask/pos=R/G/B/reserved"));
|
||||
|
||||
FOR_VIDEO_ADAPTERS (adapter)
|
||||
{
|
||||
grub_printf ("Adapter '%s':\n", adapter->name);
|
||||
struct grub_video_mode_info info;
|
||||
struct grub_video_edid_info edid_info;
|
||||
|
||||
grub_printf_ (N_("Adapter '%s':\n"), adapter->name);
|
||||
|
||||
if (!adapter->iterate)
|
||||
{
|
||||
grub_printf (" No info available\n");
|
||||
grub_puts_ (N_(" No info available"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (adapter->id != id)
|
||||
current_mode = NULL;
|
||||
|
||||
if (adapter->id == id)
|
||||
{
|
||||
if (grub_video_get_info (&info) == GRUB_ERR_NONE)
|
||||
current_mode = &info;
|
||||
else
|
||||
/* Don't worry about errors. */
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (adapter->init ())
|
||||
{
|
||||
grub_printf (" Failed\n");
|
||||
grub_puts_ (N_(" Failed"));
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
@ -145,6 +189,13 @@ grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
adapter->iterate (hook);
|
||||
|
||||
if (adapter->get_edid && adapter->get_edid (&edid_info) == GRUB_ERR_NONE)
|
||||
print_edid (&edid_info);
|
||||
else
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
current_mode = NULL;
|
||||
|
||||
if (adapter->id != id)
|
||||
{
|
||||
if (adapter->fini ())
|
||||
|
@ -164,12 +215,13 @@ static grub_command_t cmd_vbe;
|
|||
|
||||
GRUB_MOD_INIT(videoinfo)
|
||||
{
|
||||
cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo, "[WxH[xD]]",
|
||||
cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo, N_("[WxH[xD]]"),
|
||||
N_("List available video modes. If "
|
||||
"resolution is given show only modes"
|
||||
" matching it."));
|
||||
#ifdef GRUB_MACHINE_PCBIOS
|
||||
cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo, "[WxH[xD]]",
|
||||
cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo,
|
||||
N_("[WxH[xD]]"),
|
||||
N_("List available video modes. If "
|
||||
"resolution is given show only modes"
|
||||
" matching it."));
|
||||
|
|
|
@ -74,6 +74,8 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)),
|
|||
grub_video_create_render_target (&text_layer, width, height,
|
||||
GRUB_VIDEO_MODE_TYPE_RGB
|
||||
| GRUB_VIDEO_MODE_TYPE_ALPHA);
|
||||
if (!text_layer)
|
||||
goto fail;
|
||||
|
||||
grub_video_set_active_render_target (text_layer);
|
||||
|
||||
|
@ -191,6 +193,11 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return grub_errno;
|
||||
|
||||
fail:
|
||||
grub_video_delete_render_target (text_layer);
|
||||
grub_video_restore ();
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
|
|
@ -139,6 +139,7 @@ make_regex (const char *start, const char *end, regex_t *regexp)
|
|||
case '.':
|
||||
case '(':
|
||||
case ')':
|
||||
case '@':
|
||||
buffer[i++] = '\\';
|
||||
buffer[i++] = ch;
|
||||
break;
|
||||
|
@ -255,8 +256,7 @@ match_devices (const regex_t *regexp, int noparts)
|
|||
for (i = 0; devs && devs[i]; i++)
|
||||
grub_free (devs[i]);
|
||||
|
||||
if (devs)
|
||||
grub_free (devs);
|
||||
grub_free (devs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -288,6 +288,8 @@ match_files (const char *prefix, const char *suffix, const char *end,
|
|||
if (regexec (regexp, name, 0, 0, 0))
|
||||
return 0;
|
||||
|
||||
grub_dprintf ("expand", "matched\n");
|
||||
|
||||
buffer = grub_xasprintf ("%s%s", dir, name);
|
||||
if (! buffer)
|
||||
return 1;
|
||||
|
@ -340,20 +342,17 @@ match_files (const char *prefix, const char *suffix, const char *end,
|
|||
|
||||
fail:
|
||||
|
||||
if (dir)
|
||||
grub_free (dir);
|
||||
grub_free (dir);
|
||||
|
||||
for (i = 0; files && files[i]; i++)
|
||||
grub_free (files[i]);
|
||||
|
||||
if (files)
|
||||
grub_free (files);
|
||||
grub_free (files);
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
||||
if (device_name)
|
||||
grub_free (device_name);
|
||||
grub_free (device_name);
|
||||
|
||||
grub_error_pop ();
|
||||
return 0;
|
||||
|
@ -423,8 +422,6 @@ wildcard_expand (const char *s, char ***strs)
|
|||
while (*start)
|
||||
{
|
||||
split_path (start, &noregexop, ®exop);
|
||||
if (noregexop >= regexop) /* no more wildcards */
|
||||
break;
|
||||
|
||||
if (make_regex (noregexop, regexop, ®exp))
|
||||
goto fail;
|
||||
|
@ -439,7 +436,7 @@ wildcard_expand (const char *s, char ***strs)
|
|||
|
||||
else if (*start == '/') /* no device part */
|
||||
{
|
||||
char *root;
|
||||
const char *root;
|
||||
char *prefix;
|
||||
|
||||
root = grub_env_get ("root");
|
||||
|
|
|
@ -51,10 +51,18 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)),
|
|||
char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")];
|
||||
char *ptr;
|
||||
grub_uint8_t ctx[GRUB_MD_MD5->contextsize];
|
||||
int low = 0;
|
||||
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required");
|
||||
|
||||
if (argc > 1 && grub_strcmp (args[0], "-l") == 0)
|
||||
{
|
||||
low = 1;
|
||||
argc--;
|
||||
args++;
|
||||
}
|
||||
|
||||
serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16));
|
||||
|
||||
GRUB_MD_MD5->init (&ctx);
|
||||
|
@ -75,10 +83,11 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)),
|
|||
(unsigned int) xnu_uuid[10], (unsigned int) xnu_uuid[11],
|
||||
(unsigned int) xnu_uuid[12], (unsigned int) xnu_uuid[13],
|
||||
(unsigned int) xnu_uuid[14], (unsigned int) xnu_uuid[15]);
|
||||
for (ptr = uuid_string; *ptr; ptr++)
|
||||
*ptr = grub_toupper (*ptr);
|
||||
if (!low)
|
||||
for (ptr = uuid_string; *ptr; ptr++)
|
||||
*ptr = grub_toupper (*ptr);
|
||||
if (argc == 1)
|
||||
grub_printf ("%s", uuid_string);
|
||||
grub_printf ("%s\n", uuid_string);
|
||||
if (argc > 1)
|
||||
grub_env_set (args[1], uuid_string);
|
||||
|
||||
|
@ -91,9 +100,10 @@ static grub_command_t cmd;
|
|||
GRUB_MOD_INIT (xnu_uuid)
|
||||
{
|
||||
cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid,
|
||||
N_("GRUBUUID [VARNAME]"),
|
||||
N_("[-l] GRUBUUID [VARNAME]"),
|
||||
N_("Transform 64-bit UUID to format "
|
||||
"suitable for XNU."));
|
||||
"suitable for XNU. If -l is given keep "
|
||||
"it lowercase as done by blkid."));
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (xnu_uuid)
|
||||
|
|
89
grub-core/disk/AFSplitter.c
Normal file
89
grub-core/disk/AFSplitter.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* AFsplitter - Anti forensic information splitter
|
||||
* Copyright 2004, Clemens Fruhwirth <clemens@endorphin.org>
|
||||
*
|
||||
* AFsplitter diffuses information over a large stripe of data,
|
||||
* therefor supporting secure data destruction.
|
||||
*
|
||||
* This program is grub_free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the grub_free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the grub_free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src,
|
||||
grub_uint8_t * dst, grub_size_t blocksize,
|
||||
grub_size_t blocknumbers);
|
||||
|
||||
static void
|
||||
diffuse (const gcry_md_spec_t * hash, grub_uint8_t * src,
|
||||
grub_uint8_t * dst, grub_size_t size)
|
||||
{
|
||||
grub_size_t i;
|
||||
grub_uint32_t IV; /* host byte order independend hash IV */
|
||||
|
||||
grub_size_t fullblocks = size / hash->mdlen;
|
||||
int padding = size % hash->mdlen;
|
||||
grub_uint8_t final[hash->mdlen];
|
||||
grub_uint8_t temp[sizeof (IV) + hash->mdlen];
|
||||
|
||||
/* hash block the whole data set with different IVs to produce
|
||||
* more than just a single data block
|
||||
*/
|
||||
for (i = 0; i < fullblocks; i++)
|
||||
{
|
||||
IV = grub_cpu_to_be32 (i);
|
||||
grub_memcpy (temp, &IV, sizeof (IV));
|
||||
grub_memcpy (temp + sizeof (IV), src + hash->mdlen * i, hash->mdlen);
|
||||
grub_crypto_hash (hash, dst + hash->mdlen * i, temp,
|
||||
sizeof (IV) + hash->mdlen);
|
||||
}
|
||||
|
||||
if (padding)
|
||||
{
|
||||
IV = grub_cpu_to_be32 (i);
|
||||
grub_memcpy (temp, &IV, sizeof (IV));
|
||||
grub_memcpy (temp + sizeof (IV), src + hash->mdlen * i, padding);
|
||||
grub_crypto_hash (hash, final, temp, sizeof (IV) + padding);
|
||||
grub_memcpy (dst + hash->mdlen * i, final, padding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the splitted master key stored on disk into the original key
|
||||
*/
|
||||
gcry_err_code_t
|
||||
AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, grub_uint8_t * dst,
|
||||
grub_size_t blocksize, grub_size_t blocknumbers)
|
||||
{
|
||||
grub_size_t i;
|
||||
grub_uint8_t *bufblock;
|
||||
|
||||
bufblock = grub_zalloc (blocksize);
|
||||
if (bufblock == NULL)
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
|
||||
grub_memset (bufblock, 0, blocksize);
|
||||
for (i = 0; i < blocknumbers - 1; i++)
|
||||
{
|
||||
grub_crypto_xor (bufblock, src + (blocksize * i), bufblock, blocksize);
|
||||
diffuse (hash, bufblock, bufblock, blocksize);
|
||||
}
|
||||
grub_crypto_xor (dst, src + (i * blocksize), bufblock, blocksize);
|
||||
|
||||
grub_free (bufblock);
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
738
grub-core/disk/ahci.c
Normal file
738
grub-core/disk/ahci.c
Normal file
|
@ -0,0 +1,738 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <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>
|
||||
#include <grub/loader.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
struct grub_ahci_cmd_head
|
||||
{
|
||||
grub_uint32_t config;
|
||||
grub_uint32_t transfered;
|
||||
grub_uint64_t command_table_base;
|
||||
grub_uint32_t unused[4];
|
||||
};
|
||||
|
||||
struct grub_ahci_prdt_entry
|
||||
{
|
||||
grub_uint64_t data_base;
|
||||
grub_uint32_t unused;
|
||||
grub_uint32_t size;
|
||||
};
|
||||
|
||||
struct grub_ahci_cmd_table
|
||||
{
|
||||
grub_uint8_t cfis[0x40];
|
||||
grub_uint8_t command[0x10];
|
||||
grub_uint8_t reserved[0x30];
|
||||
struct grub_ahci_prdt_entry prdt[1];
|
||||
};
|
||||
|
||||
struct grub_ahci_hba_port
|
||||
{
|
||||
grub_uint64_t command_list_base;
|
||||
grub_uint64_t fis_base;
|
||||
grub_uint32_t intstatus;
|
||||
grub_uint32_t inten;
|
||||
grub_uint32_t command;
|
||||
grub_uint32_t unused1;
|
||||
grub_uint32_t task_file_data;
|
||||
grub_uint32_t sig;
|
||||
grub_uint32_t status;
|
||||
grub_uint32_t unused2;
|
||||
grub_uint32_t sata_error;
|
||||
grub_uint32_t sata_active;
|
||||
grub_uint32_t command_issue;
|
||||
grub_uint32_t unused3;
|
||||
grub_uint32_t fbs;
|
||||
grub_uint32_t unused4[15];
|
||||
};
|
||||
|
||||
enum grub_ahci_hba_port_command
|
||||
{
|
||||
GRUB_AHCI_HBA_PORT_CMD_ST = 0x01,
|
||||
GRUB_AHCI_HBA_PORT_CMD_FRE = 0x10,
|
||||
GRUB_AHCI_HBA_PORT_CMD_CR = 0x8000,
|
||||
GRUB_AHCI_HBA_PORT_CMD_FR = 0x4000,
|
||||
};
|
||||
|
||||
struct grub_ahci_hba
|
||||
{
|
||||
grub_uint32_t cap;
|
||||
grub_uint32_t global_control;
|
||||
grub_uint32_t intr_status;
|
||||
grub_uint32_t ports_implemented;
|
||||
grub_uint32_t unused1[6];
|
||||
grub_uint32_t bios_handoff;
|
||||
grub_uint32_t unused2[53];
|
||||
struct grub_ahci_hba_port ports[32];
|
||||
};
|
||||
|
||||
struct grub_ahci_received_fis
|
||||
{
|
||||
char raw[4096];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_AHCI_HBA_CAP_NPORTS_MASK = 0x1f
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_AHCI_HBA_GLOBAL_CONTROL_RESET = 0x00000001,
|
||||
GRUB_AHCI_HBA_GLOBAL_CONTROL_INTR_EN = 0x00000002,
|
||||
GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN = 0x80000000,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED = 1,
|
||||
GRUB_AHCI_BIOS_HANDOFF_OS_OWNED = 2,
|
||||
GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED = 8,
|
||||
GRUB_AHCI_BIOS_HANDOFF_RWC = 8
|
||||
};
|
||||
|
||||
|
||||
struct grub_ahci_device
|
||||
{
|
||||
struct grub_ahci_device *next;
|
||||
volatile struct grub_ahci_hba *hba;
|
||||
int port;
|
||||
int num;
|
||||
struct grub_pci_dma_chunk *command_list_chunk;
|
||||
volatile struct grub_ahci_cmd_head *command_list;
|
||||
struct grub_pci_dma_chunk *command_table_chunk;
|
||||
volatile struct grub_ahci_cmd_table *command_table;
|
||||
struct grub_pci_dma_chunk *rfis;
|
||||
int present;
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_readwrite_real (struct grub_ahci_device *dev,
|
||||
struct grub_disk_ata_pass_through_parms *parms,
|
||||
int spinup);
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_AHCI_CONFIG_READ = 0,
|
||||
GRUB_AHCI_CONFIG_CFIS_LENGTH_MASK = 0x1f,
|
||||
GRUB_AHCI_CONFIG_ATAPI = 0x20,
|
||||
GRUB_AHCI_CONFIG_WRITE = 0x40,
|
||||
GRUB_AHCI_CONFIG_PREFETCH = 0x80,
|
||||
GRUB_AHCI_CONFIG_RESET = 0x100,
|
||||
GRUB_AHCI_CONFIG_BIST = 0x200,
|
||||
GRUB_AHCI_CONFIG_CLEAR_R_OK = 0x400,
|
||||
GRUB_AHCI_CONFIG_PMP_MASK = 0xf000,
|
||||
GRUB_AHCI_CONFIG_PRDT_LENGTH_MASK = 0xffff0000,
|
||||
};
|
||||
#define GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT 0
|
||||
#define GRUB_AHCI_CONFIG_PMP_SHIFT 12
|
||||
#define GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT 16
|
||||
#define GRUB_AHCI_INTERRUPT_ON_COMPLETE 0x80000000
|
||||
|
||||
#define GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH 0x200000
|
||||
|
||||
static struct grub_ahci_device *grub_ahci_devices;
|
||||
static int numdevs;
|
||||
|
||||
static int
|
||||
init_port (struct grub_ahci_device *dev)
|
||||
{
|
||||
struct grub_pci_dma_chunk *command_list;
|
||||
struct grub_pci_dma_chunk *command_table;
|
||||
grub_uint64_t endtime;
|
||||
|
||||
command_list = grub_memalign_dma32 (1024, sizeof (struct grub_ahci_cmd_head));
|
||||
if (!command_list)
|
||||
return 1;
|
||||
|
||||
command_table = grub_memalign_dma32 (1024,
|
||||
sizeof (struct grub_ahci_cmd_table));
|
||||
if (!command_table)
|
||||
{
|
||||
grub_dma_free (command_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_dprintf ("ahci", "found device ahci%d (port %d)\n", dev->num, dev->port);
|
||||
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't stop FR\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't stop CR\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->hba->ports[dev->port].fbs = 2;
|
||||
|
||||
dev->rfis = grub_memalign_dma32 (4096,
|
||||
sizeof (struct grub_ahci_received_fis));
|
||||
grub_memset ((char *) grub_dma_get_virt (dev->rfis), 0,
|
||||
sizeof (struct grub_ahci_received_fis));
|
||||
dev->hba->ports[dev->port].fis_base = grub_dma_get_phys (dev->rfis);
|
||||
dev->hba->ports[dev->port].command_list_base
|
||||
= grub_dma_get_phys (command_list);
|
||||
dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_FRE;
|
||||
while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't start FR\n");
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
|
||||
goto out;
|
||||
}
|
||||
dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST;
|
||||
while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't start CR\n");
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_CR;
|
||||
goto out_stop_fr;
|
||||
}
|
||||
|
||||
dev->hba->ports[dev->port].command
|
||||
= (dev->hba->ports[dev->port].command & 0x0fffffff) | (1 << 28) | 2 | 4;
|
||||
|
||||
dev->command_list_chunk = command_list;
|
||||
dev->command_list = grub_dma_get_virt (command_list);
|
||||
dev->command_table_chunk = command_table;
|
||||
dev->command_table = grub_dma_get_virt (command_table);
|
||||
dev->command_list->command_table_base
|
||||
= grub_dma_get_phys (command_table);
|
||||
|
||||
return 0;
|
||||
out_stop_fr:
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't stop FR\n");
|
||||
break;
|
||||
}
|
||||
out:
|
||||
grub_dma_free (command_list);
|
||||
grub_dma_free (command_table);
|
||||
grub_dma_free (dev->rfis);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int NESTED_FUNC_ATTR
|
||||
grub_ahci_pciinit (grub_pci_device_t dev,
|
||||
grub_pci_id_t pciid __attribute__ ((unused)))
|
||||
{
|
||||
grub_pci_address_t addr;
|
||||
grub_uint32_t class;
|
||||
grub_uint32_t bar;
|
||||
unsigned i, nports;
|
||||
volatile struct grub_ahci_hba *hba;
|
||||
|
||||
/* Read class. */
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
|
||||
class = grub_pci_read (addr);
|
||||
|
||||
/* Check if this class ID matches that of a PCI IDE Controller. */
|
||||
if (class >> 8 != 0x010601)
|
||||
return 0;
|
||||
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG5);
|
||||
bar = grub_pci_read (addr);
|
||||
|
||||
if ((bar & (GRUB_PCI_ADDR_SPACE_MASK | GRUB_PCI_ADDR_MEM_TYPE_MASK
|
||||
| GRUB_PCI_ADDR_MEM_PREFETCH))
|
||||
!= (GRUB_PCI_ADDR_SPACE_MEMORY | GRUB_PCI_ADDR_MEM_TYPE_32))
|
||||
return 0;
|
||||
|
||||
hba = grub_pci_device_map_range (dev, bar & GRUB_PCI_ADDR_MEM_MASK,
|
||||
sizeof (hba));
|
||||
|
||||
if (! (hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_OS_OWNED))
|
||||
{
|
||||
grub_uint64_t endtime;
|
||||
|
||||
grub_dprintf ("ahci", "Requesting AHCI ownership\n");
|
||||
hba->bios_handoff = (hba->bios_handoff & ~GRUB_AHCI_BIOS_HANDOFF_RWC)
|
||||
| GRUB_AHCI_BIOS_HANDOFF_OS_OWNED;
|
||||
grub_dprintf ("ahci", "Waiting for BIOS to give up ownership\n");
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED)
|
||||
&& grub_get_time_ms () < endtime);
|
||||
if (hba->bios_handoff & GRUB_AHCI_BIOS_HANDOFF_BIOS_OWNED)
|
||||
{
|
||||
grub_dprintf ("ahci", "Forcibly taking ownership\n");
|
||||
hba->bios_handoff = GRUB_AHCI_BIOS_HANDOFF_OS_OWNED;
|
||||
hba->bios_handoff |= GRUB_AHCI_BIOS_HANDOFF_OS_OWNERSHIP_CHANGED;
|
||||
}
|
||||
else
|
||||
grub_dprintf ("ahci", "AHCI ownership obtained\n");
|
||||
}
|
||||
else
|
||||
grub_dprintf ("ahci", "AHCI is already in OS mode\n");
|
||||
|
||||
if (!(hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN))
|
||||
grub_dprintf ("ahci", "AHCI is in compat mode. Switching\n");
|
||||
else
|
||||
grub_dprintf ("ahci", "AHCI is in AHCI mode.\n");
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN;
|
||||
grub_millisleep (1);
|
||||
if (hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN)
|
||||
break;
|
||||
}
|
||||
if (i == 5)
|
||||
{
|
||||
grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
grub_uint64_t endtime;
|
||||
hba->global_control |= 1;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while (hba->global_control & 1)
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't reset AHCI\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
hba->global_control |= GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN;
|
||||
grub_millisleep (1);
|
||||
if (hba->global_control & GRUB_AHCI_HBA_GLOBAL_CONTROL_AHCI_EN)
|
||||
break;
|
||||
}
|
||||
if (i == 5)
|
||||
{
|
||||
grub_dprintf ("ahci", "Couldn't put AHCI in AHCI mode\n");
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
nports = (hba->cap & GRUB_AHCI_HBA_CAP_NPORTS_MASK) + 1;
|
||||
|
||||
grub_dprintf ("ahci", "%d AHCI ports\n", nports);
|
||||
|
||||
for (i = 0; i < nports; i++)
|
||||
{
|
||||
struct grub_ahci_device *adev;
|
||||
grub_uint32_t st;
|
||||
|
||||
if (!(hba->ports_implemented & (1 << i)))
|
||||
continue;
|
||||
|
||||
grub_dprintf ("ahci", "status %d:%x\n", i, hba->ports[i].status);
|
||||
/* FIXME: support hotplugging. */
|
||||
st = hba->ports[i].status;
|
||||
if ((st & 0xf) != 0x3 && (st & 0xf) != 0x1)
|
||||
continue;
|
||||
|
||||
adev = grub_malloc (sizeof (*adev));
|
||||
if (!adev)
|
||||
return 1;
|
||||
|
||||
adev->hba = hba;
|
||||
adev->port = i;
|
||||
adev->present = 1;
|
||||
adev->num = numdevs++;
|
||||
|
||||
if (init_port (adev))
|
||||
{
|
||||
grub_free (adev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_list_push (GRUB_AS_LIST_P (&grub_ahci_devices),
|
||||
GRUB_AS_LIST (adev));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_initialize (void)
|
||||
{
|
||||
grub_pci_iterate (grub_ahci_pciinit);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_fini_hw (int noreturn __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_ahci_device *dev;
|
||||
|
||||
for (dev = grub_ahci_devices; dev; dev = dev->next)
|
||||
{
|
||||
grub_uint64_t endtime;
|
||||
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_FRE;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_FR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't stop FR\n");
|
||||
break;
|
||||
}
|
||||
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't stop CR\n");
|
||||
break;
|
||||
}
|
||||
grub_dma_free (dev->command_list_chunk);
|
||||
grub_dma_free (dev->command_table_chunk);
|
||||
grub_dma_free (dev->rfis);
|
||||
dev->command_list_chunk = NULL;
|
||||
dev->command_table_chunk = NULL;
|
||||
dev->rfis = NULL;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_restore_hw (void)
|
||||
{
|
||||
struct grub_ahci_device **pdev;
|
||||
|
||||
for (pdev = &grub_ahci_devices; *pdev; pdev = &((*pdev)->next))
|
||||
if (init_port (*pdev))
|
||||
{
|
||||
struct grub_ahci_device *odev;
|
||||
odev = *pdev;
|
||||
*pdev = (*pdev)->next;
|
||||
grub_free (odev);
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
grub_ahci_iterate (int (*hook) (int id, int bus),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_ahci_device *dev;
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
FOR_LIST_ELEMENTS(dev, grub_ahci_devices)
|
||||
if (hook (GRUB_SCSI_SUBSYSTEM_AHCI, dev->num))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
find_free_cmd_slot (struct grub_ahci_device *dev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
if (dev->hda->ports[dev->port].command_issue & (1 << i))
|
||||
continue;
|
||||
if (dev->hda->ports[dev->port].sata_active & (1 << i))
|
||||
continue;
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_AHCI_FIS_REG_H2D = 0x27
|
||||
};
|
||||
|
||||
static const int register_map[11] = { 3 /* Features */,
|
||||
12 /* Sectors */,
|
||||
4 /* LBA low */,
|
||||
5 /* LBA mid */,
|
||||
6 /* LBA high */,
|
||||
7 /* Device */,
|
||||
2 /* CMD register */,
|
||||
13 /* Sectors 48 */,
|
||||
8 /* LBA48 low */,
|
||||
9 /* LBA48 mid */,
|
||||
10 /* LBA48 high */ };
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_readwrite_real (struct grub_ahci_device *dev,
|
||||
struct grub_disk_ata_pass_through_parms *parms,
|
||||
int spinup)
|
||||
{
|
||||
struct grub_pci_dma_chunk *bufc;
|
||||
grub_uint64_t endtime;
|
||||
unsigned i;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
|
||||
grub_dprintf ("ahci", "AHCI tfd = %x\n",
|
||||
dev->hba->ports[dev->port].task_file_data);
|
||||
|
||||
if ((dev->hba->ports[dev->port].task_file_data & 0x80))
|
||||
{
|
||||
dev->hba->ports[dev->port].command &= ~GRUB_AHCI_HBA_PORT_CMD_ST;
|
||||
endtime = grub_get_time_ms () + 1000;
|
||||
while ((dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't stop CR\n");
|
||||
break;
|
||||
}
|
||||
dev->hba->ports[dev->port].command |= GRUB_AHCI_HBA_PORT_CMD_ST;
|
||||
endtime = grub_get_time_ms () + (spinup ? 10000 : 1000);
|
||||
while (!(dev->hba->ports[dev->port].command & GRUB_AHCI_HBA_PORT_CMD_CR))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "couldn't start CR\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dev->hba->ports[dev->port].sata_error = dev->hba->ports[dev->port].sata_error;
|
||||
|
||||
grub_dprintf("ahci", "grub_ahci_read (size=%llu, cmdsize = %llu)\n",
|
||||
(unsigned long long) parms->size,
|
||||
(unsigned long long) parms->cmdsize);
|
||||
|
||||
if (parms->cmdsize != 0 && parms->cmdsize != 12 && parms->cmdsize != 16)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "incorrect ATAPI command size");
|
||||
|
||||
if (parms->size > GRUB_AHCI_PRDT_MAX_CHUNK_LENGTH)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too big data buffer");
|
||||
|
||||
bufc = grub_memalign_dma32 (1024, parms->size + (parms->size & 1));
|
||||
|
||||
dev->hba->ports[dev->port].command |= 8;
|
||||
|
||||
grub_dprintf ("ahci", "AHCI tfd = %x\n",
|
||||
dev->hba->ports[dev->port].task_file_data);
|
||||
/* FIXME: support port multipliers. */
|
||||
dev->command_list[0].config
|
||||
= (5 << GRUB_AHCI_CONFIG_CFIS_LENGTH_SHIFT)
|
||||
// | GRUB_AHCI_CONFIG_CLEAR_R_OK
|
||||
| (0 << GRUB_AHCI_CONFIG_PMP_SHIFT)
|
||||
| (1 << GRUB_AHCI_CONFIG_PRDT_LENGTH_SHIFT)
|
||||
| (parms->cmdsize ? GRUB_AHCI_CONFIG_ATAPI : 0)
|
||||
| (parms->write ? GRUB_AHCI_CONFIG_WRITE : GRUB_AHCI_CONFIG_READ)
|
||||
| (parms->taskfile.cmd == 8 ? (1 << 8) : 0);
|
||||
dev->command_list[0].transfered = 0;
|
||||
dev->command_list[0].command_table_base
|
||||
= grub_dma_get_phys (dev->command_table_chunk);
|
||||
grub_memset ((char *) dev->command_list[0].unused, 0,
|
||||
sizeof (dev->command_list[0].unused));
|
||||
grub_memset ((char *) &dev->command_table[0], 0,
|
||||
sizeof (dev->command_table[0]));
|
||||
if (parms->cmdsize)
|
||||
grub_memcpy ((char *) dev->command_table[0].command, parms->cmd,
|
||||
parms->cmdsize);
|
||||
|
||||
dev->command_table[0].cfis[0] = GRUB_AHCI_FIS_REG_H2D;
|
||||
dev->command_table[0].cfis[1] = 0x80;
|
||||
for (i = 0; i < sizeof (parms->taskfile.raw); i++)
|
||||
dev->command_table[0].cfis[register_map[i]] = parms->taskfile.raw[i];
|
||||
|
||||
grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
dev->command_table[0].cfis[0], dev->command_table[0].cfis[1],
|
||||
dev->command_table[0].cfis[2], dev->command_table[0].cfis[3],
|
||||
dev->command_table[0].cfis[4], dev->command_table[0].cfis[5],
|
||||
dev->command_table[0].cfis[6], dev->command_table[0].cfis[7]);
|
||||
grub_dprintf ("ahci", "cfis: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
dev->command_table[0].cfis[8], dev->command_table[0].cfis[9],
|
||||
dev->command_table[0].cfis[10], dev->command_table[0].cfis[11],
|
||||
dev->command_table[0].cfis[12], dev->command_table[0].cfis[13],
|
||||
dev->command_table[0].cfis[14], dev->command_table[0].cfis[15]);
|
||||
|
||||
dev->command_table[0].prdt[0].data_base = grub_dma_get_phys (bufc);
|
||||
dev->command_table[0].prdt[0].unused = 0;
|
||||
dev->command_table[0].prdt[0].size = (parms->size + (parms->size & 1) - 1)
|
||||
| GRUB_AHCI_INTERRUPT_ON_COMPLETE;
|
||||
|
||||
grub_dprintf ("ahci", "PRDT = %" PRIxGRUB_UINT64_T ", %x, %x (%"
|
||||
PRIuGRUB_SIZE ")\n",
|
||||
dev->command_table[0].prdt[0].data_base,
|
||||
dev->command_table[0].prdt[0].unused,
|
||||
dev->command_table[0].prdt[0].size,
|
||||
(char *) &dev->command_table[0].prdt[0]
|
||||
- (char *) &dev->command_table[0]);
|
||||
|
||||
if (parms->write)
|
||||
grub_memcpy ((char *) grub_dma_get_virt (bufc), parms->buffer, parms->size);
|
||||
|
||||
grub_dprintf ("ahci", "AHCI command schedulded\n");
|
||||
grub_dprintf ("ahci", "AHCI tfd = %x\n",
|
||||
dev->hba->ports[dev->port].task_file_data);
|
||||
dev->hba->ports[dev->port].inten = 0xffffffff;//(1 << 2) | (1 << 5);
|
||||
dev->hba->ports[dev->port].intstatus = 0xffffffff;//(1 << 2) | (1 << 5);
|
||||
grub_dprintf ("ahci", "AHCI tfd = %x\n",
|
||||
dev->hba->ports[dev->port].task_file_data);
|
||||
dev->hba->ports[dev->port].command_issue |= 1;
|
||||
grub_dprintf ("ahci", "AHCI sig = %x\n", dev->hba->ports[dev->port].sig);
|
||||
grub_dprintf ("ahci", "AHCI tfd = %x\n",
|
||||
dev->hba->ports[dev->port].task_file_data);
|
||||
|
||||
endtime = grub_get_time_ms () + (spinup ? 10000 : 1000);
|
||||
while ((dev->hba->ports[dev->port].command_issue & 1))
|
||||
if (grub_get_time_ms () > endtime)
|
||||
{
|
||||
grub_dprintf ("ahci", "AHCI status <%x %x %x>\n",
|
||||
dev->hba->ports[dev->port].command_issue,
|
||||
dev->hba->ports[dev->port].intstatus,
|
||||
dev->hba->ports[dev->port].task_file_data);
|
||||
err = grub_error (GRUB_ERR_IO, "AHCI transfer timeouted");
|
||||
break;
|
||||
}
|
||||
|
||||
grub_dprintf ("ahci", "AHCI command completed <%x %x %x %x %x, %x %x>\n",
|
||||
dev->hba->ports[dev->port].command_issue,
|
||||
dev->hba->ports[dev->port].intstatus,
|
||||
dev->hba->ports[dev->port].task_file_data,
|
||||
dev->command_list[0].transfered,
|
||||
dev->hba->ports[dev->port].sata_error,
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x00],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x18]);
|
||||
grub_dprintf ("ahci",
|
||||
"last PIO FIS %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x08],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x09],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0a],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0b],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0c],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0d],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0e],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x0f]);
|
||||
grub_dprintf ("ahci",
|
||||
"last REG FIS %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x10],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x11],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x12],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x13],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x14],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x15],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x16],
|
||||
((grub_uint32_t *) grub_dma_get_virt (dev->rfis))[0x17]);
|
||||
|
||||
if (!parms->write)
|
||||
grub_memcpy (parms->buffer, (char *) grub_dma_get_virt (bufc), parms->size);
|
||||
grub_dma_free (bufc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_readwrite (grub_ata_t disk,
|
||||
struct grub_disk_ata_pass_through_parms *parms,
|
||||
int spinup)
|
||||
{
|
||||
return grub_ahci_readwrite_real (disk->data, parms, spinup);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_ahci_open (int id, int devnum, struct grub_ata *ata)
|
||||
{
|
||||
struct grub_ahci_device *dev;
|
||||
|
||||
if (id != GRUB_SCSI_SUBSYSTEM_AHCI)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an AHCI device");
|
||||
|
||||
FOR_LIST_ELEMENTS(dev, grub_ahci_devices)
|
||||
if (dev->num == devnum)
|
||||
break;
|
||||
|
||||
if (! dev)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such AHCI device");
|
||||
|
||||
grub_dprintf ("ahci", "opening AHCI dev `ahci%d'\n", dev->num);
|
||||
|
||||
ata->data = dev;
|
||||
ata->dma = 1;
|
||||
ata->present = &dev->present;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_ata_dev grub_ahci_dev =
|
||||
{
|
||||
.iterate = grub_ahci_iterate,
|
||||
.open = grub_ahci_open,
|
||||
.readwrite = grub_ahci_readwrite,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct grub_preboot *fini_hnd;
|
||||
|
||||
GRUB_MOD_INIT(ahci)
|
||||
{
|
||||
/* To prevent two drivers operating on the same disks. */
|
||||
grub_disk_firmware_is_tainted = 1;
|
||||
if (grub_disk_firmware_fini)
|
||||
{
|
||||
grub_disk_firmware_fini ();
|
||||
grub_disk_firmware_fini = NULL;
|
||||
}
|
||||
|
||||
/* AHCI initialization. */
|
||||
grub_ahci_initialize ();
|
||||
|
||||
/* AHCI devices are handled by scsi.mod. */
|
||||
grub_ata_dev_register (&grub_ahci_dev);
|
||||
|
||||
fini_hnd = grub_loader_register_preboot_hook (grub_ahci_fini_hw,
|
||||
grub_ahci_restore_hw,
|
||||
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(ahci)
|
||||
{
|
||||
grub_ahci_fini_hw (0);
|
||||
grub_loader_unregister_preboot_hook (fini_hnd);
|
||||
|
||||
grub_ata_dev_unregister (&grub_ahci_dev);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/* ofdisk.c - Open Firmware disk access. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2004,2006,2007,2008,2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2004,2006,2007,2008,2009,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -79,7 +79,8 @@ arcdisk_hash_add (char *devpath)
|
|||
|
||||
|
||||
static int
|
||||
grub_arcdisk_iterate (int (*hook_in) (const char *name))
|
||||
grub_arcdisk_iterate (int (*hook_in) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
auto int hook (const char *name, const struct grub_arc_component *comp);
|
||||
int hook (const char *name, const struct grub_arc_component *comp)
|
||||
|
@ -90,6 +91,9 @@ grub_arcdisk_iterate (int (*hook_in) (const char *name))
|
|||
return 0;
|
||||
return hook_in (name);
|
||||
}
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
return grub_arc_iterate_devs (hook, 1);
|
||||
}
|
||||
|
||||
|
@ -105,11 +109,6 @@ reopen (const char *name)
|
|||
grub_dprintf ("arcdisk", "using already opened %s\n", name);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (GRUB_ARC_FIRMWARE_VECTOR->open (name, 0, &handle))
|
||||
{
|
||||
grub_dprintf ("arcdisk", "couldn't open %s\n", name);
|
||||
return grub_error (GRUB_ERR_IO, "couldn't open %s", name);
|
||||
}
|
||||
if (last_path)
|
||||
{
|
||||
GRUB_ARC_FIRMWARE_VECTOR->close (last_handle);
|
||||
|
@ -117,6 +116,11 @@ reopen (const char *name)
|
|||
last_path = NULL;
|
||||
last_handle = 0;
|
||||
}
|
||||
if (GRUB_ARC_FIRMWARE_VECTOR->open (name, 0, &handle))
|
||||
{
|
||||
grub_dprintf ("arcdisk", "couldn't open %s\n", name);
|
||||
return grub_error (GRUB_ERR_IO, "couldn't open %s", name);
|
||||
}
|
||||
last_path = grub_strdup (name);
|
||||
if (!last_path)
|
||||
return grub_errno;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,108 +0,0 @@
|
|||
/* ata_pthru.c - ATA pass through for ata.mod. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/ata.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* ATA pass through support, used by hdparm.mod. */
|
||||
static grub_err_t
|
||||
grub_ata_pass_through (grub_disk_t disk,
|
||||
struct grub_disk_ata_pass_through_parms *parms)
|
||||
{
|
||||
if (disk->dev->id != GRUB_DISK_DEVICE_ATA_ID)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"device not accessed via ata.mod");
|
||||
|
||||
struct grub_ata_device *dev = (struct grub_ata_device *) disk->data;
|
||||
|
||||
if (! (parms->size == 0 || parms->size == GRUB_DISK_SECTOR_SIZE))
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"ATA multi-sector read and DATA OUT not implemented");
|
||||
|
||||
grub_dprintf ("ata", "ata_pass_through: cmd=0x%x, features=0x%x, sectors=0x%x\n",
|
||||
parms->taskfile[GRUB_ATA_REG_CMD],
|
||||
parms->taskfile[GRUB_ATA_REG_FEATURES],
|
||||
parms->taskfile[GRUB_ATA_REG_SECTORS]);
|
||||
grub_dprintf ("ata", "lba_high=0x%x, lba_mid=0x%x, lba_low=0x%x, size=%d\n",
|
||||
parms->taskfile[GRUB_ATA_REG_LBAHIGH],
|
||||
parms->taskfile[GRUB_ATA_REG_LBAMID],
|
||||
parms->taskfile[GRUB_ATA_REG_LBALOW], parms->size);
|
||||
|
||||
/* Set registers. */
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4
|
||||
| (parms->taskfile[GRUB_ATA_REG_DISK] & 0xf));
|
||||
if (grub_ata_check_ready (dev))
|
||||
return grub_errno;
|
||||
|
||||
int i;
|
||||
for (i = GRUB_ATA_REG_FEATURES; i <= GRUB_ATA_REG_LBAHIGH; i++)
|
||||
grub_ata_regset (dev, i, parms->taskfile[i]);
|
||||
|
||||
/* Start command. */
|
||||
grub_ata_regset (dev, GRUB_ATA_REG_CMD, parms->taskfile[GRUB_ATA_REG_CMD]);
|
||||
|
||||
/* Wait for !BSY. */
|
||||
if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
|
||||
return grub_errno;
|
||||
|
||||
/* Check status. */
|
||||
grub_int8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS);
|
||||
grub_dprintf ("ata", "status=0x%x\n", sts);
|
||||
|
||||
/* Transfer data. */
|
||||
if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_DRQ)
|
||||
{
|
||||
if (parms->size != GRUB_DISK_SECTOR_SIZE)
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "DRQ unexpected");
|
||||
grub_ata_pio_read (dev, parms->buffer, GRUB_DISK_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
/* Return registers. */
|
||||
for (i = GRUB_ATA_REG_ERROR; i <= GRUB_ATA_REG_STATUS; i++)
|
||||
parms->taskfile[i] = grub_ata_regget (dev, i);
|
||||
|
||||
grub_dprintf ("ata", "status=0x%x, error=0x%x, sectors=0x%x\n",
|
||||
parms->taskfile[GRUB_ATA_REG_STATUS],
|
||||
parms->taskfile[GRUB_ATA_REG_ERROR],
|
||||
parms->taskfile[GRUB_ATA_REG_SECTORS]);
|
||||
|
||||
if (parms->taskfile[GRUB_ATA_REG_STATUS]
|
||||
& (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "ATA passthrough failed");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GRUB_MOD_INIT(ata_pthru)
|
||||
{
|
||||
/* Register ATA pass through function. */
|
||||
grub_disk_ata_pass_through = grub_ata_pass_through;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(ata_pthru)
|
||||
{
|
||||
if (grub_disk_ata_pass_through == grub_ata_pass_through)
|
||||
grub_disk_ata_pass_through = NULL;
|
||||
}
|
883
grub-core/disk/cryptodisk.c
Normal file
883
grub-core/disk/cryptodisk.c
Normal file
|
@ -0,0 +1,883 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2007,2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/cryptodisk.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <grub/emu/hostdisk.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
grub_cryptodisk_dev_t grub_cryptodisk_list;
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
{
|
||||
{"uuid", 'u', 0, N_("Mount by UUID."), 0, 0},
|
||||
{"all", 'a', 0, N_("Mount all."), 0, 0},
|
||||
{"boot", 'b', 0, N_("Mount all volumes marked as boot."), 0, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
/* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */
|
||||
#define GF_POLYNOM 0x87
|
||||
static inline int GF_PER_SECTOR (const struct grub_cryptodisk *dev)
|
||||
{
|
||||
return 1U << (dev->log_sector_size - GRUB_CRYPTODISK_GF_LOG_BYTES);
|
||||
}
|
||||
|
||||
static grub_cryptodisk_t cryptodisk_list = NULL;
|
||||
static grub_uint8_t n = 0;
|
||||
|
||||
static void
|
||||
gf_mul_x (grub_uint8_t *g)
|
||||
{
|
||||
int over = 0, over2 = 0;
|
||||
unsigned j;
|
||||
|
||||
for (j = 0; j < GRUB_CRYPTODISK_GF_BYTES; j++)
|
||||
{
|
||||
over2 = !!(g[j] & 0x80);
|
||||
g[j] <<= 1;
|
||||
g[j] |= over;
|
||||
over = over2;
|
||||
}
|
||||
if (over)
|
||||
g[0] ^= GF_POLYNOM;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gf_mul_x_be (grub_uint8_t *g)
|
||||
{
|
||||
int over = 0, over2 = 0;
|
||||
int j;
|
||||
|
||||
for (j = (int) GRUB_CRYPTODISK_GF_BYTES - 1; j >= 0; j--)
|
||||
{
|
||||
over2 = !!(g[j] & 0x80);
|
||||
g[j] <<= 1;
|
||||
g[j] |= over;
|
||||
over = over2;
|
||||
}
|
||||
if (over)
|
||||
g[GRUB_CRYPTODISK_GF_BYTES - 1] ^= GF_POLYNOM;
|
||||
}
|
||||
|
||||
static void
|
||||
gf_mul_be (grub_uint8_t *o, const grub_uint8_t *a, const grub_uint8_t *b)
|
||||
{
|
||||
unsigned i;
|
||||
grub_uint8_t t[GRUB_CRYPTODISK_GF_BYTES];
|
||||
grub_memset (o, 0, GRUB_CRYPTODISK_GF_BYTES);
|
||||
grub_memcpy (t, b, GRUB_CRYPTODISK_GF_BYTES);
|
||||
for (i = 0; i < GRUB_CRYPTODISK_GF_SIZE; i++)
|
||||
{
|
||||
if (((a[GRUB_CRYPTODISK_GF_BYTES - i / 8 - 1] >> (i % 8))) & 1)
|
||||
grub_crypto_xor (o, o, t, GRUB_CRYPTODISK_GF_BYTES);
|
||||
gf_mul_x_be (t);
|
||||
}
|
||||
}
|
||||
|
||||
static gcry_err_code_t
|
||||
grub_crypto_pcbc_decrypt (grub_crypto_cipher_handle_t cipher,
|
||||
void *out, void *in, grub_size_t size,
|
||||
void *iv)
|
||||
{
|
||||
grub_uint8_t *inptr, *outptr, *end;
|
||||
grub_uint8_t ivt[cipher->cipher->blocksize];
|
||||
if (!cipher->cipher->decrypt)
|
||||
return GPG_ERR_NOT_SUPPORTED;
|
||||
if (size % cipher->cipher->blocksize != 0)
|
||||
return GPG_ERR_INV_ARG;
|
||||
end = (grub_uint8_t *) in + size;
|
||||
for (inptr = in, outptr = out; inptr < end;
|
||||
inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
|
||||
{
|
||||
grub_memcpy (ivt, inptr, cipher->cipher->blocksize);
|
||||
cipher->cipher->decrypt (cipher->ctx, outptr, inptr);
|
||||
grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize);
|
||||
grub_crypto_xor (iv, ivt, outptr, cipher->cipher->blocksize);
|
||||
}
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
struct lrw_sector
|
||||
{
|
||||
grub_uint8_t low[GRUB_CRYPTODISK_GF_BYTES];
|
||||
grub_uint8_t high[GRUB_CRYPTODISK_GF_BYTES];
|
||||
grub_uint8_t low_byte, low_byte_c;
|
||||
};
|
||||
|
||||
static void
|
||||
generate_lrw_sector (struct lrw_sector *sec,
|
||||
const struct grub_cryptodisk *dev,
|
||||
const grub_uint8_t *iv)
|
||||
{
|
||||
grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES];
|
||||
grub_uint16_t c;
|
||||
int j;
|
||||
grub_memcpy (idx, iv, GRUB_CRYPTODISK_GF_BYTES);
|
||||
sec->low_byte = (idx[GRUB_CRYPTODISK_GF_BYTES - 1]
|
||||
& (GF_PER_SECTOR (dev) - 1));
|
||||
sec->low_byte_c = (((GF_PER_SECTOR (dev) - 1) & ~sec->low_byte) + 1);
|
||||
idx[GRUB_CRYPTODISK_GF_BYTES - 1] &= ~(GF_PER_SECTOR (dev) - 1);
|
||||
gf_mul_be (sec->low, dev->lrw_key, idx);
|
||||
if (!sec->low_byte)
|
||||
return;
|
||||
|
||||
c = idx[GRUB_CRYPTODISK_GF_BYTES - 1] + GF_PER_SECTOR (dev);
|
||||
if (c & 0x100)
|
||||
{
|
||||
for (j = GRUB_CRYPTODISK_GF_BYTES - 2; j >= 0; j--)
|
||||
{
|
||||
idx[j]++;
|
||||
if (idx[j] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
idx[GRUB_CRYPTODISK_GF_BYTES - 1] = c;
|
||||
gf_mul_be (sec->high, dev->lrw_key, idx);
|
||||
}
|
||||
|
||||
static void __attribute__ ((unused))
|
||||
lrw_xor (const struct lrw_sector *sec,
|
||||
const struct grub_cryptodisk *dev,
|
||||
grub_uint8_t *b)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES;
|
||||
i += GRUB_CRYPTODISK_GF_BYTES)
|
||||
grub_crypto_xor (b + i, b + i, sec->low, GRUB_CRYPTODISK_GF_BYTES);
|
||||
grub_crypto_xor (b, b, dev->lrw_precalc + GRUB_CRYPTODISK_GF_BYTES * sec->low_byte,
|
||||
sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES);
|
||||
if (!sec->low_byte)
|
||||
return;
|
||||
|
||||
for (i = sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES;
|
||||
i < (1U << dev->log_sector_size); i += GRUB_CRYPTODISK_GF_BYTES)
|
||||
grub_crypto_xor (b + i, b + i, sec->high, GRUB_CRYPTODISK_GF_BYTES);
|
||||
grub_crypto_xor (b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES,
|
||||
b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES,
|
||||
dev->lrw_precalc, sec->low_byte * GRUB_CRYPTODISK_GF_BYTES);
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||
grub_uint8_t * data, grub_size_t len,
|
||||
grub_disk_addr_t sector)
|
||||
{
|
||||
grub_size_t i;
|
||||
gcry_err_code_t err;
|
||||
|
||||
/* The only mode without IV. */
|
||||
if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey)
|
||||
return grub_crypto_ecb_decrypt (dev->cipher, data, data, len);
|
||||
|
||||
for (i = 0; i < len; i += (1U << dev->log_sector_size))
|
||||
{
|
||||
grub_size_t sz = ((dev->cipher->cipher->blocksize
|
||||
+ sizeof (grub_uint32_t) - 1)
|
||||
/ sizeof (grub_uint32_t));
|
||||
grub_uint32_t iv[sz];
|
||||
|
||||
if (dev->rekey)
|
||||
{
|
||||
grub_uint64_t zone = sector >> dev->rekey_shift;
|
||||
if (zone != dev->last_rekey)
|
||||
{
|
||||
err = dev->rekey (dev, zone);
|
||||
if (err)
|
||||
return err;
|
||||
dev->last_rekey = zone;
|
||||
}
|
||||
}
|
||||
|
||||
grub_memset (iv, 0, sz * sizeof (iv[0]));
|
||||
switch (dev->mode_iv)
|
||||
{
|
||||
case GRUB_CRYPTODISK_MODE_IV_NULL:
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH:
|
||||
{
|
||||
grub_uint64_t tmp;
|
||||
grub_uint64_t ctx[(dev->iv_hash->contextsize + 7) / 8];
|
||||
|
||||
grub_memset (ctx, 0, sizeof (ctx));
|
||||
|
||||
tmp = grub_cpu_to_le64 (sector << dev->log_sector_size);
|
||||
dev->iv_hash->init (ctx);
|
||||
dev->iv_hash->write (ctx, dev->iv_prefix, dev->iv_prefix_len);
|
||||
dev->iv_hash->write (ctx, &tmp, sizeof (tmp));
|
||||
dev->iv_hash->final (ctx);
|
||||
|
||||
grub_memcpy (iv, dev->iv_hash->read (ctx), sizeof (iv));
|
||||
}
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_IV_PLAIN64:
|
||||
iv[1] = grub_cpu_to_le32 (sector >> 32);
|
||||
case GRUB_CRYPTODISK_MODE_IV_PLAIN:
|
||||
iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF);
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64:
|
||||
iv[1] = grub_cpu_to_le32 (sector >> (32 - dev->log_sector_size));
|
||||
iv[0] = grub_cpu_to_le32 ((sector << dev->log_sector_size)
|
||||
& 0xFFFFFFFF);
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_IV_BENBI:
|
||||
{
|
||||
grub_uint64_t num = (sector << dev->benbi_log) + 1;
|
||||
iv[sz - 2] = grub_cpu_to_be32 (num >> 32);
|
||||
iv[sz - 1] = grub_cpu_to_be32 (num & 0xFFFFFFFF);
|
||||
}
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_IV_ESSIV:
|
||||
iv[0] = grub_cpu_to_le32 (sector & 0xFFFFFFFF);
|
||||
err = grub_crypto_ecb_encrypt (dev->essiv_cipher, iv, iv,
|
||||
dev->cipher->cipher->blocksize);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (dev->mode)
|
||||
{
|
||||
case GRUB_CRYPTODISK_MODE_CBC:
|
||||
err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i,
|
||||
(1U << dev->log_sector_size), iv);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
|
||||
case GRUB_CRYPTODISK_MODE_PCBC:
|
||||
err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i,
|
||||
(1U << dev->log_sector_size), iv);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_XTS:
|
||||
{
|
||||
unsigned j;
|
||||
err = grub_crypto_ecb_encrypt (dev->secondary_cipher, iv, iv,
|
||||
dev->cipher->cipher->blocksize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (j = 0; j < (1U << dev->log_sector_size);
|
||||
j += dev->cipher->cipher->blocksize)
|
||||
{
|
||||
grub_crypto_xor (data + i + j, data + i + j, iv,
|
||||
dev->cipher->cipher->blocksize);
|
||||
err = grub_crypto_ecb_decrypt (dev->cipher, data + i + j,
|
||||
data + i + j,
|
||||
dev->cipher->cipher->blocksize);
|
||||
if (err)
|
||||
return err;
|
||||
grub_crypto_xor (data + i + j, data + i + j, iv,
|
||||
dev->cipher->cipher->blocksize);
|
||||
gf_mul_x ((grub_uint8_t *) iv);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_LRW:
|
||||
{
|
||||
struct lrw_sector sec;
|
||||
|
||||
generate_lrw_sector (&sec, dev, (grub_uint8_t *) iv);
|
||||
lrw_xor (&sec, dev, data + i);
|
||||
|
||||
err = grub_crypto_ecb_decrypt (dev->cipher, data + i,
|
||||
data + i,
|
||||
(1U << dev->log_sector_size));
|
||||
if (err)
|
||||
return err;
|
||||
lrw_xor (&sec, dev, data + i);
|
||||
}
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_ECB:
|
||||
grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i,
|
||||
(1U << dev->log_sector_size));
|
||||
break;
|
||||
default:
|
||||
return GPG_ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
sector++;
|
||||
}
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t keysize)
|
||||
{
|
||||
gcry_err_code_t err;
|
||||
int real_keysize;
|
||||
|
||||
real_keysize = keysize;
|
||||
if (dev->mode == GRUB_CRYPTODISK_MODE_XTS)
|
||||
real_keysize /= 2;
|
||||
if (dev->mode == GRUB_CRYPTODISK_MODE_LRW)
|
||||
real_keysize -= dev->cipher->cipher->blocksize;
|
||||
|
||||
/* Set the PBKDF2 output as the cipher key. */
|
||||
err = grub_crypto_cipher_set_key (dev->cipher, key, real_keysize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Configure ESSIV if necessary. */
|
||||
if (dev->mode_iv == GRUB_CRYPTODISK_MODE_IV_ESSIV)
|
||||
{
|
||||
grub_size_t essiv_keysize = dev->essiv_hash->mdlen;
|
||||
grub_uint8_t hashed_key[essiv_keysize];
|
||||
|
||||
grub_crypto_hash (dev->essiv_hash, hashed_key, key, keysize);
|
||||
err = grub_crypto_cipher_set_key (dev->essiv_cipher,
|
||||
hashed_key, essiv_keysize);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (dev->mode == GRUB_CRYPTODISK_MODE_XTS)
|
||||
{
|
||||
err = grub_crypto_cipher_set_key (dev->secondary_cipher,
|
||||
key + real_keysize,
|
||||
keysize / 2);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (dev->mode == GRUB_CRYPTODISK_MODE_LRW)
|
||||
{
|
||||
unsigned i;
|
||||
grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES];
|
||||
|
||||
grub_free (dev->lrw_precalc);
|
||||
grub_memcpy (dev->lrw_key, key + real_keysize,
|
||||
dev->cipher->cipher->blocksize);
|
||||
dev->lrw_precalc = grub_malloc ((1U << dev->log_sector_size));
|
||||
if (!dev->lrw_precalc)
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
grub_memset (idx, 0, GRUB_CRYPTODISK_GF_BYTES);
|
||||
for (i = 0; i < (1U << dev->log_sector_size);
|
||||
i += GRUB_CRYPTODISK_GF_BYTES)
|
||||
{
|
||||
idx[GRUB_CRYPTODISK_GF_BYTES - 1] = i / GRUB_CRYPTODISK_GF_BYTES;
|
||||
gf_mul_be (dev->lrw_precalc + i, idx, dev->lrw_key);
|
||||
}
|
||||
}
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_cryptodisk_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
grub_cryptodisk_t i;
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
for (i = cryptodisk_list; i != NULL; i = i->next)
|
||||
{
|
||||
char buf[30];
|
||||
grub_snprintf (buf, sizeof (buf), "crypto%lu", i->id);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cryptodisk_open (const char *name, grub_disk_t disk)
|
||||
{
|
||||
grub_cryptodisk_t dev;
|
||||
|
||||
if (grub_memcmp (name, "crypto", sizeof ("crypto") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
|
||||
|
||||
if (grub_memcmp (name, "cryptouuid/", sizeof ("cryptouuid/") - 1) == 0)
|
||||
{
|
||||
for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
|
||||
if (grub_strcasecmp (name + sizeof ("cryptouuid/") - 1, dev->uuid) == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long id = grub_strtoul (name + sizeof ("crypto") - 1, 0, 0);
|
||||
if (grub_errno)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
|
||||
/* Search for requested device in the list of CRYPTODISK devices. */
|
||||
for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
|
||||
if (dev->id == id)
|
||||
break;
|
||||
}
|
||||
if (!dev)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
|
||||
|
||||
disk->log_sector_size = dev->log_sector_size;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
if (dev->cheat)
|
||||
{
|
||||
if (dev->cheat_fd == -1)
|
||||
dev->cheat_fd = open (dev->cheat, O_RDONLY);
|
||||
if (dev->cheat_fd == -1)
|
||||
return grub_error (GRUB_ERR_IO, "couldn't open %s: %s",
|
||||
dev->cheat, strerror (errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!dev->source_disk)
|
||||
{
|
||||
grub_dprintf ("cryptodisk", "Opening device %s\n", name);
|
||||
/* Try to open the source disk and populate the requested disk. */
|
||||
dev->source_disk = grub_disk_open (dev->source);
|
||||
if (!dev->source_disk)
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
disk->data = dev;
|
||||
disk->total_sectors = dev->total_length;
|
||||
disk->id = dev->id;
|
||||
dev->ref++;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_cryptodisk_close (grub_disk_t disk)
|
||||
{
|
||||
grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
|
||||
grub_dprintf ("cryptodisk", "Closing disk\n");
|
||||
|
||||
dev->ref--;
|
||||
|
||||
if (dev->ref != 0)
|
||||
return;
|
||||
#ifdef GRUB_UTIL
|
||||
if (dev->cheat)
|
||||
{
|
||||
close (dev->cheat_fd);
|
||||
dev->cheat_fd = -1;
|
||||
}
|
||||
#endif
|
||||
grub_disk_close (dev->source_disk);
|
||||
dev->source_disk = NULL;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cryptodisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
|
||||
grub_err_t err;
|
||||
gcry_err_code_t gcry_err;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
if (dev->cheat)
|
||||
{
|
||||
err = grub_util_fd_seek (dev->cheat_fd, dev->cheat,
|
||||
sector << disk->log_sector_size);
|
||||
if (err)
|
||||
return err;
|
||||
if (grub_util_fd_read (dev->cheat_fd, buf, size << disk->log_sector_size)
|
||||
!= (ssize_t) (size << disk->log_sector_size))
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'",
|
||||
dev->cheat);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
grub_dprintf ("cryptodisk",
|
||||
"Reading %" PRIuGRUB_SIZE " sectors from sector 0x%"
|
||||
PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT64_T "\n",
|
||||
size, sector, dev->offset);
|
||||
|
||||
err = grub_disk_read (dev->source_disk,
|
||||
(sector << (disk->log_sector_size
|
||||
- GRUB_DISK_SECTOR_BITS)) + dev->offset, 0,
|
||||
size << disk->log_sector_size, buf);
|
||||
if (err)
|
||||
{
|
||||
grub_dprintf ("cryptodisk", "grub_disk_read failed with error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
gcry_err = grub_cryptodisk_decrypt (dev, (grub_uint8_t *) buf,
|
||||
size << disk->log_sector_size,
|
||||
sector);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cryptodisk_write (grub_disk_t disk __attribute ((unused)),
|
||||
grub_disk_addr_t sector __attribute ((unused)),
|
||||
grub_size_t size __attribute ((unused)),
|
||||
const char *buf __attribute ((unused)))
|
||||
{
|
||||
return GRUB_ERR_NOT_IMPLEMENTED_YET;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
static grub_disk_memberlist_t
|
||||
grub_cryptodisk_memberlist (grub_disk_t disk)
|
||||
{
|
||||
grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
|
||||
grub_disk_memberlist_t list = NULL;
|
||||
|
||||
list = grub_malloc (sizeof (*list));
|
||||
if (list)
|
||||
{
|
||||
list->disk = dev->source_disk;
|
||||
list->next = NULL;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
cryptodisk_cleanup (void)
|
||||
{
|
||||
grub_cryptodisk_t dev = cryptodisk_list;
|
||||
grub_cryptodisk_t tmp;
|
||||
|
||||
while (dev != NULL)
|
||||
{
|
||||
grub_free (dev->source);
|
||||
grub_free (dev->cipher);
|
||||
grub_free (dev->secondary_cipher);
|
||||
grub_free (dev->essiv_cipher);
|
||||
tmp = dev->next;
|
||||
grub_free (dev);
|
||||
dev = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_cryptodisk_insert (grub_cryptodisk_t newdev, const char *name,
|
||||
grub_disk_t source)
|
||||
{
|
||||
newdev->source = grub_strdup (name);
|
||||
if (!newdev->source)
|
||||
{
|
||||
grub_free (newdev);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
newdev->id = n++;
|
||||
newdev->source_id = source->id;
|
||||
newdev->source_dev_id = source->dev->id;
|
||||
newdev->next = cryptodisk_list;
|
||||
cryptodisk_list = newdev;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_cryptodisk_t
|
||||
grub_cryptodisk_get_by_uuid (const char *uuid)
|
||||
{
|
||||
grub_cryptodisk_t dev;
|
||||
for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
|
||||
if (grub_strcasecmp (dev->uuid, uuid) == 0)
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_cryptodisk_t
|
||||
grub_cryptodisk_get_by_source_disk (grub_disk_t disk)
|
||||
{
|
||||
grub_cryptodisk_t dev;
|
||||
for (dev = cryptodisk_list; dev != NULL; dev = dev->next)
|
||||
if (dev->source_id == disk->id && dev->source_dev_id == disk->dev->id)
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
grub_err_t
|
||||
grub_cryptodisk_cheat_insert (grub_cryptodisk_t newdev, const char *name,
|
||||
grub_disk_t source, const char *cheat)
|
||||
{
|
||||
newdev->cheat = grub_strdup (cheat);
|
||||
newdev->source = grub_strdup (name);
|
||||
if (!newdev->source || !newdev->cheat)
|
||||
{
|
||||
grub_free (newdev->source);
|
||||
grub_free (newdev->cheat);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
newdev->cheat_fd = -1;
|
||||
newdev->source_id = source->id;
|
||||
newdev->source_dev_id = source->dev->id;
|
||||
newdev->id = n++;
|
||||
newdev->next = cryptodisk_list;
|
||||
cryptodisk_list = newdev;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
grub_util_cryptodisk_print_abstraction (grub_disk_t disk)
|
||||
{
|
||||
grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
|
||||
|
||||
grub_printf ("cryptodisk %s ", dev->modname);
|
||||
|
||||
if (dev->cipher)
|
||||
grub_printf ("%s ", dev->cipher->cipher->modname);
|
||||
if (dev->secondary_cipher)
|
||||
grub_printf ("%s ", dev->secondary_cipher->cipher->modname);
|
||||
if (dev->essiv_cipher)
|
||||
grub_printf ("%s ", dev->essiv_cipher->cipher->modname);
|
||||
if (dev->hash)
|
||||
grub_printf ("%s ", dev->hash->modname);
|
||||
if (dev->essiv_hash)
|
||||
grub_printf ("%s ", dev->essiv_hash->modname);
|
||||
if (dev->iv_hash)
|
||||
grub_printf ("%s ", dev->iv_hash->modname);
|
||||
}
|
||||
|
||||
void
|
||||
grub_util_cryptodisk_print_uuid (grub_disk_t disk)
|
||||
{
|
||||
grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
|
||||
grub_printf ("%s ", dev->uuid);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int check_boot, have_it;
|
||||
static char *search_uuid;
|
||||
|
||||
static void
|
||||
cryptodisk_close (grub_cryptodisk_t dev)
|
||||
{
|
||||
grub_crypto_cipher_close (dev->cipher);
|
||||
grub_crypto_cipher_close (dev->secondary_cipher);
|
||||
grub_crypto_cipher_close (dev->essiv_cipher);
|
||||
grub_free (dev);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_cryptodisk_t dev;
|
||||
grub_cryptodisk_dev_t cr;
|
||||
|
||||
dev = grub_cryptodisk_get_by_source_disk (source);
|
||||
|
||||
if (dev)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
FOR_CRYPTODISK_DEVS (cr)
|
||||
{
|
||||
dev = cr->scan (source, search_uuid, check_boot);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
if (!dev)
|
||||
continue;
|
||||
|
||||
err = cr->recover_key (source, dev);
|
||||
if (err)
|
||||
{
|
||||
cryptodisk_close (dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
grub_cryptodisk_insert (dev, name, source);
|
||||
|
||||
have_it = 1;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
#include <grub/util/misc.h>
|
||||
grub_err_t
|
||||
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_cryptodisk_t dev;
|
||||
grub_cryptodisk_dev_t cr;
|
||||
grub_disk_t source;
|
||||
|
||||
/* Try to open disk. */
|
||||
source = grub_disk_open (sourcedev);
|
||||
if (!source)
|
||||
return grub_errno;
|
||||
|
||||
dev = grub_cryptodisk_get_by_source_disk (source);
|
||||
|
||||
if (dev)
|
||||
{
|
||||
grub_disk_close (source);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
FOR_CRYPTODISK_DEVS (cr)
|
||||
{
|
||||
dev = cr->scan (source, search_uuid, check_boot);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
if (!dev)
|
||||
continue;
|
||||
|
||||
grub_util_info ("cheatmounted %s (%s) at %s", sourcedev, dev->modname,
|
||||
cheat);
|
||||
err = grub_cryptodisk_cheat_insert (dev, sourcedev, source, cheat);
|
||||
grub_disk_close (source);
|
||||
if (err)
|
||||
grub_free (dev);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_disk_close (source);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
grub_cryptodisk_scan_device (const char *name)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_disk_t source;
|
||||
|
||||
/* Try to open disk. */
|
||||
source = grub_disk_open (name);
|
||||
if (!source)
|
||||
return grub_errno;
|
||||
|
||||
err = grub_cryptodisk_scan_device_real (name, source);
|
||||
|
||||
grub_disk_close (source);
|
||||
|
||||
if (err)
|
||||
grub_print_error ();
|
||||
return have_it && search_uuid ? 1 : 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
|
||||
if (argc < 1 && !state[1].set && !state[2].set)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
|
||||
|
||||
have_it = 0;
|
||||
if (state[0].set)
|
||||
{
|
||||
grub_cryptodisk_t dev;
|
||||
|
||||
dev = grub_cryptodisk_get_by_uuid (args[0]);
|
||||
if (dev)
|
||||
{
|
||||
grub_dprintf ("cryptodisk",
|
||||
"already mounted as crypto%lu\n", dev->id);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
check_boot = state[2].set;
|
||||
search_uuid = args[0];
|
||||
grub_device_iterate (&grub_cryptodisk_scan_device);
|
||||
search_uuid = NULL;
|
||||
|
||||
if (!have_it)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found");
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
else if (state[1].set || (argc == 0 && state[2].set))
|
||||
{
|
||||
search_uuid = NULL;
|
||||
check_boot = state[2].set;
|
||||
grub_device_iterate (&grub_cryptodisk_scan_device);
|
||||
search_uuid = NULL;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_disk_t disk;
|
||||
grub_cryptodisk_t dev;
|
||||
|
||||
search_uuid = NULL;
|
||||
check_boot = state[2].set;
|
||||
disk = grub_disk_open (args[0]);
|
||||
if (!disk)
|
||||
return grub_errno;
|
||||
|
||||
dev = grub_cryptodisk_get_by_source_disk (disk);
|
||||
if (dev)
|
||||
{
|
||||
grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id);
|
||||
grub_disk_close (disk);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
err = grub_cryptodisk_scan_device_real (args[0], disk);
|
||||
|
||||
grub_disk_close (disk);
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_cryptodisk_dev = {
|
||||
.name = "cryptodisk",
|
||||
.id = GRUB_DISK_DEVICE_CRYPTODISK_ID,
|
||||
.iterate = grub_cryptodisk_iterate,
|
||||
.open = grub_cryptodisk_open,
|
||||
.close = grub_cryptodisk_close,
|
||||
.read = grub_cryptodisk_read,
|
||||
.write = grub_cryptodisk_write,
|
||||
#ifdef GRUB_UTIL
|
||||
.memberlist = grub_cryptodisk_memberlist,
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
static grub_extcmd_t cmd;
|
||||
|
||||
GRUB_MOD_INIT (cryptodisk)
|
||||
{
|
||||
grub_disk_dev_register (&grub_cryptodisk_dev);
|
||||
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
|
||||
N_("SOURCE|-u UUID|-a|-b"),
|
||||
N_("Mount a crypto device."), options);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (cryptodisk)
|
||||
{
|
||||
grub_disk_dev_unregister (&grub_cryptodisk_dev);
|
||||
cryptodisk_cleanup ();
|
||||
}
|
|
@ -33,12 +33,10 @@ struct grub_efidisk_data
|
|||
grub_efi_device_path_t *device_path;
|
||||
grub_efi_device_path_t *last_device_path;
|
||||
grub_efi_block_io_t *block_io;
|
||||
grub_efi_disk_io_t *disk_io;
|
||||
struct grub_efidisk_data *next;
|
||||
};
|
||||
|
||||
/* GUIDs. */
|
||||
static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID;
|
||||
/* GUID. */
|
||||
static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
|
||||
|
||||
static struct grub_efidisk_data *fd_devices;
|
||||
|
@ -86,54 +84,6 @@ find_last_device_path (const grub_efi_device_path_t *dp)
|
|||
return p;
|
||||
}
|
||||
|
||||
/* Compare device paths. */
|
||||
static int
|
||||
compare_device_paths (const grub_efi_device_path_t *dp1,
|
||||
const grub_efi_device_path_t *dp2)
|
||||
{
|
||||
if (! dp1 || ! dp2)
|
||||
/* Return non-zero. */
|
||||
return 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_efi_uint8_t type1, type2;
|
||||
grub_efi_uint8_t subtype1, subtype2;
|
||||
grub_efi_uint16_t len1, len2;
|
||||
int ret;
|
||||
|
||||
type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
|
||||
type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
|
||||
|
||||
if (type1 != type2)
|
||||
return (int) type2 - (int) type1;
|
||||
|
||||
subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
|
||||
subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
|
||||
|
||||
if (subtype1 != subtype2)
|
||||
return (int) subtype1 - (int) subtype2;
|
||||
|
||||
len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
|
||||
len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
|
||||
|
||||
if (len1 != len2)
|
||||
return (int) len1 - (int) len2;
|
||||
|
||||
ret = grub_memcmp (dp1, dp2, len1);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
|
||||
break;
|
||||
|
||||
dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
|
||||
dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct grub_efidisk_data *
|
||||
make_devices (void)
|
||||
{
|
||||
|
@ -143,7 +93,7 @@ make_devices (void)
|
|||
struct grub_efidisk_data *devices = 0;
|
||||
|
||||
/* Find handles which support the disk io interface. */
|
||||
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_guid,
|
||||
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_guid,
|
||||
0, &num_handles);
|
||||
if (! handles)
|
||||
return 0;
|
||||
|
@ -155,7 +105,6 @@ make_devices (void)
|
|||
grub_efi_device_path_t *ldp;
|
||||
struct grub_efidisk_data *d;
|
||||
grub_efi_block_io_t *bio;
|
||||
grub_efi_disk_io_t *dio;
|
||||
|
||||
dp = grub_efi_get_device_path (*handle);
|
||||
if (! dp)
|
||||
|
@ -168,9 +117,7 @@ make_devices (void)
|
|||
|
||||
bio = grub_efi_open_protocol (*handle, &block_io_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
dio = grub_efi_open_protocol (*handle, &disk_io_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (! bio || ! dio)
|
||||
if (! bio)
|
||||
/* This should not happen... Why? */
|
||||
continue;
|
||||
|
||||
|
@ -186,7 +133,6 @@ make_devices (void)
|
|||
d->device_path = dp;
|
||||
d->last_device_path = ldp;
|
||||
d->block_io = bio;
|
||||
d->disk_io = dio;
|
||||
d->next = devices;
|
||||
devices = d;
|
||||
}
|
||||
|
@ -220,7 +166,7 @@ find_parent_device (struct grub_efidisk_data *devices,
|
|||
if (parent == d)
|
||||
continue;
|
||||
|
||||
if (compare_device_paths (parent->device_path, dp) == 0)
|
||||
if (grub_efi_compare_device_paths (parent->device_path, dp) == 0)
|
||||
{
|
||||
/* Found. */
|
||||
if (! parent->last_device_path)
|
||||
|
@ -255,7 +201,7 @@ iterate_child_devices (struct grub_efidisk_data *devices,
|
|||
ldp->length[0] = sizeof (*ldp);
|
||||
ldp->length[1] = 0;
|
||||
|
||||
if (compare_device_paths (dp, d->device_path) == 0)
|
||||
if (grub_efi_compare_device_paths (dp, d->device_path) == 0)
|
||||
if (hook (p))
|
||||
{
|
||||
grub_free (dp);
|
||||
|
@ -279,11 +225,11 @@ add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = compare_device_paths (find_last_device_path ((*p)->device_path),
|
||||
find_last_device_path (d->device_path));
|
||||
ret = grub_efi_compare_device_paths (find_last_device_path ((*p)->device_path),
|
||||
find_last_device_path (d->device_path));
|
||||
if (ret == 0)
|
||||
ret = compare_device_paths ((*p)->device_path,
|
||||
d->device_path);
|
||||
ret = grub_efi_compare_device_paths ((*p)->device_path,
|
||||
d->device_path);
|
||||
if (ret == 0)
|
||||
return;
|
||||
else if (ret > 0)
|
||||
|
@ -432,34 +378,43 @@ enumerate_disks (void)
|
|||
}
|
||||
|
||||
static int
|
||||
grub_efidisk_iterate (int (*hook) (const char *name))
|
||||
grub_efidisk_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_efidisk_data *d;
|
||||
char buf[16];
|
||||
int count;
|
||||
|
||||
for (d = fd_devices, count = 0; d; d = d->next, count++)
|
||||
switch (pull)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "fd%d", count);
|
||||
grub_dprintf ("efidisk", "iterating %s\n", buf);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
}
|
||||
case GRUB_DISK_PULL_NONE:
|
||||
for (d = hd_devices, count = 0; d; d = d->next, count++)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "hd%d", count);
|
||||
grub_dprintf ("efidisk", "iterating %s\n", buf);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case GRUB_DISK_PULL_REMOVABLE:
|
||||
for (d = fd_devices, count = 0; d; d = d->next, count++)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "fd%d", count);
|
||||
grub_dprintf ("efidisk", "iterating %s\n", buf);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (d = hd_devices, count = 0; d; d = d->next, count++)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "hd%d", count);
|
||||
grub_dprintf ("efidisk", "iterating %s\n", buf);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (d = cd_devices, count = 0; d; d = d->next, count++)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "cd%d", count);
|
||||
grub_dprintf ("efidisk", "iterating %s\n", buf);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
for (d = cd_devices, count = 0; d; d = d->next, count++)
|
||||
{
|
||||
grub_snprintf (buf, sizeof (buf), "cd%d", count);
|
||||
grub_dprintf ("efidisk", "iterating %s\n", buf);
|
||||
if (hook (buf))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -536,8 +491,13 @@ grub_efidisk_open (const char *name, struct grub_disk *disk)
|
|||
and total sectors should be replaced with total blocks. */
|
||||
grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n",
|
||||
m, (unsigned long long) m->last_block, m->block_size);
|
||||
disk->total_sectors = (m->last_block
|
||||
* (m->block_size >> GRUB_DISK_SECTOR_BITS));
|
||||
disk->total_sectors = m->last_block + 1;
|
||||
if (m->block_size & (m->block_size - 1) || !m->block_size)
|
||||
return grub_error (GRUB_ERR_IO, "invalid sector size %d",
|
||||
m->block_size);
|
||||
for (disk->log_sector_size = 0;
|
||||
(1U << disk->log_sector_size) < m->block_size;
|
||||
disk->log_sector_size++);
|
||||
disk->data = d;
|
||||
|
||||
grub_dprintf ("efidisk", "opening %s succeeded\n", name);
|
||||
|
@ -558,22 +518,20 @@ grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
|
|||
{
|
||||
/* For now, use the disk io interface rather than the block io's. */
|
||||
struct grub_efidisk_data *d;
|
||||
grub_efi_disk_io_t *dio;
|
||||
grub_efi_block_io_t *bio;
|
||||
grub_efi_status_t status;
|
||||
|
||||
d = disk->data;
|
||||
dio = d->disk_io;
|
||||
bio = d->block_io;
|
||||
|
||||
grub_dprintf ("efidisk",
|
||||
"reading 0x%lx sectors at the sector 0x%llx from %s\n",
|
||||
(unsigned long) size, (unsigned long long) sector, disk->name);
|
||||
|
||||
status = efi_call_5 (dio->read, dio, bio->media->media_id,
|
||||
(grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
|
||||
(grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
|
||||
buf);
|
||||
status = efi_call_5 (bio->read_blocks, bio, bio->media->media_id,
|
||||
(grub_efi_uint64_t) sector,
|
||||
(grub_efi_uintn_t) size << disk->log_sector_size,
|
||||
buf);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error");
|
||||
|
||||
|
@ -586,21 +544,19 @@ grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector,
|
|||
{
|
||||
/* For now, use the disk io interface rather than the block io's. */
|
||||
struct grub_efidisk_data *d;
|
||||
grub_efi_disk_io_t *dio;
|
||||
grub_efi_block_io_t *bio;
|
||||
grub_efi_status_t status;
|
||||
|
||||
d = disk->data;
|
||||
dio = d->disk_io;
|
||||
bio = d->block_io;
|
||||
|
||||
grub_dprintf ("efidisk",
|
||||
"writing 0x%lx sectors at the sector 0x%llx to %s\n",
|
||||
(unsigned long) size, (unsigned long long) sector, disk->name);
|
||||
|
||||
status = efi_call_5 (dio->write, dio, bio->media->media_id,
|
||||
(grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
|
||||
(grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
|
||||
status = efi_call_5 (bio->write_blocks, bio, bio->media->media_id,
|
||||
(grub_efi_uint64_t) sector,
|
||||
(grub_efi_uintn_t) size << disk->log_sector_size,
|
||||
(void *) buf);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error");
|
||||
|
@ -711,7 +667,35 @@ grub_efidisk_get_device_handle (grub_disk_t disk)
|
|||
char *
|
||||
grub_efidisk_get_device_name (grub_efi_handle_t *handle)
|
||||
{
|
||||
grub_efi_device_path_t *dp, *ldp;
|
||||
grub_efi_device_path_t *dp, *ldp, *sdp;
|
||||
/* This is a hard disk partition. */
|
||||
grub_disk_t parent = 0;
|
||||
auto int find_parent_disk (const char *name);
|
||||
|
||||
/* Find the disk which is the parent of a given hard disk partition. */
|
||||
int find_parent_disk (const char *name)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (! disk)
|
||||
return 1;
|
||||
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
|
||||
{
|
||||
struct grub_efidisk_data *d;
|
||||
|
||||
d = disk->data;
|
||||
if (grub_efi_compare_device_paths (d->device_path, sdp) == 0)
|
||||
{
|
||||
parent = disk;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dp = grub_efi_get_device_path (handle);
|
||||
if (! dp)
|
||||
|
@ -725,40 +709,12 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
|
|||
&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
|
||||
== GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
|
||||
{
|
||||
/* This is a hard disk partition. */
|
||||
grub_disk_t parent = 0;
|
||||
grub_partition_t tpart = NULL;
|
||||
char *partition_name = NULL;
|
||||
char *device_name;
|
||||
grub_efi_device_path_t *dup_dp, *dup_ldp;
|
||||
grub_efi_hard_drive_device_path_t hd;
|
||||
auto int find_parent_disk (const char *name);
|
||||
auto int find_partition (grub_disk_t disk, const grub_partition_t part);
|
||||
|
||||
/* Find the disk which is the parent of a given hard disk partition. */
|
||||
int find_parent_disk (const char *name)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (! disk)
|
||||
return 1;
|
||||
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
|
||||
{
|
||||
struct grub_efidisk_data *d;
|
||||
|
||||
d = disk->data;
|
||||
if (compare_device_paths (d->device_path, dup_dp) == 0)
|
||||
{
|
||||
parent = disk;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find the identical partition. */
|
||||
int find_partition (grub_disk_t disk __attribute__ ((unused)),
|
||||
const grub_partition_t part)
|
||||
|
@ -766,7 +722,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
|
|||
if (grub_partition_get_start (part) == hd.partition_start
|
||||
&& grub_partition_get_len (part) == hd.partition_size)
|
||||
{
|
||||
tpart = part;
|
||||
partition_name = grub_partition_get_name (part);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -785,7 +741,11 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
|
|||
dup_ldp->length[0] = sizeof (*dup_ldp);
|
||||
dup_ldp->length[1] = 0;
|
||||
|
||||
grub_efidisk_iterate (find_parent_disk);
|
||||
sdp = dup_dp;
|
||||
|
||||
grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_NONE);
|
||||
if (!parent)
|
||||
grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_REMOVABLE);
|
||||
grub_free (dup_dp);
|
||||
|
||||
if (! parent)
|
||||
|
@ -793,19 +753,24 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
|
|||
|
||||
/* Find a partition which matches the hard drive device path. */
|
||||
grub_memcpy (&hd, ldp, sizeof (hd));
|
||||
grub_partition_iterate (parent, find_partition);
|
||||
|
||||
if (! tpart)
|
||||
if (hd.partition_start == 0
|
||||
&& hd.partition_size == grub_disk_get_size (parent))
|
||||
{
|
||||
grub_disk_close (parent);
|
||||
return 0;
|
||||
device_name = grub_strdup (parent->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_partition_iterate (parent, find_partition);
|
||||
|
||||
{
|
||||
char *partition_name = grub_partition_get_name (tpart);
|
||||
device_name = grub_xasprintf ("%s,%s", parent->name, partition_name);
|
||||
grub_free (partition_name);
|
||||
}
|
||||
if (! partition_name)
|
||||
{
|
||||
grub_disk_close (parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_name = grub_xasprintf ("%s,%s", parent->name, partition_name);
|
||||
grub_free (partition_name);
|
||||
}
|
||||
grub_disk_close (parent);
|
||||
|
||||
return device_name;
|
||||
|
@ -813,38 +778,17 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
|
|||
else
|
||||
{
|
||||
/* This should be an entire disk. */
|
||||
auto int find_disk (const char *name);
|
||||
char *device_name = 0;
|
||||
|
||||
int find_disk (const char *name)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
sdp = dp;
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (! disk)
|
||||
return 1;
|
||||
|
||||
if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID)
|
||||
{
|
||||
struct grub_efidisk_data *d;
|
||||
|
||||
d = disk->data;
|
||||
if (compare_device_paths (d->device_path, dp) == 0)
|
||||
{
|
||||
device_name = grub_strdup (disk->name);
|
||||
grub_disk_close (disk);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
grub_efidisk_iterate (find_disk);
|
||||
grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_NONE);
|
||||
if (!parent)
|
||||
grub_efidisk_iterate (find_parent_disk, GRUB_DISK_PULL_REMOVABLE);
|
||||
if (!parent)
|
||||
return NULL;
|
||||
device_name = grub_strdup (parent->name);
|
||||
grub_disk_close (parent);
|
||||
return device_name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
568
grub-core/disk/geli.c
Normal file
568
grub-core/disk/geli.c
Normal file
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2007,2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file is loosely based on FreeBSD geli implementation
|
||||
(but no code was directly copied). FreeBSD geli is distributed under
|
||||
following terms: */
|
||||
/*-
|
||||
* Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@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 AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <grub/cryptodisk.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* Dirty trick to solve circular dependency. */
|
||||
#ifdef GRUB_UTIL
|
||||
|
||||
#include <grub/util/misc.h>
|
||||
|
||||
#undef GRUB_MD_SHA256
|
||||
#undef GRUB_MD_SHA512
|
||||
|
||||
static const gcry_md_spec_t *
|
||||
grub_md_sha256_real (void)
|
||||
{
|
||||
const gcry_md_spec_t *ret;
|
||||
ret = grub_crypto_lookup_md_by_name ("sha256");
|
||||
if (!ret)
|
||||
grub_util_error ("Coulnd't load sha256");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const gcry_md_spec_t *
|
||||
grub_md_sha512_real (void)
|
||||
{
|
||||
const gcry_md_spec_t *ret;
|
||||
ret = grub_crypto_lookup_md_by_name ("sha512");
|
||||
if (!ret)
|
||||
grub_util_error ("Coulnd't load sha512");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define GRUB_MD_SHA256 grub_md_sha256_real()
|
||||
#define GRUB_MD_SHA512 grub_md_sha512_real()
|
||||
#endif
|
||||
|
||||
struct grub_geli_key
|
||||
{
|
||||
grub_uint8_t iv_key[64];
|
||||
grub_uint8_t cipher_key[64];
|
||||
grub_uint8_t hmac[64];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_geli_phdr
|
||||
{
|
||||
grub_uint8_t magic[16];
|
||||
#define GELI_MAGIC "GEOM::ELI"
|
||||
grub_uint32_t version;
|
||||
grub_uint32_t flags;
|
||||
grub_uint16_t alg;
|
||||
grub_uint16_t keylen;
|
||||
grub_uint16_t unused3[5];
|
||||
grub_uint32_t sector_size;
|
||||
grub_uint8_t keys_used;
|
||||
grub_uint32_t niter;
|
||||
grub_uint8_t salt[64];
|
||||
struct grub_geli_key keys[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_GELI_FLAGS_ONETIME = 1,
|
||||
GRUB_GELI_FLAGS_BOOT = 2,
|
||||
};
|
||||
|
||||
/* FIXME: support version 0. */
|
||||
/* FIXME: support big-endian pre-version-4 volumes. */
|
||||
/* FIXME: support for keyfiles. */
|
||||
/* FIXME: support for HMAC. */
|
||||
const char *algorithms[] = {
|
||||
[0x01] = "des",
|
||||
[0x02] = "3des",
|
||||
[0x03] = "blowfish",
|
||||
[0x04] = "cast5",
|
||||
/* FIXME: 0x05 is skipjack, but we don't have it. */
|
||||
[0x0b] = "aes",
|
||||
/* FIXME: 0x10 is null. */
|
||||
[0x15] = "camellia128",
|
||||
[0x16] = "aes"
|
||||
};
|
||||
|
||||
#define MAX_PASSPHRASE 256
|
||||
|
||||
static gcry_err_code_t
|
||||
geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno)
|
||||
{
|
||||
gcry_err_code_t gcry_err;
|
||||
const struct {
|
||||
char magic[4];
|
||||
grub_uint64_t zone;
|
||||
} __attribute__ ((packed)) tohash
|
||||
= { {'e', 'k', 'e', 'y'}, grub_cpu_to_le64 (zoneno) };
|
||||
grub_uint64_t key[(dev->hash->mdlen + 7) / 8];
|
||||
|
||||
grub_dprintf ("geli", "rekeying %" PRIuGRUB_UINT64_T " keysize=%d\n",
|
||||
zoneno, dev->rekey_derived_size);
|
||||
gcry_err = grub_crypto_hmac_buffer (dev->hash, dev->rekey_key, 64,
|
||||
&tohash, sizeof (tohash), key);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
return grub_cryptodisk_setkey (dev, (grub_uint8_t *) key,
|
||||
dev->rekey_derived_size);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ascii2hex (char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline gcry_err_code_t
|
||||
make_uuid (const struct grub_geli_phdr *header,
|
||||
char *uuid)
|
||||
{
|
||||
grub_uint8_t uuidbin[GRUB_MD_SHA256->mdlen];
|
||||
gcry_err_code_t err;
|
||||
grub_uint8_t *iptr;
|
||||
char *optr;
|
||||
|
||||
err = grub_crypto_hmac_buffer (GRUB_MD_SHA256,
|
||||
header->salt, sizeof (header->salt),
|
||||
"uuid", sizeof ("uuid") - 1, uuidbin);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
optr = uuid;
|
||||
for (iptr = uuidbin; iptr < &uuidbin[ARRAY_SIZE (uuidbin)]; iptr++)
|
||||
{
|
||||
grub_snprintf (optr, 3, "%02x", *iptr);
|
||||
optr += 2;
|
||||
}
|
||||
*optr = 0;
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <grub/emu/hostdisk.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <grub/emu/misc.h>
|
||||
|
||||
char *
|
||||
grub_util_get_geli_uuid (const char *dev)
|
||||
{
|
||||
int fd = open (dev, O_RDONLY);
|
||||
grub_uint64_t s;
|
||||
unsigned log_secsize;
|
||||
grub_uint8_t hdr[512];
|
||||
struct grub_geli_phdr *header;
|
||||
char *uuid;
|
||||
gcry_err_code_t err;
|
||||
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
s = grub_util_get_fd_sectors (fd, &log_secsize);
|
||||
grub_util_fd_seek (fd, dev, (s << log_secsize) - 512);
|
||||
|
||||
uuid = xmalloc (GRUB_MD_SHA256->mdlen * 2 + 1);
|
||||
if (grub_util_fd_read (fd, (void *) &hdr, 512) < 0)
|
||||
grub_util_error (_("couldn't read ELI metadata"));
|
||||
|
||||
COMPILE_TIME_ASSERT (sizeof (header) <= 512);
|
||||
header = (void *) &hdr;
|
||||
|
||||
/* Look for GELI magic sequence. */
|
||||
if (grub_memcmp (header->magic, GELI_MAGIC, sizeof (GELI_MAGIC))
|
||||
|| grub_le_to_cpu32 (header->version) > 5
|
||||
|| grub_le_to_cpu32 (header->version) < 1)
|
||||
grub_util_error (_("wrong ELI magic or version"));
|
||||
|
||||
err = make_uuid ((void *) &hdr, uuid);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
return uuid;
|
||||
}
|
||||
#endif
|
||||
|
||||
static grub_cryptodisk_t
|
||||
configure_ciphers (grub_disk_t disk, const char *check_uuid,
|
||||
int boot_only)
|
||||
{
|
||||
grub_cryptodisk_t newdev;
|
||||
struct grub_geli_phdr header;
|
||||
grub_crypto_cipher_handle_t cipher = NULL, secondary_cipher = NULL;
|
||||
const struct gcry_cipher_spec *ciph;
|
||||
const char *ciphername = NULL;
|
||||
gcry_err_code_t gcry_err;
|
||||
char uuid[GRUB_MD_SHA256->mdlen * 2 + 1];
|
||||
grub_disk_addr_t sector;
|
||||
grub_err_t err;
|
||||
|
||||
sector = grub_disk_get_size (disk);
|
||||
if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0)
|
||||
return NULL;
|
||||
|
||||
/* Read the GELI header. */
|
||||
err = grub_disk_read (disk, sector - 1, 0, sizeof (header), &header);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
/* Look for GELI magic sequence. */
|
||||
if (grub_memcmp (header.magic, GELI_MAGIC, sizeof (GELI_MAGIC))
|
||||
|| grub_le_to_cpu32 (header.version) > 5
|
||||
|| grub_le_to_cpu32 (header.version) < 1)
|
||||
{
|
||||
grub_dprintf ("geli", "wrong magic %02x\n", header.magic[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((grub_le_to_cpu32 (header.sector_size)
|
||||
& (grub_le_to_cpu32 (header.sector_size) - 1))
|
||||
|| grub_le_to_cpu32 (header.sector_size) == 0)
|
||||
{
|
||||
grub_dprintf ("geli", "incorrect sector size %d\n",
|
||||
grub_le_to_cpu32 (header.sector_size));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_ONETIME)
|
||||
{
|
||||
grub_dprintf ("geli", "skipping one-time volume\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT))
|
||||
{
|
||||
grub_dprintf ("geli", "not a boot volume\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gcry_err = make_uuid (&header, uuid);
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_crypto_gcry_error (gcry_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
|
||||
{
|
||||
grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (grub_le_to_cpu16 (header.alg) >= ARRAY_SIZE (algorithms)
|
||||
|| algorithms[grub_le_to_cpu16 (header.alg)] == NULL)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher 0x%x unknown",
|
||||
grub_le_to_cpu16 (header.alg));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ciphername = algorithms[grub_le_to_cpu16 (header.alg)];
|
||||
ciph = grub_crypto_lookup_cipher_by_name (ciphername);
|
||||
if (!ciph)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available",
|
||||
ciphername);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Configure the cipher used for the bulk data. */
|
||||
cipher = grub_crypto_cipher_open (ciph);
|
||||
if (!cipher)
|
||||
return NULL;
|
||||
|
||||
if (grub_le_to_cpu16 (header.alg) == 0x16)
|
||||
{
|
||||
secondary_cipher = grub_crypto_cipher_open (ciph);
|
||||
if (!secondary_cipher)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (grub_le_to_cpu16 (header.keylen) > 1024)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d",
|
||||
grub_le_to_cpu16 (header.keylen));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newdev = grub_zalloc (sizeof (struct grub_cryptodisk));
|
||||
if (!newdev)
|
||||
return NULL;
|
||||
newdev->cipher = cipher;
|
||||
newdev->secondary_cipher = secondary_cipher;
|
||||
newdev->offset = 0;
|
||||
newdev->source_disk = NULL;
|
||||
newdev->benbi_log = 0;
|
||||
if (grub_le_to_cpu16 (header.alg) == 0x16)
|
||||
{
|
||||
newdev->mode = GRUB_CRYPTODISK_MODE_XTS;
|
||||
newdev->mode_iv = GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64;
|
||||
}
|
||||
else
|
||||
{
|
||||
newdev->mode = GRUB_CRYPTODISK_MODE_CBC;
|
||||
newdev->mode_iv = GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH;
|
||||
}
|
||||
newdev->essiv_cipher = NULL;
|
||||
newdev->essiv_hash = NULL;
|
||||
newdev->hash = GRUB_MD_SHA512;
|
||||
newdev->iv_hash = GRUB_MD_SHA256;
|
||||
|
||||
for (newdev->log_sector_size = 0;
|
||||
(1U << newdev->log_sector_size) < grub_le_to_cpu32 (header.sector_size);
|
||||
newdev->log_sector_size++);
|
||||
|
||||
if (grub_le_to_cpu32 (header.version) >= 5)
|
||||
{
|
||||
newdev->rekey = geli_rekey;
|
||||
newdev->rekey_shift = 20;
|
||||
}
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
newdev->modname = "geli";
|
||||
#endif
|
||||
|
||||
newdev->total_length = grub_disk_get_size (disk) - 1;
|
||||
grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
|
||||
COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= 32 * 2 + 1);
|
||||
return newdev;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
recover_key (grub_disk_t source, grub_cryptodisk_t dev)
|
||||
{
|
||||
grub_size_t keysize;
|
||||
grub_uint8_t digest[dev->hash->mdlen];
|
||||
grub_uint8_t geomkey[dev->hash->mdlen];
|
||||
grub_uint8_t verify_key[dev->hash->mdlen];
|
||||
grub_uint8_t zero[dev->cipher->cipher->blocksize];
|
||||
char passphrase[MAX_PASSPHRASE] = "";
|
||||
unsigned i;
|
||||
gcry_err_code_t gcry_err;
|
||||
struct grub_geli_phdr header;
|
||||
char *tmp;
|
||||
grub_disk_addr_t sector;
|
||||
grub_err_t err;
|
||||
|
||||
sector = grub_disk_get_size (source);
|
||||
if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not a geli");
|
||||
|
||||
/* Read the GELI header. */
|
||||
err = grub_disk_read (source, sector - 1, 0, sizeof (header), &header);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
keysize = grub_le_to_cpu16 (header.keylen) / 8;
|
||||
grub_memset (zero, 0, sizeof (zero));
|
||||
|
||||
grub_puts_ (N_("Attempting to decrypt master key..."));
|
||||
|
||||
/* Get the passphrase from the user. */
|
||||
tmp = NULL;
|
||||
if (source->partition)
|
||||
tmp = grub_partition_get_name (source->partition);
|
||||
grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
|
||||
source->partition ? "," : "", tmp ? : "",
|
||||
dev->uuid);
|
||||
grub_free (tmp);
|
||||
if (!grub_password_get (passphrase, MAX_PASSPHRASE))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
|
||||
|
||||
/* Calculate the PBKDF2 of the user supplied passphrase. */
|
||||
if (grub_le_to_cpu32 (header.niter) != 0)
|
||||
{
|
||||
grub_uint8_t pbkdf_key[64];
|
||||
gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
|
||||
grub_strlen (passphrase),
|
||||
header.salt,
|
||||
sizeof (header.salt),
|
||||
grub_le_to_cpu32 (header.niter),
|
||||
pbkdf_key, sizeof (pbkdf_key));
|
||||
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
gcry_err = grub_crypto_hmac_buffer (dev->hash, NULL, 0, pbkdf_key,
|
||||
sizeof (pbkdf_key), geomkey);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct grub_crypto_hmac_handle *hnd;
|
||||
|
||||
hnd = grub_crypto_hmac_init (dev->hash, NULL, 0);
|
||||
if (!hnd)
|
||||
return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY);
|
||||
|
||||
grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
|
||||
grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase));
|
||||
|
||||
gcry_err = grub_crypto_hmac_fini (hnd, geomkey);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
|
||||
sizeof (geomkey), "\1", 1, digest);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
|
||||
sizeof (geomkey), "\0", 1, verify_key);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
grub_dprintf ("geli", "keylen = %" PRIuGRUB_SIZE "\n", keysize);
|
||||
|
||||
/* Try to recover master key from each active keyslot. */
|
||||
for (i = 0; i < ARRAY_SIZE (header.keys); i++)
|
||||
{
|
||||
struct grub_geli_key candidate_key;
|
||||
grub_uint8_t key_hmac[dev->hash->mdlen];
|
||||
|
||||
/* Check if keyslot is enabled. */
|
||||
if (! (header.keys_used & (1 << i)))
|
||||
continue;
|
||||
|
||||
grub_dprintf ("geli", "Trying keyslot %d\n", i);
|
||||
|
||||
gcry_err = grub_crypto_cipher_set_key (dev->cipher,
|
||||
digest, keysize);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
gcry_err = grub_crypto_cbc_decrypt (dev->cipher, &candidate_key,
|
||||
&header.keys[i],
|
||||
sizeof (candidate_key),
|
||||
zero);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
gcry_err = grub_crypto_hmac_buffer (dev->hash, verify_key,
|
||||
sizeof (verify_key),
|
||||
&candidate_key,
|
||||
(sizeof (candidate_key)
|
||||
- sizeof (candidate_key.hmac)),
|
||||
key_hmac);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
|
||||
if (grub_memcmp (candidate_key.hmac, key_hmac, dev->hash->mdlen) != 0)
|
||||
continue;
|
||||
grub_printf_ (N_("Slot %d opened\n"), i);
|
||||
|
||||
/* Set the master key. */
|
||||
if (!dev->rekey)
|
||||
{
|
||||
grub_size_t real_keysize = keysize;
|
||||
if (grub_le_to_cpu16 (header.alg) == 0x16)
|
||||
real_keysize *= 2;
|
||||
gcry_err = grub_cryptodisk_setkey (dev, candidate_key.cipher_key,
|
||||
real_keysize);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_size_t real_keysize = keysize;
|
||||
if (grub_le_to_cpu16 (header.alg) == 0x16)
|
||||
real_keysize *= 2;
|
||||
/* For a reason I don't know, the IV key is used in rekeying. */
|
||||
grub_memcpy (dev->rekey_key, candidate_key.iv_key,
|
||||
sizeof (candidate_key.iv_key));
|
||||
dev->rekey_derived_size = real_keysize;
|
||||
dev->last_rekey = -1;
|
||||
COMPILE_TIME_ASSERT (sizeof (dev->rekey_key)
|
||||
>= sizeof (candidate_key.iv_key));
|
||||
}
|
||||
|
||||
dev->iv_prefix_len = sizeof (candidate_key.iv_key);
|
||||
grub_memcpy (dev->iv_prefix, candidate_key.iv_key,
|
||||
sizeof (candidate_key.iv_key));
|
||||
|
||||
COMPILE_TIME_ASSERT (sizeof (dev->iv_prefix) >= sizeof (candidate_key.iv_key));
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
return GRUB_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
struct grub_cryptodisk_dev geli_crypto = {
|
||||
.scan = configure_ciphers,
|
||||
.recover_key = recover_key
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (geli)
|
||||
{
|
||||
grub_cryptodisk_dev_register (&geli_crypto);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (geli)
|
||||
{
|
||||
grub_cryptodisk_dev_unregister (&geli_crypto);
|
||||
}
|
|
@ -27,8 +27,12 @@
|
|||
int grub_disk_host_i_want_a_reference;
|
||||
|
||||
static int
|
||||
grub_host_iterate (int (*hook) (const char *name))
|
||||
grub_host_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
if (hook ("host"))
|
||||
return 1;
|
||||
return 0;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -284,37 +285,46 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive)
|
|||
}
|
||||
|
||||
static int
|
||||
grub_biosdisk_iterate (int (*hook) (const char *name))
|
||||
grub_biosdisk_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull __attribute__ ((unused)))
|
||||
{
|
||||
int drive;
|
||||
int num_floppies;
|
||||
int drive;
|
||||
|
||||
/* For hard disks, attempt to read the MBR. */
|
||||
for (drive = 0x80; drive < 0x90; drive++)
|
||||
switch (pull)
|
||||
{
|
||||
if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
|
||||
GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
|
||||
case GRUB_DISK_PULL_NONE:
|
||||
for (drive = 0x80; drive < 0x90; drive++)
|
||||
{
|
||||
grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
|
||||
break;
|
||||
if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
|
||||
GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
|
||||
{
|
||||
grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
|
||||
break;
|
||||
}
|
||||
|
||||
if (grub_biosdisk_call_hook (hook, drive))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case GRUB_DISK_PULL_REMOVABLE:
|
||||
if (cd_drive)
|
||||
{
|
||||
if (grub_biosdisk_call_hook (hook, cd_drive))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (grub_biosdisk_call_hook (hook, drive))
|
||||
return 1;
|
||||
/* For floppy disks, we can get the number safely. */
|
||||
num_floppies = grub_biosdisk_get_num_floppies ();
|
||||
for (drive = 0; drive < num_floppies; drive++)
|
||||
if (grub_biosdisk_call_hook (hook, drive))
|
||||
return 1;
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cd_drive)
|
||||
{
|
||||
if (grub_biosdisk_call_hook (hook, cd_drive))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* For floppy disks, we can get the number safely. */
|
||||
num_floppies = grub_biosdisk_get_num_floppies ();
|
||||
for (drive = 0; drive < num_floppies; drive++)
|
||||
if (grub_biosdisk_call_hook (hook, drive))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -340,7 +350,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
if ((cd_drive) && (drive == cd_drive))
|
||||
{
|
||||
data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
|
||||
data->sectors = 32;
|
||||
data->sectors = 8;
|
||||
disk->log_sector_size = 11;
|
||||
/* TODO: get the correct size. */
|
||||
total_sectors = GRUB_DISK_SIZE_UNKNOWN;
|
||||
}
|
||||
|
@ -349,6 +360,8 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
/* HDD */
|
||||
int version;
|
||||
|
||||
disk->log_sector_size = 9;
|
||||
|
||||
version = grub_biosdisk_check_int13_extensions (drive);
|
||||
if (version)
|
||||
{
|
||||
|
@ -369,6 +382,15 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
|
|||
correctly but returns zero. So if it is zero, compute
|
||||
it by C/H/S returned by the LBA BIOS call. */
|
||||
total_sectors = drp->cylinders * drp->heads * drp->sectors;
|
||||
if (drp->bytes_per_sector
|
||||
&& !(drp->bytes_per_sector & (drp->bytes_per_sector - 1))
|
||||
&& drp->bytes_per_sector >= 512
|
||||
&& drp->bytes_per_sector <= 16384)
|
||||
{
|
||||
for (disk->log_sector_size = 0;
|
||||
(1 << disk->log_sector_size) < drp->bytes_per_sector;
|
||||
disk->log_sector_size++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +453,7 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk,
|
|||
|
||||
dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR
|
||||
+ (data->sectors
|
||||
<< GRUB_DISK_SECTOR_BITS));
|
||||
<< disk->log_sector_size));
|
||||
dap->length = sizeof (*dap);
|
||||
dap->reserved = 0;
|
||||
dap->blocks = size;
|
||||
|
@ -445,9 +467,6 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk,
|
|||
if (cmd)
|
||||
return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom");
|
||||
|
||||
dap->blocks = ALIGN_UP (dap->blocks, 4) >> 2;
|
||||
dap->block >>= 2;
|
||||
|
||||
for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++)
|
||||
if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap))
|
||||
break;
|
||||
|
@ -503,10 +522,12 @@ grub_biosdisk_rw (int cmd, grub_disk_t disk,
|
|||
|
||||
/* Return the number of sectors which can be read safely at a time. */
|
||||
static grub_size_t
|
||||
get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors)
|
||||
get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector)
|
||||
{
|
||||
grub_size_t size;
|
||||
grub_uint64_t offset;
|
||||
struct grub_biosdisk_data *data = disk->data;
|
||||
grub_uint32_t sectors = data->sectors;
|
||||
|
||||
/* OFFSET = SECTOR % SECTORS */
|
||||
grub_divmod64 (sector, sectors, &offset);
|
||||
|
@ -514,8 +535,8 @@ get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors)
|
|||
size = sectors - offset;
|
||||
|
||||
/* Limit the max to 0x7f because of Phoenix EDD. */
|
||||
if (size > 0x7f)
|
||||
size = 0x7f;
|
||||
if (size > ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size))
|
||||
size = ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
@ -524,21 +545,11 @@ static grub_err_t
|
|||
grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
struct grub_biosdisk_data *data = disk->data;
|
||||
|
||||
while (size)
|
||||
{
|
||||
grub_size_t len;
|
||||
grub_size_t cdoff = 0;
|
||||
|
||||
len = get_safe_sectors (sector, data->sectors);
|
||||
|
||||
if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
|
||||
{
|
||||
cdoff = (sector & 3) << GRUB_DISK_SECTOR_BITS;
|
||||
len = ALIGN_UP (sector + len, 4) - (sector & ~3);
|
||||
sector &= ~3;
|
||||
}
|
||||
len = get_safe_sectors (disk, sector);
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
@ -547,9 +558,10 @@ grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
|||
GRUB_MEMORY_MACHINE_SCRATCH_SEG))
|
||||
return grub_errno;
|
||||
|
||||
grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdoff),
|
||||
len << GRUB_DISK_SECTOR_BITS);
|
||||
buf += len << GRUB_DISK_SECTOR_BITS;
|
||||
grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR,
|
||||
len << disk->log_sector_size);
|
||||
|
||||
buf += len << disk->log_sector_size;
|
||||
sector += len;
|
||||
size -= len;
|
||||
}
|
||||
|
@ -570,18 +582,18 @@ grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
|||
{
|
||||
grub_size_t len;
|
||||
|
||||
len = get_safe_sectors (sector, data->sectors);
|
||||
len = get_safe_sectors (disk, sector);
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf,
|
||||
len << GRUB_DISK_SECTOR_BITS);
|
||||
len << disk->log_sector_size);
|
||||
|
||||
if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len,
|
||||
GRUB_MEMORY_MACHINE_SCRATCH_SEG))
|
||||
return grub_errno;
|
||||
|
||||
buf += len << GRUB_DISK_SECTOR_BITS;
|
||||
buf += len << disk->log_sector_size;
|
||||
sector += len;
|
||||
size -= len;
|
||||
}
|
||||
|
@ -610,11 +622,12 @@ grub_disk_biosdisk_fini (void)
|
|||
GRUB_MOD_INIT(biosdisk)
|
||||
{
|
||||
struct grub_biosdisk_cdrp *cdrp
|
||||
= (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
|
||||
= (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
|
||||
grub_uint8_t boot_drive;
|
||||
|
||||
if (grub_disk_firmware_is_tainted)
|
||||
{
|
||||
grub_printf ("Firmware is marked as tainted, refusing to initialize.\n");
|
||||
grub_puts_ (N_("Firmware is marked as tainted, refusing to initialize."));
|
||||
return;
|
||||
}
|
||||
grub_disk_firmware_fini = grub_disk_biosdisk_fini;
|
||||
|
@ -622,15 +635,16 @@ GRUB_MOD_INIT(biosdisk)
|
|||
grub_memset (cdrp, 0, sizeof (*cdrp));
|
||||
cdrp->size = sizeof (*cdrp);
|
||||
cdrp->media_type = 0xFF;
|
||||
if ((! grub_biosdisk_get_cdinfo_int13_extensions (grub_boot_drive, cdrp)) &&
|
||||
((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK)
|
||||
== GRUB_BIOSDISK_CDTYPE_NO_EMUL))
|
||||
boot_drive = (grub_boot_device >> 24);
|
||||
if ((! grub_biosdisk_get_cdinfo_int13_extensions (boot_drive, cdrp))
|
||||
&& ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK)
|
||||
== GRUB_BIOSDISK_CDTYPE_NO_EMUL))
|
||||
cd_drive = cdrp->drive_no;
|
||||
/* Since diskboot.S rejects devices over 0x90 it must be a CD booted with
|
||||
cdboot.S
|
||||
*/
|
||||
if (grub_boot_drive >= 0x90)
|
||||
cd_drive = grub_boot_drive;
|
||||
if (boot_drive >= 0x90)
|
||||
cd_drive = boot_drive;
|
||||
|
||||
grub_disk_dev_register (&grub_biosdisk_dev);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ struct grub_nand_data
|
|||
};
|
||||
|
||||
static int
|
||||
grub_nand_iterate (int (*hook) (const char *name))
|
||||
grub_nand_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
auto int dev_iterate (struct grub_ieee1275_devalias *alias);
|
||||
int dev_iterate (struct grub_ieee1275_devalias *alias)
|
||||
|
@ -46,6 +47,9 @@ grub_nand_iterate (int (*hook) (const char *name))
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
return grub_devalias_iterate (dev_iterate);
|
||||
}
|
||||
|
||||
|
|
|
@ -152,9 +152,14 @@ scan (void)
|
|||
}
|
||||
|
||||
static int
|
||||
grub_ofdisk_iterate (int (*hook) (const char *name))
|
||||
grub_ofdisk_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
scan ();
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++)
|
||||
|
@ -252,14 +257,24 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
|
|||
grub_dprintf ("disk", "Opening `%s'.\n", devpath);
|
||||
|
||||
if (grub_ieee1275_finddevice (devpath, &dev))
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties");
|
||||
{
|
||||
grub_free (devpath);
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"can't read device properties");
|
||||
}
|
||||
|
||||
if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop),
|
||||
&actual))
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type");
|
||||
{
|
||||
grub_free (devpath);
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type");
|
||||
}
|
||||
|
||||
if (grub_strcmp (prop, "block"))
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device");
|
||||
{
|
||||
grub_free (devpath);
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device");
|
||||
}
|
||||
|
||||
/* XXX: There is no property to read the number of blocks. There
|
||||
should be a property `#blocks', but it is not there. Perhaps it
|
||||
|
|
|
@ -133,9 +133,12 @@ fail:
|
|||
|
||||
|
||||
static int
|
||||
grub_loopback_iterate (int (*hook) (const char *name))
|
||||
grub_loopback_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_loopback *d;
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
for (d = loopback_list; d; d = d->next)
|
||||
{
|
||||
if (hook (d->devname))
|
||||
|
|
470
grub-core/disk/luks.c
Normal file
470
grub-core/disk/luks.c
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2007,2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/cryptodisk.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define MAX_PASSPHRASE 256
|
||||
|
||||
#define LUKS_KEY_ENABLED 0x00AC71F3
|
||||
|
||||
/* On disk LUKS header */
|
||||
struct grub_luks_phdr
|
||||
{
|
||||
grub_uint8_t magic[6];
|
||||
#define LUKS_MAGIC "LUKS\xBA\xBE"
|
||||
grub_uint16_t version;
|
||||
char cipherName[32];
|
||||
char cipherMode[32];
|
||||
char hashSpec[32];
|
||||
grub_uint32_t payloadOffset;
|
||||
grub_uint32_t keyBytes;
|
||||
grub_uint8_t mkDigest[20];
|
||||
grub_uint8_t mkDigestSalt[32];
|
||||
grub_uint32_t mkDigestIterations;
|
||||
char uuid[40];
|
||||
struct
|
||||
{
|
||||
grub_uint32_t active;
|
||||
grub_uint32_t passwordIterations;
|
||||
grub_uint8_t passwordSalt[32];
|
||||
grub_uint32_t keyMaterialOffset;
|
||||
grub_uint32_t stripes;
|
||||
} keyblock[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct grub_luks_phdr *grub_luks_phdr_t;
|
||||
|
||||
gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src,
|
||||
grub_uint8_t * dst, grub_size_t blocksize,
|
||||
grub_size_t blocknumbers);
|
||||
|
||||
static grub_cryptodisk_t
|
||||
configure_ciphers (grub_disk_t disk, const char *check_uuid,
|
||||
int check_boot)
|
||||
{
|
||||
grub_cryptodisk_t newdev;
|
||||
const char *iptr;
|
||||
struct grub_luks_phdr header;
|
||||
char *optr;
|
||||
char uuid[sizeof (header.uuid) + 1];
|
||||
char ciphername[sizeof (header.cipherName) + 1];
|
||||
char ciphermode[sizeof (header.cipherMode) + 1];
|
||||
char *cipheriv = NULL;
|
||||
char hashspec[sizeof (header.hashSpec) + 1];
|
||||
grub_crypto_cipher_handle_t cipher = NULL, secondary_cipher = NULL;
|
||||
grub_crypto_cipher_handle_t essiv_cipher = NULL;
|
||||
const gcry_md_spec_t *hash = NULL, *essiv_hash = NULL;
|
||||
const struct gcry_cipher_spec *ciph;
|
||||
grub_cryptodisk_mode_t mode;
|
||||
grub_cryptodisk_mode_iv_t mode_iv;
|
||||
int benbi_log = 0;
|
||||
grub_err_t err;
|
||||
|
||||
if (check_boot)
|
||||
return NULL;
|
||||
|
||||
/* Read the LUKS header. */
|
||||
err = grub_disk_read (disk, 0, 0, sizeof (header), &header);
|
||||
if (err)
|
||||
{
|
||||
if (err == GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Look for LUKS magic sequence. */
|
||||
if (grub_memcmp (header.magic, LUKS_MAGIC, sizeof (header.magic))
|
||||
|| grub_be_to_cpu16 (header.version) != 1)
|
||||
return NULL;
|
||||
|
||||
optr = uuid;
|
||||
for (iptr = header.uuid; iptr < &header.uuid[ARRAY_SIZE (header.uuid)];
|
||||
iptr++)
|
||||
{
|
||||
if (*iptr != '-')
|
||||
*optr++ = *iptr;
|
||||
}
|
||||
*optr = 0;
|
||||
|
||||
if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0)
|
||||
{
|
||||
grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure that strings are null terminated. */
|
||||
grub_memcpy (ciphername, header.cipherName, sizeof (header.cipherName));
|
||||
ciphername[sizeof (header.cipherName)] = 0;
|
||||
grub_memcpy (ciphermode, header.cipherMode, sizeof (header.cipherMode));
|
||||
ciphermode[sizeof (header.cipherMode)] = 0;
|
||||
grub_memcpy (hashspec, header.hashSpec, sizeof (header.hashSpec));
|
||||
hashspec[sizeof (header.hashSpec)] = 0;
|
||||
|
||||
ciph = grub_crypto_lookup_cipher_by_name (ciphername);
|
||||
if (!ciph)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "Cipher %s isn't available",
|
||||
ciphername);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Configure the cipher used for the bulk data. */
|
||||
cipher = grub_crypto_cipher_open (ciph);
|
||||
if (!cipher)
|
||||
return NULL;
|
||||
|
||||
if (grub_be_to_cpu32 (header.keyBytes) > 1024)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid keysize %d",
|
||||
grub_be_to_cpu32 (header.keyBytes));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Configure the cipher mode. */
|
||||
if (grub_strcmp (ciphermode, "ecb") == 0)
|
||||
{
|
||||
mode = GRUB_CRYPTODISK_MODE_ECB;
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN;
|
||||
cipheriv = NULL;
|
||||
}
|
||||
else if (grub_strcmp (ciphermode, "plain") == 0)
|
||||
{
|
||||
mode = GRUB_CRYPTODISK_MODE_CBC;
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN;
|
||||
cipheriv = NULL;
|
||||
}
|
||||
else if (grub_memcmp (ciphermode, "cbc-", sizeof ("cbc-") - 1) == 0)
|
||||
{
|
||||
mode = GRUB_CRYPTODISK_MODE_CBC;
|
||||
cipheriv = ciphermode + sizeof ("cbc-") - 1;
|
||||
}
|
||||
else if (grub_memcmp (ciphermode, "pcbc-", sizeof ("pcbc-") - 1) == 0)
|
||||
{
|
||||
mode = GRUB_CRYPTODISK_MODE_PCBC;
|
||||
cipheriv = ciphermode + sizeof ("pcbc-") - 1;
|
||||
}
|
||||
else if (grub_memcmp (ciphermode, "xts-", sizeof ("xts-") - 1) == 0)
|
||||
{
|
||||
mode = GRUB_CRYPTODISK_MODE_XTS;
|
||||
cipheriv = ciphermode + sizeof ("xts-") - 1;
|
||||
secondary_cipher = grub_crypto_cipher_open (ciph);
|
||||
if (!secondary_cipher)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
return NULL;
|
||||
}
|
||||
if (cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported XTS block size: %d",
|
||||
cipher->cipher->blocksize);
|
||||
return NULL;
|
||||
}
|
||||
if (secondary_cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported XTS block size: %d",
|
||||
secondary_cipher->cipher->blocksize);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (grub_memcmp (ciphermode, "lrw-", sizeof ("lrw-") - 1) == 0)
|
||||
{
|
||||
mode = GRUB_CRYPTODISK_MODE_LRW;
|
||||
cipheriv = ciphermode + sizeof ("lrw-") - 1;
|
||||
if (cipher->cipher->blocksize != GRUB_CRYPTODISK_GF_BYTES)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported LRW block size: %d",
|
||||
cipher->cipher->blocksize);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown cipher mode: %s",
|
||||
ciphermode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cipheriv == NULL);
|
||||
else if (grub_memcmp (cipheriv, "plain", sizeof ("plain") - 1) == 0)
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN;
|
||||
else if (grub_memcmp (cipheriv, "plain64", sizeof ("plain64") - 1) == 0)
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_PLAIN64;
|
||||
else if (grub_memcmp (cipheriv, "benbi", sizeof ("benbi") - 1) == 0)
|
||||
{
|
||||
if (cipher->cipher->blocksize & (cipher->cipher->blocksize - 1)
|
||||
|| cipher->cipher->blocksize == 0)
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported benbi blocksize: %d",
|
||||
cipher->cipher->blocksize);
|
||||
for (benbi_log = 0;
|
||||
(cipher->cipher->blocksize << benbi_log) < GRUB_DISK_SECTOR_SIZE;
|
||||
benbi_log++);
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_BENBI;
|
||||
}
|
||||
else if (grub_memcmp (cipheriv, "null", sizeof ("null") - 1) == 0)
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_NULL;
|
||||
else if (grub_memcmp (cipheriv, "essiv:", sizeof ("essiv:") - 1) == 0)
|
||||
{
|
||||
char *hash_str = cipheriv + 6;
|
||||
|
||||
mode_iv = GRUB_CRYPTODISK_MODE_IV_ESSIV;
|
||||
|
||||
/* Configure the hash and cipher used for ESSIV. */
|
||||
essiv_hash = grub_crypto_lookup_md_by_name (hash_str);
|
||||
if (!essiv_hash)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||
"Couldn't load %s hash", hash_str);
|
||||
return NULL;
|
||||
}
|
||||
essiv_cipher = grub_crypto_cipher_open (ciph);
|
||||
if (!essiv_cipher)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown IV mode: %s",
|
||||
cipheriv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Configure the hash used for the AF splitter and HMAC. */
|
||||
hash = grub_crypto_lookup_md_by_name (hashspec);
|
||||
if (!hash)
|
||||
{
|
||||
grub_crypto_cipher_close (cipher);
|
||||
grub_crypto_cipher_close (essiv_cipher);
|
||||
grub_crypto_cipher_close (secondary_cipher);
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "Couldn't load %s hash",
|
||||
hashspec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newdev = grub_zalloc (sizeof (struct grub_cryptodisk));
|
||||
if (!newdev)
|
||||
return NULL;
|
||||
newdev->cipher = cipher;
|
||||
newdev->offset = grub_be_to_cpu32 (header.payloadOffset);
|
||||
newdev->source_disk = NULL;
|
||||
newdev->benbi_log = benbi_log;
|
||||
newdev->mode = mode;
|
||||
newdev->mode_iv = mode_iv;
|
||||
newdev->secondary_cipher = secondary_cipher;
|
||||
newdev->essiv_cipher = essiv_cipher;
|
||||
newdev->essiv_hash = essiv_hash;
|
||||
newdev->hash = hash;
|
||||
newdev->log_sector_size = 9;
|
||||
newdev->total_length = grub_disk_get_size (disk) - newdev->offset;
|
||||
grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
|
||||
#ifdef GRUB_UTIL
|
||||
newdev->modname = "luks";
|
||||
#endif
|
||||
COMPILE_TIME_ASSERT (sizeof (newdev->uuid) >= sizeof (uuid));
|
||||
return newdev;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
luks_recover_key (grub_disk_t source,
|
||||
grub_cryptodisk_t dev)
|
||||
{
|
||||
struct grub_luks_phdr header;
|
||||
grub_size_t keysize;
|
||||
grub_uint8_t *split_key = NULL;
|
||||
char passphrase[MAX_PASSPHRASE] = "";
|
||||
grub_uint8_t candidate_digest[sizeof (header.mkDigest)];
|
||||
unsigned i;
|
||||
grub_size_t length;
|
||||
grub_err_t err;
|
||||
grub_size_t max_stripes = 1;
|
||||
char *tmp;
|
||||
|
||||
err = grub_disk_read (source, 0, 0, sizeof (header), &header);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
grub_puts_ (N_("Attempting to decrypt master key..."));
|
||||
keysize = grub_be_to_cpu32 (header.keyBytes);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (header.keyblock); i++)
|
||||
if (grub_be_to_cpu32 (header.keyblock[i].active) == LUKS_KEY_ENABLED
|
||||
&& grub_be_to_cpu32 (header.keyblock[i].stripes) > max_stripes)
|
||||
max_stripes = grub_be_to_cpu32 (header.keyblock[i].stripes);
|
||||
|
||||
split_key = grub_malloc (keysize * max_stripes);
|
||||
if (!split_key)
|
||||
return grub_errno;
|
||||
|
||||
/* Get the passphrase from the user. */
|
||||
tmp = NULL;
|
||||
if (source->partition)
|
||||
tmp = grub_partition_get_name (source->partition);
|
||||
grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
|
||||
source->partition ? "," : "", tmp ? : "",
|
||||
dev->uuid);
|
||||
grub_free (tmp);
|
||||
if (!grub_password_get (passphrase, MAX_PASSPHRASE))
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
|
||||
}
|
||||
|
||||
/* Try to recover master key from each active keyslot. */
|
||||
for (i = 0; i < ARRAY_SIZE (header.keyblock); i++)
|
||||
{
|
||||
gcry_err_code_t gcry_err;
|
||||
grub_uint8_t candidate_key[keysize];
|
||||
grub_uint8_t digest[keysize];
|
||||
|
||||
/* Check if keyslot is enabled. */
|
||||
if (grub_be_to_cpu32 (header.keyblock[i].active) != LUKS_KEY_ENABLED)
|
||||
continue;
|
||||
|
||||
grub_dprintf ("luks", "Trying keyslot %d\n", i);
|
||||
|
||||
/* Calculate the PBKDF2 of the user supplied passphrase. */
|
||||
gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
|
||||
grub_strlen (passphrase),
|
||||
header.keyblock[i].passwordSalt,
|
||||
sizeof (header.keyblock[i].passwordSalt),
|
||||
grub_be_to_cpu32 (header.keyblock[i].
|
||||
passwordIterations),
|
||||
digest, keysize);
|
||||
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
grub_dprintf ("luks", "PBKDF2 done\n");
|
||||
|
||||
gcry_err = grub_cryptodisk_setkey (dev, digest, keysize);
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
length = (keysize * grub_be_to_cpu32 (header.keyblock[i].stripes));
|
||||
|
||||
/* Read and decrypt the key material from the disk. */
|
||||
err = grub_disk_read (source,
|
||||
grub_be_to_cpu32 (header.keyblock
|
||||
[i].keyMaterialOffset), 0,
|
||||
length, split_key);
|
||||
if (err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return err;
|
||||
}
|
||||
|
||||
gcry_err = grub_cryptodisk_decrypt (dev, split_key, length, 0);
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
/* Merge the decrypted key material to get the candidate master key. */
|
||||
gcry_err = AF_merge (dev->hash, split_key, candidate_key, keysize,
|
||||
grub_be_to_cpu32 (header.keyblock[i].stripes));
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
grub_dprintf ("luks", "candidate key recovered\n");
|
||||
|
||||
/* Calculate the PBKDF2 of the candidate master key. */
|
||||
gcry_err = grub_crypto_pbkdf2 (dev->hash, candidate_key,
|
||||
grub_be_to_cpu32 (header.keyBytes),
|
||||
header.mkDigestSalt,
|
||||
sizeof (header.mkDigestSalt),
|
||||
grub_be_to_cpu32
|
||||
(header.mkDigestIterations),
|
||||
candidate_digest,
|
||||
sizeof (candidate_digest));
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
/* Compare the calculated PBKDF2 to the digest stored
|
||||
in the header to see if it's correct. */
|
||||
if (grub_memcmp (candidate_digest, header.mkDigest,
|
||||
sizeof (header.mkDigest)) != 0)
|
||||
{
|
||||
grub_dprintf ("luks", "bad digest\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
grub_printf_ (N_("Slot %d opened\n"), i);
|
||||
|
||||
/* Set the master key. */
|
||||
gcry_err = grub_cryptodisk_setkey (dev, candidate_key, keysize);
|
||||
if (gcry_err)
|
||||
{
|
||||
grub_free (split_key);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
grub_free (split_key);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
return GRUB_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
struct grub_cryptodisk_dev luks_crypto = {
|
||||
.scan = configure_ciphers,
|
||||
.recover_key = luks_recover_key
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (luks)
|
||||
{
|
||||
COMPILE_TIME_ASSERT (sizeof (((struct grub_luks_phdr *) 0)->uuid)
|
||||
< GRUB_CRYPTODISK_MAX_UUID_LENGTH);
|
||||
grub_cryptodisk_dev_register (&luks_crypto);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (luks)
|
||||
{
|
||||
grub_cryptodisk_dev_unregister (&luks_crypto);
|
||||
}
|
1302
grub-core/disk/lvm.c
1302
grub-core/disk/lvm.c
File diff suppressed because it is too large
Load diff
|
@ -216,11 +216,11 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
|
|||
array->chunk_size = grub_le_to_cpu32 (sb.chunk_size) >> 9;
|
||||
array->index = grub_le_to_cpu32 (sb.this_disk.number);
|
||||
array->uuid_len = 16;
|
||||
array->uuid = grub_malloc (16);
|
||||
uuid = grub_malloc (16);
|
||||
array->uuid = (char *) uuid;
|
||||
if (!array->uuid)
|
||||
return grub_errno;
|
||||
|
||||
uuid = (grub_uint32_t *) array->uuid;
|
||||
uuid[0] = grub_swap_bytes32 (sb.set_uuid0);
|
||||
uuid[1] = grub_swap_bytes32 (sb.set_uuid1);
|
||||
uuid[2] = grub_swap_bytes32 (sb.set_uuid2);
|
||||
|
|
|
@ -30,8 +30,12 @@ static char *memdisk_addr;
|
|||
static grub_off_t memdisk_size = 0;
|
||||
|
||||
static int
|
||||
grub_memdisk_iterate (int (*hook) (const char *name))
|
||||
grub_memdisk_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
return hook ("memdisk");
|
||||
}
|
||||
|
||||
|
@ -82,30 +86,24 @@ static struct grub_disk_dev grub_memdisk_dev =
|
|||
|
||||
GRUB_MOD_INIT(memdisk)
|
||||
{
|
||||
auto int hook (struct grub_module_header *);
|
||||
int hook (struct grub_module_header *header)
|
||||
{
|
||||
if (header->type == OBJ_TYPE_MEMDISK)
|
||||
{
|
||||
char *memdisk_orig_addr;
|
||||
memdisk_orig_addr = (char *) header + sizeof (struct grub_module_header);
|
||||
struct grub_module_header *header;
|
||||
FOR_MODULES (header)
|
||||
if (header->type == OBJ_TYPE_MEMDISK)
|
||||
{
|
||||
char *memdisk_orig_addr;
|
||||
memdisk_orig_addr = (char *) header + sizeof (struct grub_module_header);
|
||||
|
||||
grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr);
|
||||
grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr);
|
||||
|
||||
memdisk_size = header->size - sizeof (struct grub_module_header);
|
||||
memdisk_addr = grub_malloc (memdisk_size);
|
||||
memdisk_size = header->size - sizeof (struct grub_module_header);
|
||||
memdisk_addr = grub_malloc (memdisk_size);
|
||||
|
||||
grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n");
|
||||
grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size);
|
||||
grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n");
|
||||
grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size);
|
||||
|
||||
grub_disk_dev_register (&grub_memdisk_dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_module_iterate (hook);
|
||||
grub_disk_dev_register (&grub_memdisk_dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(memdisk)
|
||||
|
|
538
grub-core/disk/pata.c
Normal file
538
grub-core/disk/pata.c
Normal file
|
@ -0,0 +1,538 @@
|
|||
/* ata_pthru.c - ATA pass through for ata.mod. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <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>
|
||||
#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS
|
||||
#include <grub/pci.h>
|
||||
#include <grub/cs5536.h>
|
||||
#else
|
||||
#define GRUB_MACHINE_PCI_IO_BASE 0xb4000000
|
||||
#endif
|
||||
#include <grub/time.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* At the moment, only two IDE ports are supported. */
|
||||
static const grub_port_t grub_pata_ioaddress[] = { GRUB_ATA_CH0_PORT1,
|
||||
GRUB_ATA_CH1_PORT1 };
|
||||
|
||||
struct grub_pata_device
|
||||
{
|
||||
/* IDE port to use. */
|
||||
int port;
|
||||
|
||||
/* IO addresses on which the registers for this device can be
|
||||
found. */
|
||||
grub_port_t ioaddress;
|
||||
|
||||
/* Two devices can be connected to a single cable. Use this field
|
||||
to select device 0 (commonly known as "master") or device 1
|
||||
(commonly known as "slave"). */
|
||||
int device;
|
||||
|
||||
int present;
|
||||
|
||||
struct grub_pata_device *next;
|
||||
};
|
||||
|
||||
static struct grub_pata_device *grub_pata_devices;
|
||||
|
||||
static inline void
|
||||
grub_pata_regset (struct grub_pata_device *dev, int reg, int val)
|
||||
{
|
||||
grub_outb (val, dev->ioaddress + reg);
|
||||
}
|
||||
|
||||
static inline grub_uint8_t
|
||||
grub_pata_regget (struct grub_pata_device *dev, int reg)
|
||||
{
|
||||
return grub_inb (dev->ioaddress + reg);
|
||||
}
|
||||
|
||||
/* Wait for !BSY. */
|
||||
static grub_err_t
|
||||
grub_pata_wait_not_busy (struct grub_pata_device *dev, int milliseconds)
|
||||
{
|
||||
/* ATA requires 400ns (after a write to CMD register) or
|
||||
1 PIO cycle (after a DRQ block transfer) before
|
||||
first check of BSY. */
|
||||
grub_millisleep (1);
|
||||
|
||||
int i = 1;
|
||||
grub_uint8_t sts;
|
||||
while ((sts = grub_pata_regget (dev, GRUB_ATA_REG_STATUS))
|
||||
& GRUB_ATA_STATUS_BUSY)
|
||||
{
|
||||
if (i >= milliseconds)
|
||||
{
|
||||
grub_dprintf ("pata", "timeout: %dms, status=0x%x\n",
|
||||
milliseconds, sts);
|
||||
return grub_error (GRUB_ERR_TIMEOUT, "PATA timeout");
|
||||
}
|
||||
|
||||
grub_millisleep (1);
|
||||
i++;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static inline grub_err_t
|
||||
grub_pata_check_ready (struct grub_pata_device *dev, int spinup)
|
||||
{
|
||||
if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY)
|
||||
return grub_pata_wait_not_busy (dev, spinup ? GRUB_ATA_TOUT_SPINUP
|
||||
: GRUB_ATA_TOUT_STD);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
grub_pata_wait (void)
|
||||
{
|
||||
grub_millisleep (50);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_pata_pio_read (struct grub_pata_device *dev, char *buf, grub_size_t size)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Read in the data, word by word. */
|
||||
for (i = 0; i < size / 2; i++)
|
||||
grub_set_unaligned16 (buf + 2 * i,
|
||||
grub_le_to_cpu16 (grub_inw(dev->ioaddress
|
||||
+ GRUB_ATA_REG_DATA)));
|
||||
if (size & 1)
|
||||
buf[size - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress
|
||||
+ GRUB_ATA_REG_DATA));
|
||||
}
|
||||
|
||||
static void
|
||||
grub_pata_pio_write (struct grub_pata_device *dev, char *buf, grub_size_t size)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Write the data, word by word. */
|
||||
for (i = 0; i < size / 2; i++)
|
||||
grub_outw(grub_cpu_to_le16 (grub_get_unaligned16 (buf + 2 * i)), dev->ioaddress + GRUB_ATA_REG_DATA);
|
||||
}
|
||||
|
||||
/* ATA pass through support, used by hdparm.mod. */
|
||||
static grub_err_t
|
||||
grub_pata_readwrite (struct grub_ata *disk,
|
||||
struct grub_disk_ata_pass_through_parms *parms,
|
||||
int spinup)
|
||||
{
|
||||
struct grub_pata_device *dev = (struct grub_pata_device *) disk->data;
|
||||
grub_size_t nread = 0;
|
||||
int i;
|
||||
|
||||
if (! (parms->cmdsize == 0 || parms->cmdsize == 12))
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"ATAPI non-12 byte commands not supported");
|
||||
|
||||
grub_dprintf ("pata", "pata_pass_through: cmd=0x%x, features=0x%x, sectors=0x%x\n",
|
||||
parms->taskfile.cmd,
|
||||
parms->taskfile.features,
|
||||
parms->taskfile.sectors);
|
||||
grub_dprintf ("pata", "lba_high=0x%x, lba_mid=0x%x, lba_low=0x%x, size=%"
|
||||
PRIuGRUB_SIZE "\n",
|
||||
parms->taskfile.lba_high,
|
||||
parms->taskfile.lba_mid,
|
||||
parms->taskfile.lba_low, parms->size);
|
||||
|
||||
/* Set registers. */
|
||||
grub_pata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4)
|
||||
| (parms->taskfile.disk & 0xef));
|
||||
if (grub_pata_check_ready (dev, spinup))
|
||||
return grub_errno;
|
||||
|
||||
for (i = GRUB_ATA_REG_SECTORS; i <= GRUB_ATA_REG_LBAHIGH; i++)
|
||||
grub_pata_regset (dev, i,
|
||||
parms->taskfile.raw[7 + (i - GRUB_ATA_REG_SECTORS)]);
|
||||
for (i = GRUB_ATA_REG_FEATURES; i <= GRUB_ATA_REG_LBAHIGH; i++)
|
||||
grub_pata_regset (dev, i, parms->taskfile.raw[i - GRUB_ATA_REG_FEATURES]);
|
||||
|
||||
/* Start command. */
|
||||
grub_pata_regset (dev, GRUB_ATA_REG_CMD, parms->taskfile.cmd);
|
||||
|
||||
/* Wait for !BSY. */
|
||||
if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
|
||||
return grub_errno;
|
||||
|
||||
/* Check status. */
|
||||
grub_int8_t sts = grub_pata_regget (dev, GRUB_ATA_REG_STATUS);
|
||||
grub_dprintf ("pata", "status=0x%x\n", sts);
|
||||
|
||||
if (parms->cmdsize)
|
||||
{
|
||||
grub_uint8_t irs;
|
||||
/* Wait for !BSY. */
|
||||
if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
|
||||
return grub_errno;
|
||||
|
||||
irs = grub_pata_regget (dev, GRUB_ATAPI_REG_IREASON);
|
||||
/* OK if DRQ is asserted and interrupt reason is as expected. */
|
||||
if (!((sts & GRUB_ATA_STATUS_DRQ)
|
||||
&& (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_CMD_OUT))
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error");
|
||||
/* Write the packet. */
|
||||
grub_pata_pio_write (dev, parms->cmd, parms->cmdsize);
|
||||
}
|
||||
|
||||
/* Transfer data. */
|
||||
while (nread < parms->size
|
||||
&& ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
|
||||
== GRUB_ATA_STATUS_DRQ)
|
||||
&& (!parms->cmdsize
|
||||
|| ((grub_pata_regget (dev, GRUB_ATAPI_REG_IREASON)
|
||||
& GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_DATA_IN)))
|
||||
{
|
||||
unsigned cnt;
|
||||
|
||||
/* Wait for !BSY. */
|
||||
if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
|
||||
return grub_errno;
|
||||
|
||||
if (parms->cmdsize)
|
||||
{
|
||||
cnt = grub_pata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8
|
||||
| grub_pata_regget (dev, GRUB_ATAPI_REG_CNTLOW);
|
||||
grub_dprintf("pata", "DRQ count=%u\n", cnt);
|
||||
|
||||
/* Count of last transfer may be uneven. */
|
||||
if (! (0 < cnt && cnt <= parms->size - nread
|
||||
&& (! (cnt & 1) || cnt == parms->size - nread)))
|
||||
return grub_error (GRUB_ERR_READ_ERROR,
|
||||
"invalid ATAPI transfer count");
|
||||
}
|
||||
else
|
||||
cnt = GRUB_DISK_SECTOR_SIZE;
|
||||
if (cnt > parms->size - nread)
|
||||
cnt = parms->size - nread;
|
||||
|
||||
if (parms->write)
|
||||
grub_pata_pio_write (dev, (char *) parms->buffer + nread, cnt);
|
||||
else
|
||||
grub_pata_pio_read (dev, (char *) parms->buffer + nread, cnt);
|
||||
|
||||
nread += cnt;
|
||||
}
|
||||
if (parms->write)
|
||||
{
|
||||
/* Check for write error. */
|
||||
if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
|
||||
return grub_errno;
|
||||
|
||||
if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS)
|
||||
& (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
|
||||
return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error");
|
||||
}
|
||||
parms->size = nread;
|
||||
|
||||
/* Wait for !BSY. */
|
||||
if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA))
|
||||
return grub_errno;
|
||||
|
||||
/* Return registers. */
|
||||
for (i = GRUB_ATA_REG_ERROR; i <= GRUB_ATA_REG_STATUS; i++)
|
||||
parms->taskfile.raw[i - GRUB_ATA_REG_FEATURES] = grub_pata_regget (dev, i);
|
||||
|
||||
grub_dprintf ("pata", "status=0x%x, error=0x%x, sectors=0x%x\n",
|
||||
parms->taskfile.status,
|
||||
parms->taskfile.error,
|
||||
parms->taskfile.sectors);
|
||||
|
||||
if (parms->taskfile.status
|
||||
& (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR))
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "PATA passthrough failed");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
check_device (struct grub_pata_device *dev)
|
||||
{
|
||||
grub_pata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
|
||||
grub_pata_wait ();
|
||||
|
||||
/* Try to detect if the port is in use by writing to it,
|
||||
waiting for a while and reading it again. If the value
|
||||
was preserved, there is a device connected. */
|
||||
grub_pata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
|
||||
grub_pata_wait ();
|
||||
grub_uint8_t sec = grub_pata_regget (dev, GRUB_ATA_REG_SECTORS);
|
||||
grub_dprintf ("ata", "sectors=0x%x\n", sec);
|
||||
if (sec != 0x5A)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected");
|
||||
|
||||
/* The above test may detect a second (slave) device
|
||||
connected to a SATA controller which supports only one
|
||||
(master) device. It is not safe to use the status register
|
||||
READY bit to check for controller channel existence. Some
|
||||
ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pata_device_initialize (int port, int device, int addr)
|
||||
{
|
||||
struct grub_pata_device *dev;
|
||||
struct grub_pata_device **devp;
|
||||
grub_err_t err;
|
||||
|
||||
grub_dprintf ("pata", "detecting device %d,%d (0x%x)\n",
|
||||
port, device, addr);
|
||||
|
||||
dev = grub_malloc (sizeof(*dev));
|
||||
if (! dev)
|
||||
return grub_errno;
|
||||
|
||||
/* Setup the device information. */
|
||||
dev->port = port;
|
||||
dev->device = device;
|
||||
dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE;
|
||||
dev->present = 1;
|
||||
dev->next = NULL;
|
||||
|
||||
/* Register the device. */
|
||||
for (devp = &grub_pata_devices; *devp; devp = &(*devp)->next);
|
||||
*devp = dev;
|
||||
|
||||
err = check_device (dev);
|
||||
if (err)
|
||||
grub_print_error ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef GRUB_MACHINE_MIPS_QEMU_MIPS
|
||||
static int NESTED_FUNC_ATTR
|
||||
grub_pata_pciinit (grub_pci_device_t dev,
|
||||
grub_pci_id_t pciid)
|
||||
{
|
||||
static int compat_use[2] = { 0 };
|
||||
grub_pci_address_t addr;
|
||||
grub_uint32_t class;
|
||||
grub_uint32_t bar1;
|
||||
grub_uint32_t bar2;
|
||||
int rega;
|
||||
int i;
|
||||
static int controller = 0;
|
||||
int cs5536 = 0;
|
||||
int nports = 2;
|
||||
|
||||
/* Read class. */
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
|
||||
class = grub_pci_read (addr);
|
||||
|
||||
/* AMD CS5536 Southbridge. */
|
||||
if (pciid == GRUB_CS5536_PCIID)
|
||||
{
|
||||
cs5536 = 1;
|
||||
nports = 1;
|
||||
}
|
||||
|
||||
/* Check if this class ID matches that of a PCI IDE Controller. */
|
||||
if (!cs5536 && (class >> 16 != 0x0101))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < nports; i++)
|
||||
{
|
||||
/* Set to 0 when the channel operated in compatibility mode. */
|
||||
int compat;
|
||||
|
||||
/* We don't support non-compatibility mode for CS5536. */
|
||||
if (cs5536)
|
||||
compat = 0;
|
||||
else
|
||||
compat = (class >> (8 + 2 * i)) & 1;
|
||||
|
||||
rega = 0;
|
||||
|
||||
/* If the channel is in compatibility mode, just assign the
|
||||
default registers. */
|
||||
if (compat == 0 && !compat_use[i])
|
||||
{
|
||||
rega = grub_pata_ioaddress[i];
|
||||
compat_use[i] = 1;
|
||||
}
|
||||
else if (compat)
|
||||
{
|
||||
/* Read the BARs, which either contain a mmapped IO address
|
||||
or the IO port address. */
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES
|
||||
+ sizeof (grub_uint64_t) * i);
|
||||
bar1 = grub_pci_read (addr);
|
||||
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES
|
||||
+ sizeof (grub_uint64_t) * i
|
||||
+ sizeof (grub_uint32_t));
|
||||
bar2 = grub_pci_read (addr);
|
||||
|
||||
/* Check if the BARs describe an IO region. */
|
||||
if ((bar1 & 1) && (bar2 & 1))
|
||||
{
|
||||
rega = bar1 & ~3;
|
||||
}
|
||||
}
|
||||
|
||||
grub_dprintf ("pata",
|
||||
"PCI dev (%d,%d,%d) compat=%d rega=0x%x\n",
|
||||
grub_pci_get_bus (dev), grub_pci_get_device (dev),
|
||||
grub_pci_get_function (dev), compat, rega);
|
||||
|
||||
if (rega)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_pata_device_initialize (controller * 2 + i, 0, rega);
|
||||
|
||||
/* Most errors raised by grub_ata_device_initialize() are harmless.
|
||||
They just indicate this particular drive is not responding, most
|
||||
likely because it doesn't exist. We might want to ignore specific
|
||||
error types here, instead of printing them. */
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_pata_device_initialize (controller * 2 + i, 1, rega);
|
||||
|
||||
/* Likewise. */
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
controller++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pata_initialize (void)
|
||||
{
|
||||
grub_pci_iterate (grub_pata_pciinit);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static grub_err_t
|
||||
grub_pata_initialize (void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
grub_pata_device_initialize (i, 0, grub_pata_ioaddress[i]);
|
||||
grub_pata_device_initialize (i, 1, grub_pata_ioaddress[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_pata_open (int id, int devnum, struct grub_ata *ata)
|
||||
{
|
||||
struct grub_pata_device *dev;
|
||||
struct grub_pata_device *devfnd = 0;
|
||||
grub_err_t err;
|
||||
|
||||
if (id != GRUB_SCSI_SUBSYSTEM_PATA)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a PATA device");
|
||||
|
||||
for (dev = grub_pata_devices; dev; dev = dev->next)
|
||||
{
|
||||
if (dev->port * 2 + dev->device == devnum)
|
||||
{
|
||||
devfnd = dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
grub_dprintf ("pata", "opening PATA dev `ata%d'\n", devnum);
|
||||
|
||||
if (! devfnd)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such PATA device");
|
||||
|
||||
err = check_device (devfnd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ata->data = devfnd;
|
||||
ata->dma = 0;
|
||||
ata->present = &devfnd->present;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_pata_iterate (int (*hook) (int id, int bus),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_pata_device *dev;
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
for (dev = grub_pata_devices; dev; dev = dev->next)
|
||||
if (hook (GRUB_SCSI_SUBSYSTEM_PATA, dev->port * 2 + dev->device))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct grub_ata_dev grub_pata_dev =
|
||||
{
|
||||
.iterate = grub_pata_iterate,
|
||||
.open = grub_pata_open,
|
||||
.readwrite = grub_pata_readwrite,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
GRUB_MOD_INIT(ata_pthru)
|
||||
{
|
||||
/* To prevent two drivers operating on the same disks. */
|
||||
grub_disk_firmware_is_tainted = 1;
|
||||
if (grub_disk_firmware_fini)
|
||||
{
|
||||
grub_disk_firmware_fini ();
|
||||
grub_disk_firmware_fini = NULL;
|
||||
}
|
||||
|
||||
/* ATA initialization. */
|
||||
grub_pata_initialize ();
|
||||
|
||||
grub_ata_dev_register (&grub_pata_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(ata_pthru)
|
||||
{
|
||||
grub_ata_dev_unregister (&grub_pata_dev);
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/partition.h>
|
||||
#ifdef GRUB_UTIL
|
||||
#include <grub/util/misc.h>
|
||||
#endif
|
||||
|
@ -33,6 +34,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
static struct grub_raid_array *array_list;
|
||||
grub_raid5_recover_func_t grub_raid5_recover_func;
|
||||
grub_raid6_recover_func_t grub_raid6_recover_func;
|
||||
static grub_raid_t grub_raid_list;
|
||||
static int inscnt = 0;
|
||||
|
||||
static struct grub_raid_array *
|
||||
find_array (const char *name);
|
||||
|
||||
|
||||
static char
|
||||
|
@ -78,14 +84,102 @@ grub_is_array_readable (struct grub_raid_array *array)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
||||
grub_disk_addr_t start_sector, const char *scanner_name,
|
||||
grub_raid_t raid __attribute__ ((unused)));
|
||||
|
||||
static int scan_depth = 0;
|
||||
|
||||
static void
|
||||
scan_devices (const char *arname)
|
||||
{
|
||||
grub_raid_t raid;
|
||||
|
||||
auto int hook (const char *name);
|
||||
int hook (const char *name)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_raid_array array;
|
||||
struct grub_raid_array *arr;
|
||||
grub_disk_addr_t start_sector;
|
||||
|
||||
grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
|
||||
raid->name, name);
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("Scanning for %s RAID devices on disk %s",
|
||||
raid->name, name);
|
||||
#endif
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (!disk)
|
||||
return 0;
|
||||
|
||||
for (arr = array_list; arr != NULL; arr = arr->next)
|
||||
{
|
||||
struct grub_raid_member *m;
|
||||
for (m = arr->members; m < arr->members + arr->nr_devs; m++)
|
||||
if (m->device && m->device->id == disk->id
|
||||
&& m->device->dev->id == disk->dev->id
|
||||
&& grub_partition_get_start (m->device->partition)
|
||||
== grub_partition_get_start (disk->partition)
|
||||
&& grub_disk_get_size (m->device)
|
||||
== grub_disk_get_size (disk))
|
||||
{
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((disk->total_sectors != GRUB_ULONG_MAX) &&
|
||||
(! raid->detect (disk, &array, &start_sector)) &&
|
||||
(! insert_array (disk, &array, start_sector, raid->name,
|
||||
raid)))
|
||||
return 0;
|
||||
|
||||
/* This error usually means it's not raid, no need to display
|
||||
it. */
|
||||
if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_print_error ();
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_disk_close (disk);
|
||||
|
||||
if (arname && find_array (arname))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scan_depth)
|
||||
return;
|
||||
|
||||
scan_depth++;
|
||||
for (raid = grub_raid_list; raid; raid = raid->next)
|
||||
grub_device_iterate (&hook);
|
||||
scan_depth--;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_raid_iterate (int (*hook) (const char *name))
|
||||
grub_raid_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
int islcnt = 0;
|
||||
|
||||
if (pull == GRUB_DISK_PULL_RESCAN)
|
||||
{
|
||||
islcnt = inscnt;
|
||||
scan_devices (NULL);
|
||||
}
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
|
||||
return 0;
|
||||
|
||||
for (array = array_list; array != NULL; array = array->next)
|
||||
{
|
||||
if (grub_is_array_readable (array))
|
||||
if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
|
||||
if (hook (array->name))
|
||||
return 1;
|
||||
}
|
||||
|
@ -134,11 +228,10 @@ ascii2hex (char c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid_open (const char *name, grub_disk_t disk)
|
||||
static struct grub_raid_array *
|
||||
find_array (const char *name)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
unsigned n;
|
||||
|
||||
if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
|
||||
{
|
||||
|
@ -155,7 +248,7 @@ grub_raid_open (const char *name, grub_disk_t disk)
|
|||
if (uuid_len == (unsigned) array->uuid_len
|
||||
&& grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
|
||||
if (grub_is_array_readable (array))
|
||||
break;
|
||||
return array;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -163,8 +256,33 @@ grub_raid_open (const char *name, grub_disk_t disk)
|
|||
{
|
||||
if (!grub_strcmp (array->name, name))
|
||||
if (grub_is_array_readable (array))
|
||||
break;
|
||||
return array;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid_open (const char *name, grub_disk_t disk)
|
||||
{
|
||||
struct grub_raid_array *array;
|
||||
unsigned n;
|
||||
|
||||
if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
|
||||
name);
|
||||
|
||||
array = find_array (name);
|
||||
|
||||
if (! array)
|
||||
{
|
||||
scan_devices (name);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
array = find_array (name);
|
||||
}
|
||||
|
||||
if (!array)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
|
||||
|
@ -214,23 +332,6 @@ grub_raid_close (grub_disk_t disk __attribute ((unused)))
|
|||
return;
|
||||
}
|
||||
|
||||
void
|
||||
grub_raid_block_xor (char *buf1, const char *buf2, int size)
|
||||
{
|
||||
grub_size_t *p1;
|
||||
const grub_size_t *p2;
|
||||
|
||||
p1 = (grub_size_t *) buf1;
|
||||
p2 = (const grub_size_t *) buf2;
|
||||
size /= GRUB_CPU_SIZEOF_VOID_P;
|
||||
|
||||
while (size)
|
||||
{
|
||||
*(p1++) ^= *(p2++);
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
|
@ -524,6 +625,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
|||
grub_raid_t raid __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_raid_array *array = 0, *p;
|
||||
int was_readable = 0;
|
||||
|
||||
/* See whether the device is part of an array we have already seen a
|
||||
device from. */
|
||||
|
@ -534,6 +636,8 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
|||
grub_free (new_array->uuid);
|
||||
array = p;
|
||||
|
||||
was_readable = grub_is_array_readable (array);
|
||||
|
||||
/* Do some checks before adding the device to the array. */
|
||||
|
||||
if (new_array->index >= array->allocated_devs)
|
||||
|
@ -679,6 +783,49 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
|||
scanner_name);
|
||||
#endif
|
||||
|
||||
{
|
||||
int max_used_number = 0, len, need_new_name = 0;
|
||||
int add_us = 0;
|
||||
len = grub_strlen (array->name);
|
||||
if (len && grub_isdigit (array->name[len-1]))
|
||||
add_us = 1;
|
||||
for (p = array_list; p != NULL; p = p->next)
|
||||
{
|
||||
int cur_num;
|
||||
char *num, *end;
|
||||
if (grub_strncmp (p->name, array->name, len) != 0)
|
||||
continue;
|
||||
if (p->name[len] == 0)
|
||||
{
|
||||
need_new_name = 1;
|
||||
continue;
|
||||
}
|
||||
if (add_us && p->name[len] != '_')
|
||||
continue;
|
||||
if (add_us)
|
||||
num = p->name + len + 1;
|
||||
else
|
||||
num = p->name + len;
|
||||
if (!grub_isdigit (num[0]))
|
||||
continue;
|
||||
cur_num = grub_strtoull (num, &end, 10);
|
||||
if (end[0])
|
||||
continue;
|
||||
if (cur_num > max_used_number)
|
||||
max_used_number = cur_num;
|
||||
}
|
||||
if (need_new_name)
|
||||
{
|
||||
char *tmp;
|
||||
tmp = grub_xasprintf ("%s%s%d", array->name, add_us ? "_" : "",
|
||||
max_used_number + 1);
|
||||
if (!tmp)
|
||||
return grub_errno;
|
||||
grub_free (array->name);
|
||||
array->name = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add our new array to the list. */
|
||||
array->next = array_list;
|
||||
array_list = array;
|
||||
|
@ -693,12 +840,12 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
|
|||
array->members[new_array->index].device = disk;
|
||||
array->members[new_array->index].start_sector = start_sector;
|
||||
array->nr_devs++;
|
||||
if (!was_readable && grub_is_array_readable (array))
|
||||
array->became_readable_at = inscnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_raid_t grub_raid_list;
|
||||
|
||||
static void
|
||||
free_array (void)
|
||||
{
|
||||
|
@ -729,45 +876,8 @@ free_array (void)
|
|||
void
|
||||
grub_raid_register (grub_raid_t raid)
|
||||
{
|
||||
auto int hook (const char *name);
|
||||
int hook (const char *name)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_raid_array array;
|
||||
grub_disk_addr_t start_sector;
|
||||
|
||||
grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
|
||||
grub_raid_list->name, name);
|
||||
#ifdef GRUB_UTIL
|
||||
grub_util_info ("Scanning for %s RAID devices on disk %s",
|
||||
grub_raid_list->name, name);
|
||||
#endif
|
||||
|
||||
disk = grub_disk_open (name);
|
||||
if (!disk)
|
||||
return 0;
|
||||
|
||||
if ((disk->total_sectors != GRUB_ULONG_MAX) &&
|
||||
(! grub_raid_list->detect (disk, &array, &start_sector)) &&
|
||||
(! insert_array (disk, &array, start_sector, grub_raid_list->name,
|
||||
grub_raid_list)))
|
||||
return 0;
|
||||
|
||||
/* This error usually means it's not raid, no need to display
|
||||
it. */
|
||||
if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_print_error ();
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
grub_disk_close (disk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
raid->next = grub_raid_list;
|
||||
grub_raid_list = raid;
|
||||
grub_device_iterate (&hook);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/crypto.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -57,7 +58,7 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr,
|
|||
return err;
|
||||
}
|
||||
|
||||
grub_raid_block_xor (buf, buf2, size);
|
||||
grub_crypto_xor (buf, buf2, buf2, size);
|
||||
}
|
||||
|
||||
grub_free (buf2);
|
||||
|
|
|
@ -23,70 +23,44 @@
|
|||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/raid.h>
|
||||
#include <grub/crypto.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_uint8_t raid6_table1[256][256];
|
||||
static grub_uint8_t raid6_table2[256][256];
|
||||
/* x**y. */
|
||||
static grub_uint8_t powx[255 * 2];
|
||||
/* Such an s that x**s = y */
|
||||
static int powx_inv[256];
|
||||
static const grub_uint8_t poly = 0x1d;
|
||||
|
||||
static void
|
||||
grub_raid_block_mul (grub_uint8_t mul, char *buf, int size)
|
||||
grub_raid_block_mulx (int mul, char *buf, int size)
|
||||
{
|
||||
int i;
|
||||
grub_uint8_t *p;
|
||||
|
||||
p = (grub_uint8_t *) buf;
|
||||
for (i = 0; i < size; i++, p++)
|
||||
*p = raid6_table1[mul][*p];
|
||||
if (*p)
|
||||
*p = powx[mul + powx_inv[*p]];
|
||||
}
|
||||
|
||||
static void
|
||||
grub_raid6_init_table (void)
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
raid6_table1[i][1] = raid6_table1[1][i] = i;
|
||||
|
||||
for (i = 2; i < 256; i++)
|
||||
for (j = i; j < 256; j++)
|
||||
{
|
||||
int n;
|
||||
grub_uint8_t c;
|
||||
|
||||
n = i >> 1;
|
||||
|
||||
c = raid6_table1[n][j];
|
||||
c = (c << 1) ^ ((c & 0x80) ? 0x1d : 0);
|
||||
if (i & 1)
|
||||
c ^= j;
|
||||
|
||||
raid6_table1[j][i] = raid6_table1[i][j] = c;
|
||||
}
|
||||
|
||||
raid6_table2[0][0] = 1;
|
||||
for (i = 1; i < 256; i++)
|
||||
raid6_table2[i][i] = raid6_table1[raid6_table2[i - 1][i - 1]][2];
|
||||
|
||||
for (i = 0; i < 254; i++)
|
||||
for (j = 0; j < 254; j++)
|
||||
{
|
||||
grub_uint8_t c, n;
|
||||
int k;
|
||||
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
k = i - j;
|
||||
if (k < 0)
|
||||
k += 255;
|
||||
|
||||
c = n = raid6_table2[k][k] ^ 1;
|
||||
for (k = 0; k < 253; k++)
|
||||
c = raid6_table1[c][n];
|
||||
|
||||
raid6_table2[i][j] = raid6_table1[raid6_table2[255 - j][255 - j]][c];
|
||||
}
|
||||
grub_uint8_t cur = 1;
|
||||
for (i = 0; i < 255; i++)
|
||||
{
|
||||
powx[i] = cur;
|
||||
powx[i + 255] = cur;
|
||||
powx_inv[cur] = i;
|
||||
if (cur & 0x80)
|
||||
cur = (cur << 1) ^ poly;
|
||||
else
|
||||
cur <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
@ -122,12 +96,12 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
{
|
||||
if ((array->members[pos].device) &&
|
||||
(! grub_disk_read (array->members[pos].device,
|
||||
array->members[i].start_sector + sector,
|
||||
array->members[pos].start_sector + sector,
|
||||
0, size, buf)))
|
||||
{
|
||||
grub_raid_block_xor (pbuf, buf, size);
|
||||
grub_raid_block_mul (raid6_table2[i][i], buf, size);
|
||||
grub_raid_block_xor (qbuf, buf, size);
|
||||
grub_crypto_xor (pbuf, pbuf, buf, size);
|
||||
grub_raid_block_mulx (i, buf, size);
|
||||
grub_crypto_xor (qbuf, qbuf, buf, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -154,10 +128,10 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
/* One bad device */
|
||||
if ((array->members[p].device) &&
|
||||
(! grub_disk_read (array->members[p].device,
|
||||
array->members[i].start_sector + sector,
|
||||
array->members[p].start_sector + sector,
|
||||
0, size, buf)))
|
||||
{
|
||||
grub_raid_block_xor (buf, pbuf, size);
|
||||
grub_crypto_xor (buf, buf, pbuf, size);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
|
@ -169,17 +143,17 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (grub_disk_read (array->members[q].device,
|
||||
array->members[i].start_sector + sector, 0, size, buf))
|
||||
array->members[q].start_sector + sector, 0, size, buf))
|
||||
goto quit;
|
||||
|
||||
grub_raid_block_xor (buf, qbuf, size);
|
||||
grub_raid_block_mul (raid6_table2[255 - bad1][255 - bad1], buf,
|
||||
grub_crypto_xor (buf, buf, qbuf, size);
|
||||
grub_raid_block_mulx (255 - bad1, buf,
|
||||
size);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Two bad devices */
|
||||
grub_uint8_t c;
|
||||
int c;
|
||||
|
||||
if ((! array->members[p].device) || (! array->members[q].device))
|
||||
{
|
||||
|
@ -188,26 +162,26 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
|
|||
}
|
||||
|
||||
if (grub_disk_read (array->members[p].device,
|
||||
array->members[i].start_sector + sector,
|
||||
array->members[p].start_sector + sector,
|
||||
0, size, buf))
|
||||
goto quit;
|
||||
|
||||
grub_raid_block_xor (pbuf, buf, size);
|
||||
grub_crypto_xor (pbuf, pbuf, buf, size);
|
||||
|
||||
if (grub_disk_read (array->members[q].device,
|
||||
array->members[i].start_sector + sector,
|
||||
array->members[q].start_sector + sector,
|
||||
0, size, buf))
|
||||
goto quit;
|
||||
|
||||
grub_raid_block_xor (qbuf, buf, size);
|
||||
grub_crypto_xor (qbuf, qbuf, buf, size);
|
||||
|
||||
c = raid6_table2[bad2][bad1];
|
||||
grub_raid_block_mul (c, qbuf, size);
|
||||
c = (255 - bad1 + (255 - powx_inv[(powx[bad2 - bad1 + 255] ^ 1)])) % 255;
|
||||
grub_raid_block_mulx (c, qbuf, size);
|
||||
|
||||
c = raid6_table1[raid6_table2[bad2][bad2]][c];
|
||||
grub_raid_block_mul (c, pbuf, size);
|
||||
c = (bad2 + c) % 255;
|
||||
grub_raid_block_mulx (c, pbuf, size);
|
||||
|
||||
grub_raid_block_xor (pbuf, qbuf, size);
|
||||
grub_crypto_xor (pbuf, pbuf, qbuf, size);
|
||||
grub_memcpy (buf, pbuf, size);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,12 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
|
||||
static grub_scsi_dev_t grub_scsi_dev_list;
|
||||
|
||||
const char grub_scsi_names[GRUB_SCSI_NUM_SUBSYSTEMS][5] = {
|
||||
[GRUB_SCSI_SUBSYSTEM_USBMS] = "usb",
|
||||
[GRUB_SCSI_SUBSYSTEM_PATA] = "ata",
|
||||
[GRUB_SCSI_SUBSYSTEM_AHCI] = "ahci"
|
||||
};
|
||||
|
||||
void
|
||||
grub_scsi_dev_register (grub_scsi_dev_t dev)
|
||||
{
|
||||
|
@ -316,13 +322,14 @@ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
|
|||
|
||||
|
||||
static int
|
||||
grub_scsi_iterate (int (*hook) (const char *name))
|
||||
grub_scsi_iterate (int (*hook) (const char *name),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
grub_scsi_dev_t p;
|
||||
|
||||
auto int scsi_iterate (int bus, int luns);
|
||||
auto int NESTED_FUNC_ATTR scsi_iterate (int id, int bus, int luns);
|
||||
|
||||
int scsi_iterate (int bus, int luns)
|
||||
int NESTED_FUNC_ATTR scsi_iterate (int id, int bus, int luns)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -331,7 +338,7 @@ grub_scsi_iterate (int (*hook) (const char *name))
|
|||
{
|
||||
char *sname;
|
||||
int ret;
|
||||
sname = grub_xasprintf ("%s%d", p->name, bus);
|
||||
sname = grub_xasprintf ("%s%d", grub_scsi_names[id], bus);
|
||||
if (!sname)
|
||||
return 1;
|
||||
ret = hook (sname);
|
||||
|
@ -345,7 +352,7 @@ grub_scsi_iterate (int (*hook) (const char *name))
|
|||
{
|
||||
char *sname;
|
||||
int ret;
|
||||
sname = grub_xasprintf ("%s%d%c", p->name, bus, 'a' + i);
|
||||
sname = grub_xasprintf ("%s%d%c", grub_scsi_names[id], bus, 'a' + i);
|
||||
if (!sname)
|
||||
return 1;
|
||||
ret = hook (sname);
|
||||
|
@ -357,7 +364,7 @@ grub_scsi_iterate (int (*hook) (const char *name))
|
|||
}
|
||||
|
||||
for (p = grub_scsi_dev_list; p; p = p->next)
|
||||
if (p->iterate && (p->iterate) (scsi_iterate))
|
||||
if (p->iterate && (p->iterate) (scsi_iterate, pull))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
@ -372,6 +379,7 @@ grub_scsi_open (const char *name, grub_disk_t disk)
|
|||
int lun, bus;
|
||||
grub_uint64_t maxtime;
|
||||
const char *nameend;
|
||||
unsigned id;
|
||||
|
||||
nameend = name + grub_strlen (name) - 1;
|
||||
/* Try to detect a LUN ('a'-'z'), otherwise just use the first
|
||||
|
@ -396,15 +404,25 @@ grub_scsi_open (const char *name, grub_disk_t disk)
|
|||
if (! scsi)
|
||||
return grub_errno;
|
||||
|
||||
for (id = 0; id < ARRAY_SIZE (grub_scsi_names); id++)
|
||||
if (grub_strncmp (grub_scsi_names[id], name, nameend - name) == 0)
|
||||
break;
|
||||
|
||||
if (id == ARRAY_SIZE (grub_scsi_names))
|
||||
{
|
||||
grub_free (scsi);
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
|
||||
}
|
||||
|
||||
for (p = grub_scsi_dev_list; p; p = p->next)
|
||||
{
|
||||
if (grub_strncmp (p->name, name, nameend - name) != 0)
|
||||
continue;
|
||||
if (p->open (id, bus, scsi))
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->open (bus, scsi))
|
||||
continue;
|
||||
|
||||
disk->id = grub_make_scsi_id (p->id, bus, lun);
|
||||
disk->id = grub_make_scsi_id (id, bus, lun);
|
||||
disk->data = scsi;
|
||||
scsi->dev = p;
|
||||
scsi->lun = lun;
|
||||
|
@ -465,22 +483,26 @@ grub_scsi_open (const char *name, grub_disk_t disk)
|
|||
return err;
|
||||
}
|
||||
|
||||
/* SCSI blocks can be something else than 512, although GRUB
|
||||
wants 512 byte blocks. */
|
||||
disk->total_sectors = ((grub_uint64_t)scsi->size
|
||||
* (grub_uint64_t)scsi->blocksize)
|
||||
>> GRUB_DISK_SECTOR_BITS;
|
||||
disk->total_sectors = scsi->size;
|
||||
if (scsi->blocksize & (scsi->blocksize - 1) || !scsi->blocksize)
|
||||
{
|
||||
grub_free (scsi);
|
||||
return grub_error (GRUB_ERR_IO, "invalid sector size %d",
|
||||
scsi->blocksize);
|
||||
}
|
||||
for (disk->log_sector_size = 0;
|
||||
(1 << disk->log_sector_size) < scsi->blocksize;
|
||||
disk->log_sector_size++);
|
||||
|
||||
grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
|
||||
scsi->size, scsi->blocksize);
|
||||
grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n",
|
||||
grub_dprintf ("scsi", "Disk total sectors = %llu\n",
|
||||
(unsigned long long) disk->total_sectors);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_free (scsi);
|
||||
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a SCSI disk");
|
||||
}
|
||||
|
||||
|
@ -503,36 +525,36 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
|
|||
|
||||
scsi = disk->data;
|
||||
|
||||
/* SCSI sectors are variable in size. GRUB uses 512 byte
|
||||
sectors. */
|
||||
if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE)
|
||||
while (size)
|
||||
{
|
||||
unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS;
|
||||
if (spb == 0 || (scsi->blocksize & (GRUB_DISK_SECTOR_SIZE - 1)) != 0)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported SCSI block size");
|
||||
/* PATA doesn't support more than 32K reads.
|
||||
Not sure about AHCI and USB. If it's confirmed that either of
|
||||
them can do bigger reads reliably this value can be moved to 'scsi'
|
||||
structure. */
|
||||
grub_size_t len = 32768 >> disk->log_sector_size;
|
||||
grub_err_t err;
|
||||
if (len > size)
|
||||
len = size;
|
||||
/* Depending on the type, select a read function. */
|
||||
switch (scsi->devtype)
|
||||
{
|
||||
case grub_scsi_devtype_direct:
|
||||
err = grub_scsi_read10 (disk, sector, len, buf);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
|
||||
grub_uint64_t sector_mod = 0;
|
||||
sector = grub_divmod64 (sector, spb, §or_mod);
|
||||
|
||||
if (! (sector_mod == 0 && size % spb == 0))
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unaligned SCSI read not supported");
|
||||
|
||||
size /= spb;
|
||||
case grub_scsi_devtype_cdrom:
|
||||
err = grub_scsi_read12 (disk, sector, len, buf);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
size -= len;
|
||||
sector += len;
|
||||
buf += len << disk->log_sector_size;
|
||||
}
|
||||
|
||||
/* Depending on the type, select a read function. */
|
||||
switch (scsi->devtype)
|
||||
{
|
||||
case grub_scsi_devtype_direct:
|
||||
return grub_scsi_read10 (disk, sector, size, buf);
|
||||
|
||||
case grub_scsi_devtype_cdrom:
|
||||
return grub_scsi_read12 (disk, sector, size, buf);
|
||||
}
|
||||
|
||||
/* XXX: Never reached. */
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
#if 0 /* Workaround - it works - but very slowly, from some reason
|
||||
|
|
|
@ -211,16 +211,20 @@ grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
|||
|
||||
|
||||
static int
|
||||
grub_usbms_iterate (int (*hook) (int bus, int luns))
|
||||
grub_usbms_iterate (int NESTED_FUNC_ATTR (*hook) (int id, int bus, int luns),
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (pull != GRUB_DISK_PULL_NONE)
|
||||
return 0;
|
||||
|
||||
grub_usb_poll_devices ();
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
|
||||
if (grub_usbms_devices[i])
|
||||
{
|
||||
if (hook (i, grub_usbms_devices[i]->luns))
|
||||
if (hook (GRUB_SCSI_SUBSYSTEM_USBMS, i, grub_usbms_devices[i]->luns))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -390,8 +394,12 @@ grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_usbms_open (int devnum, struct grub_scsi *scsi)
|
||||
grub_usbms_open (int id, int devnum, struct grub_scsi *scsi)
|
||||
{
|
||||
if (id != GRUB_SCSI_SUBSYSTEM_USBMS)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||
"not USB Mass Storage device");
|
||||
|
||||
grub_usb_poll_devices ();
|
||||
|
||||
if (!grub_usbms_devices[devnum])
|
||||
|
@ -406,8 +414,6 @@ grub_usbms_open (int devnum, struct grub_scsi *scsi)
|
|||
|
||||
static struct grub_scsi_dev grub_usbms_dev =
|
||||
{
|
||||
.name = "usb",
|
||||
.id = GRUB_SCSI_SUBSYSTEM_USBMS,
|
||||
.iterate = grub_usbms_iterate,
|
||||
.open = grub_usbms_open,
|
||||
.read = grub_usbms_read,
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#define bit_LM (1 << 29)
|
||||
|
||||
char *
|
||||
const char *
|
||||
grub_efiemu_get_default_core_name (void)
|
||||
{
|
||||
|
||||
|
|
|
@ -149,7 +149,8 @@ grub_efiemu_register_configuration_table (grub_efi_guid_t guid,
|
|||
if (! get_table && ! data)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"you must set at least get_table or data");
|
||||
if ((err = grub_efiemu_unregister_configuration_table (guid)))
|
||||
err = grub_efiemu_unregister_configuration_table (guid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tbl = (struct grub_efiemu_configuration_table *) grub_malloc (sizeof (*tbl));
|
||||
|
@ -226,7 +227,7 @@ grub_efiemu_autocore (void)
|
|||
{
|
||||
const char *prefix;
|
||||
char *filename;
|
||||
char *suffix;
|
||||
const char *suffix;
|
||||
grub_err_t err;
|
||||
|
||||
if (grub_efiemu_sizeof_uintn_t () != 0)
|
||||
|
|
|
@ -201,10 +201,10 @@ efiemu_alloc_requests (void)
|
|||
- (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE);
|
||||
if (align_overhead == GRUB_EFIEMU_PAGESIZE)
|
||||
align_overhead = 0;
|
||||
curptr = ((grub_uint8_t *)curptr) + align_overhead;
|
||||
curptr = ((grub_uint8_t *) curptr) + align_overhead;
|
||||
|
||||
/* Add the region to memory map */
|
||||
grub_efiemu_add_to_mmap (PTR_TO_UINT64 (typestart),
|
||||
grub_efiemu_add_to_mmap ((grub_addr_t) typestart,
|
||||
curptr - typestart, reqorder[i]);
|
||||
}
|
||||
|
||||
|
@ -404,7 +404,8 @@ grub_efiemu_mmap_fill (void)
|
|||
GRUB_EFI_ACPI_MEMORY_NVS);
|
||||
|
||||
default:
|
||||
grub_printf ("Unknown memory type %d. Assuming unusable\n", type);
|
||||
grub_dprintf ("efiemu",
|
||||
"Unknown memory type %d. Assuming unusable\n", type);
|
||||
case GRUB_MEMORY_RESERVED:
|
||||
return grub_efiemu_add_to_mmap (addr, size,
|
||||
GRUB_EFI_UNUSABLE_MEMORY);
|
||||
|
|
|
@ -97,10 +97,9 @@ SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks,
|
|||
grub_memcpy (&(conftables[i].vendor_guid), &(cur->guid),
|
||||
sizeof (cur->guid));
|
||||
if (cur->get_table)
|
||||
conftables[i].vendor_table
|
||||
= PTR_TO_UINT64 (cur->get_table (cur->data));
|
||||
conftables[i].vendor_table = (grub_addr_t) cur->get_table (cur->data);
|
||||
else
|
||||
conftables[i].vendor_table = PTR_TO_UINT64 (cur->data);
|
||||
conftables[i].vendor_table = (grub_addr_t) cur->data;
|
||||
}
|
||||
|
||||
err = SUFFIX (grub_efiemu_crc) ();
|
||||
|
|
|
@ -169,7 +169,7 @@ grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
|
|||
else
|
||||
ptv_rels[ptv_written].plustype = 0;
|
||||
|
||||
ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr);
|
||||
ptv_rels[ptv_written].addr = (grub_addr_t) addr;
|
||||
ptv_rels[ptv_written].size = size;
|
||||
ptv_written++;
|
||||
|
||||
|
@ -179,10 +179,10 @@ grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
|
|||
|
||||
/* Compute the value */
|
||||
if (minus_handle)
|
||||
value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle));
|
||||
value -= (grub_addr_t) grub_efiemu_mm_obtain_request (minus_handle);
|
||||
|
||||
if (plus_handle)
|
||||
value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle));
|
||||
value += (grub_addr_t) grub_efiemu_mm_obtain_request (plus_handle);
|
||||
|
||||
/* Write the value */
|
||||
switch (size)
|
||||
|
@ -248,16 +248,16 @@ grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
|
|||
switch (cur_relloc->size)
|
||||
{
|
||||
case 8:
|
||||
*((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
|
||||
*((grub_uint64_t *) (grub_addr_t) cur_relloc->addr) += corr;
|
||||
break;
|
||||
case 4:
|
||||
*((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
|
||||
*((grub_uint32_t *) (grub_addr_t) cur_relloc->addr) += corr;
|
||||
break;
|
||||
case 2:
|
||||
*((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
|
||||
*((grub_uint16_t *) (grub_addr_t) cur_relloc->addr) += corr;
|
||||
break;
|
||||
case 1:
|
||||
*((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
|
||||
*((grub_uint8_t *) (grub_addr_t) cur_relloc->addr) += corr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -608,7 +608,7 @@ grub_font_load (const char *filename)
|
|||
|
||||
if (!font->name)
|
||||
{
|
||||
grub_printf ("Note: Font has no name.\n");
|
||||
grub_dprintf ("font", "Font has no name.\n");
|
||||
font->name = grub_strdup ("Unknown");
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ lsfonts_command (grub_command_t cmd __attribute__ ((unused)),
|
|||
{
|
||||
struct grub_font_node *node;
|
||||
|
||||
grub_printf ("Loaded fonts:\n");
|
||||
grub_puts_ (N_("Loaded fonts:"));
|
||||
for (node = grub_font_list; node; node = node->next)
|
||||
{
|
||||
grub_font_t font = node->value;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <grub/dl.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -32,15 +33,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
struct grub_affs_bblock
|
||||
{
|
||||
grub_uint8_t type[3];
|
||||
grub_uint8_t flags;
|
||||
grub_uint8_t version;
|
||||
grub_uint32_t checksum;
|
||||
grub_uint32_t rootblock;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Set if the filesystem is a AFFS filesystem. Otherwise this is an
|
||||
OFS filesystem. */
|
||||
#define GRUB_AFFS_FLAG_FFS 1
|
||||
|
||||
/* The affs rootblock. */
|
||||
struct grub_affs_rblock
|
||||
{
|
||||
|
@ -85,19 +82,19 @@ struct grub_affs_file
|
|||
#define GRUB_AFFS_BLOCKPTR_OFFSET 24
|
||||
#define GRUB_AFFS_SYMLINK_OFFSET 24
|
||||
|
||||
#define GRUB_AFFS_SYMLINK_SIZE(blocksize) ((blocksize) - 225)
|
||||
|
||||
#define GRUB_AFFS_FILETYPE_DIR -3
|
||||
#define GRUB_AFFS_FILETYPE_REG 2
|
||||
#define GRUB_AFFS_FILETYPE_REG 0xfffffffd
|
||||
#define GRUB_AFFS_FILETYPE_DIR 2
|
||||
#define GRUB_AFFS_FILETYPE_SYMLINK 3
|
||||
|
||||
|
||||
struct grub_fshelp_node
|
||||
{
|
||||
struct grub_affs_data *data;
|
||||
grub_disk_addr_t block;
|
||||
grub_uint32_t block;
|
||||
struct grub_fshelp_node *parent;
|
||||
struct grub_affs_file di;
|
||||
grub_uint32_t *block_cache;
|
||||
grub_uint32_t last_block_cache;
|
||||
};
|
||||
|
||||
/* Information about a "mounted" affs filesystem. */
|
||||
|
@ -120,32 +117,46 @@ static grub_dl_t my_mod;
|
|||
static grub_disk_addr_t
|
||||
grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||
{
|
||||
int links;
|
||||
grub_uint32_t target, curblock;
|
||||
grub_uint32_t pos;
|
||||
int block = node->block;
|
||||
struct grub_affs_file file;
|
||||
struct grub_affs_data *data = node->data;
|
||||
grub_uint64_t mod;
|
||||
|
||||
if (!node->block_cache)
|
||||
{
|
||||
node->block_cache = grub_malloc ((((grub_be_to_cpu32 (node->di.size)
|
||||
+ 511) >> 9) / data->htsize + 1)
|
||||
* sizeof (node->block_cache[0]));
|
||||
if (!node->block_cache)
|
||||
return -1;
|
||||
node->last_block_cache = 0;
|
||||
node->block_cache[0] = node->block;
|
||||
}
|
||||
|
||||
/* Files are at most 2G on AFFS, so no need for 64-bit division. */
|
||||
target = (grub_uint32_t) fileblock / data->htsize;
|
||||
mod = (grub_uint32_t) fileblock % data->htsize;
|
||||
/* Find the block that points to the fileblock we are looking up by
|
||||
following the chain until the right table is reached. */
|
||||
for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--)
|
||||
for (curblock = node->last_block_cache + 1; curblock <= target; curblock++)
|
||||
{
|
||||
grub_disk_read (data->disk, block + data->blocksize - 1,
|
||||
grub_disk_read (data->disk,
|
||||
node->block_cache[curblock - 1] + data->blocksize - 1,
|
||||
data->blocksize * (GRUB_DISK_SECTOR_SIZE
|
||||
- GRUB_AFFS_FILE_LOCATION),
|
||||
sizeof (file), &file);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
||||
block = grub_be_to_cpu32 (file.extension);
|
||||
node->block_cache[curblock] = grub_be_to_cpu32 (file.extension);
|
||||
node->last_block_cache = curblock;
|
||||
}
|
||||
|
||||
/* Translate the fileblock to the block within the right table. */
|
||||
fileblock = mod;
|
||||
grub_disk_read (data->disk, block,
|
||||
grub_disk_read (data->disk, node->block_cache[target],
|
||||
GRUB_AFFS_BLOCKPTR_OFFSET
|
||||
+ (data->htsize - fileblock - 1) * sizeof (pos),
|
||||
+ (data->htsize - mod - 1) * sizeof (pos),
|
||||
sizeof (pos), &pos);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
@ -153,21 +164,6 @@ grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
return grub_be_to_cpu32 (pos);
|
||||
}
|
||||
|
||||
|
||||
/* Read LEN bytes from the file described by DATA starting with byte
|
||||
POS. Return the amount of read bytes in READ. */
|
||||
static grub_ssize_t
|
||||
grub_affs_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_affs_read_block,
|
||||
grub_be_to_cpu32 (node->di.size), 0);
|
||||
}
|
||||
|
||||
|
||||
static struct grub_affs_data *
|
||||
grub_affs_mount (grub_disk_t disk)
|
||||
{
|
||||
|
@ -178,7 +174,7 @@ grub_affs_mount (grub_disk_t disk)
|
|||
int checksum = 0;
|
||||
int blocksize = 0;
|
||||
|
||||
data = grub_malloc (sizeof (struct grub_affs_data));
|
||||
data = grub_zalloc (sizeof (struct grub_affs_data));
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
|
@ -196,18 +192,12 @@ grub_affs_mount (grub_disk_t disk)
|
|||
}
|
||||
|
||||
/* Test if the filesystem is a OFS filesystem. */
|
||||
if (! (data->bblock.flags & GRUB_AFFS_FLAG_FFS))
|
||||
if (data->bblock.version < 1)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "OFS not yet supported");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Read the bootblock. */
|
||||
grub_disk_read (disk, 0, 0, sizeof (struct grub_affs_bblock),
|
||||
&data->bblock);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
/* No sane person uses more than 8KB for a block. At least I hope
|
||||
for that person because in that case this won't work. */
|
||||
rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE * 16);
|
||||
|
@ -270,18 +260,21 @@ grub_affs_read_symlink (grub_fshelp_node_t node)
|
|||
{
|
||||
struct grub_affs_data *data = node->data;
|
||||
char *symlink;
|
||||
const grub_size_t symlink_size = (data->blocksize * GRUB_DISK_SECTOR_SIZE
|
||||
- 225);
|
||||
|
||||
symlink = grub_malloc (GRUB_AFFS_SYMLINK_SIZE (data->blocksize));
|
||||
symlink = grub_malloc (symlink_size + 1);
|
||||
if (!symlink)
|
||||
return 0;
|
||||
|
||||
grub_disk_read (data->disk, node->block, GRUB_AFFS_SYMLINK_OFFSET,
|
||||
GRUB_AFFS_SYMLINK_SIZE (data->blocksize), symlink);
|
||||
symlink_size, symlink);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_free (symlink);
|
||||
return 0;
|
||||
}
|
||||
symlink[symlink_size] = 1;
|
||||
grub_dprintf ("affs", "Symlink: `%s'\n", symlink);
|
||||
return symlink;
|
||||
}
|
||||
|
@ -300,25 +293,25 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
struct grub_affs_data *data = dir->data;
|
||||
grub_uint32_t *hashtable;
|
||||
|
||||
auto int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
||||
grub_disk_addr_t block,
|
||||
auto int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block,
|
||||
const struct grub_affs_file *fil);
|
||||
|
||||
int NESTED_FUNC_ATTR grub_affs_create_node (const char *name,
|
||||
grub_disk_addr_t block,
|
||||
int NESTED_FUNC_ATTR grub_affs_create_node (grub_uint32_t block,
|
||||
const struct grub_affs_file *fil)
|
||||
{
|
||||
int type;
|
||||
node = grub_malloc (sizeof (*node));
|
||||
grub_uint8_t name_u8[sizeof (fil->name) * GRUB_MAX_UTF8_PER_LATIN1 + 1];
|
||||
|
||||
node = grub_zalloc (sizeof (*node));
|
||||
if (!node)
|
||||
{
|
||||
grub_free (hashtable);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((int) grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
|
||||
if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
|
||||
type = GRUB_FSHELP_REG;
|
||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_REG)
|
||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_DIR)
|
||||
type = GRUB_FSHELP_DIR;
|
||||
else if (grub_be_to_cpu32 (fil->type) == GRUB_AFFS_FILETYPE_SYMLINK)
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
|
@ -330,7 +323,10 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
node->di = *fil;
|
||||
node->parent = dir;
|
||||
|
||||
if (hook (name, type, node))
|
||||
*grub_latin1_to_utf8 (name_u8, fil->name,
|
||||
grub_min (fil->namelen, sizeof (fil->name))) = '\0';
|
||||
|
||||
if (hook ((char *) name_u8, type, node))
|
||||
{
|
||||
grub_free (hashtable);
|
||||
return 1;
|
||||
|
@ -339,7 +335,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
}
|
||||
|
||||
/* Create the directory entries for `.' and `..'. */
|
||||
node = grub_malloc (sizeof (*node));
|
||||
node = grub_zalloc (sizeof (*node));
|
||||
if (!node)
|
||||
return 1;
|
||||
|
||||
|
@ -348,7 +344,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 1;
|
||||
if (dir->parent)
|
||||
{
|
||||
node = grub_malloc (sizeof (*node));
|
||||
node = grub_zalloc (sizeof (*node));
|
||||
if (!node)
|
||||
return 1;
|
||||
*node = *dir->parent;
|
||||
|
@ -356,7 +352,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 1;
|
||||
}
|
||||
|
||||
hashtable = grub_malloc (data->htsize * sizeof (*hashtable));
|
||||
hashtable = grub_zalloc (data->htsize * sizeof (*hashtable));
|
||||
if (!hashtable)
|
||||
return 1;
|
||||
|
||||
|
@ -367,7 +363,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
|
||||
for (i = 0; i < data->htsize; i++)
|
||||
{
|
||||
grub_uint64_t next;
|
||||
grub_uint32_t next;
|
||||
|
||||
if (!hashtable[i])
|
||||
continue;
|
||||
|
@ -385,9 +381,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
file.name[file.namelen] = '\0';
|
||||
|
||||
if (grub_affs_create_node ((char *) (file.name), next, &file))
|
||||
if (grub_affs_create_node (next, &file))
|
||||
return 1;
|
||||
|
||||
next = grub_be_to_cpu32 (file.next);
|
||||
|
@ -441,10 +435,13 @@ grub_affs_open (struct grub_file *file, const char *name)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_affs_close (grub_file_t file)
|
||||
{
|
||||
struct grub_affs_data *data =
|
||||
(struct grub_affs_data *) file->data;
|
||||
|
||||
grub_free (data->diropen.block_cache);
|
||||
grub_free (file->data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
@ -452,7 +449,6 @@ grub_affs_close (grub_file_t file)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/* Read LEN bytes data from FILE into BUF. */
|
||||
static grub_ssize_t
|
||||
grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
|
@ -460,13 +456,12 @@ grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
struct grub_affs_data *data =
|
||||
(struct grub_affs_data *) file->data;
|
||||
|
||||
int size = grub_affs_read_file (&data->diropen, file->read_hook,
|
||||
file->offset, len, buf);
|
||||
|
||||
return size;
|
||||
return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen,
|
||||
file->read_hook,
|
||||
file->offset, len, buf, grub_affs_read_block,
|
||||
grub_be_to_cpu32 (data->diropen.di.size), 0);
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_affs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
|
|
|
@ -1,720 +1,3 @@
|
|||
/* afs.c - The native AtheOS file-system. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define MODE_AFS 1
|
||||
#include "bfs.c"
|
||||
|
||||
#include <grub/err.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/fshelp.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#ifdef MODE_BIGENDIAN
|
||||
#define GRUB_AFS_FSNAME_SUFFIX "_be"
|
||||
#else
|
||||
#define GRUB_AFS_FSNAME_SUFFIX ""
|
||||
#endif
|
||||
|
||||
#ifdef MODE_BFS
|
||||
#define GRUB_AFS_FSNAME "befs" GRUB_AFS_FSNAME_SUFFIX
|
||||
#else
|
||||
#define GRUB_AFS_FSNAME "afs" GRUB_AFS_FSNAME_SUFFIX
|
||||
#endif
|
||||
|
||||
#define GRUB_AFS_DIRECT_BLOCK_COUNT 12
|
||||
#define GRUB_AFS_BLOCKS_PER_DI_RUN 4
|
||||
|
||||
#ifdef MODE_BFS
|
||||
#define GRUB_AFS_SBLOCK_SECTOR 1
|
||||
#define GRUB_AFS_SBLOCK_MAGIC1 0x42465331 /* BFS1. */
|
||||
#else
|
||||
#define GRUB_AFS_SBLOCK_SECTOR 2
|
||||
#define GRUB_AFS_SBLOCK_MAGIC1 0x41465331 /* AFS1. */
|
||||
#endif
|
||||
|
||||
#define GRUB_AFS_SBLOCK_MAGIC2 0xdd121031
|
||||
#define GRUB_AFS_SBLOCK_MAGIC3 0x15b6830e
|
||||
|
||||
#define GRUB_AFS_INODE_MAGIC 0x64358428
|
||||
|
||||
#ifdef MODE_BFS
|
||||
#define GRUB_AFS_BTREE_MAGIC 0x69f6c2e8
|
||||
#else
|
||||
#define GRUB_AFS_BTREE_MAGIC 0x65768995
|
||||
#endif
|
||||
|
||||
#define GRUB_AFS_BNODE_SIZE 1024
|
||||
|
||||
#define GRUB_AFS_S_IFMT 00170000
|
||||
#define GRUB_AFS_S_IFLNK 0120000
|
||||
|
||||
#define GRUB_AFS_S_IFREG 0100000
|
||||
#define GRUB_AFS_S_IFDIR 0040000
|
||||
#define GRUB_AFS_S_IFIFO 0010000
|
||||
|
||||
#define GRUB_AFS_NULL_VAL ((grub_afs_bvalue_t)-1)
|
||||
|
||||
#ifdef MODE_BIGENDIAN
|
||||
#define grub_afs_to_cpu16(x) grub_be_to_cpu16 (x)
|
||||
#define grub_afs_to_cpu32(x) grub_be_to_cpu32 (x)
|
||||
#define grub_afs_to_cpu64(x) grub_be_to_cpu64 (x)
|
||||
#else
|
||||
#define grub_afs_to_cpu16(x) grub_le_to_cpu16 (x)
|
||||
#define grub_afs_to_cpu32(x) grub_le_to_cpu32 (x)
|
||||
#define grub_afs_to_cpu64(x) grub_le_to_cpu64 (x)
|
||||
#endif
|
||||
|
||||
#ifdef MODE_BFS
|
||||
#define B_KEY_INDEX_ALIGN 8
|
||||
#else
|
||||
#define B_KEY_INDEX_ALIGN 4
|
||||
#endif
|
||||
|
||||
#define B_KEY_INDEX_OFFSET(node) ((grub_uint16_t *) \
|
||||
((char *) (node) \
|
||||
+ ALIGN_UP (sizeof (struct grub_afs_bnode) \
|
||||
+ node->key_size, \
|
||||
B_KEY_INDEX_ALIGN)))
|
||||
|
||||
#define B_KEY_VALUE_OFFSET(node) ((grub_afs_bvalue_t *) \
|
||||
((char *) B_KEY_INDEX_OFFSET (node) + \
|
||||
node->key_count * 2))
|
||||
|
||||
typedef grub_uint64_t grub_afs_off_t;
|
||||
typedef grub_uint64_t grub_afs_bigtime;
|
||||
typedef grub_uint64_t grub_afs_bvalue_t;
|
||||
|
||||
struct grub_afs_blockrun
|
||||
{
|
||||
grub_uint32_t group;
|
||||
grub_uint16_t start;
|
||||
grub_uint16_t len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_afs_datastream
|
||||
{
|
||||
struct grub_afs_blockrun direct[GRUB_AFS_DIRECT_BLOCK_COUNT];
|
||||
grub_afs_off_t max_direct_range;
|
||||
struct grub_afs_blockrun indirect;
|
||||
grub_afs_off_t max_indirect_range;
|
||||
struct grub_afs_blockrun double_indirect;
|
||||
grub_afs_off_t max_double_indirect_range;
|
||||
grub_afs_off_t size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_afs_bnode
|
||||
{
|
||||
grub_afs_bvalue_t left;
|
||||
grub_afs_bvalue_t right;
|
||||
grub_afs_bvalue_t overflow;
|
||||
#ifdef MODE_BFS
|
||||
grub_uint16_t key_count;
|
||||
grub_uint16_t key_size;
|
||||
#else
|
||||
grub_uint32_t key_count;
|
||||
grub_uint32_t key_size;
|
||||
#endif
|
||||
char key_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#ifdef MODE_BFS
|
||||
struct grub_afs_btree
|
||||
{
|
||||
grub_uint32_t magic;
|
||||
grub_uint32_t unused1;
|
||||
grub_uint32_t tree_depth;
|
||||
grub_uint32_t unused2;
|
||||
grub_afs_bvalue_t root;
|
||||
grub_uint32_t unused3[4];
|
||||
} __attribute__ ((packed));
|
||||
#else
|
||||
struct grub_afs_btree
|
||||
{
|
||||
grub_uint32_t magic;
|
||||
grub_afs_bvalue_t root;
|
||||
grub_uint32_t tree_depth;
|
||||
grub_afs_bvalue_t last_node;
|
||||
grub_afs_bvalue_t first_free;
|
||||
} __attribute__ ((packed));
|
||||
#endif
|
||||
|
||||
/* Beware that following structure describes AtheFS and if you write code
|
||||
which uses currently unused fields check it with both AtheFS and BeFS.
|
||||
*/
|
||||
struct grub_afs_sblock
|
||||
{
|
||||
char name[32];
|
||||
grub_uint32_t magic1;
|
||||
grub_uint32_t byte_order;
|
||||
grub_uint32_t block_size;
|
||||
grub_uint32_t block_shift;
|
||||
grub_afs_off_t num_blocks;
|
||||
grub_afs_off_t used_blocks;
|
||||
grub_uint32_t inode_size;
|
||||
grub_uint32_t magic2;
|
||||
grub_uint32_t block_per_group; /* Number of blocks per allocation
|
||||
group. (Max 65536) */
|
||||
grub_uint32_t alloc_group_shift; /* Number of bits to shift a group
|
||||
number to get a byte address. */
|
||||
grub_uint32_t alloc_group_count;
|
||||
grub_uint32_t flags;
|
||||
struct grub_afs_blockrun log_block;
|
||||
grub_afs_off_t log_start;
|
||||
grub_uint32_t valid_log_blocks;
|
||||
grub_uint32_t log_size;
|
||||
grub_uint32_t magic3;
|
||||
struct grub_afs_blockrun root_dir; /* Root dir inode. */
|
||||
struct grub_afs_blockrun deleted_files; /* Directory containing files
|
||||
scheduled for deletion. */
|
||||
struct grub_afs_blockrun index_dir; /* Directory of index files. */
|
||||
grub_uint32_t boot_loader_size;
|
||||
grub_uint32_t pad[7];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_afs_inode
|
||||
{
|
||||
grub_uint32_t magic1;
|
||||
struct grub_afs_blockrun inode_num;
|
||||
grub_uint32_t uid;
|
||||
grub_uint32_t gid;
|
||||
grub_uint32_t mode;
|
||||
grub_uint32_t flags;
|
||||
#ifndef MODE_BFS
|
||||
grub_uint32_t link_count;
|
||||
#endif
|
||||
grub_afs_bigtime create_time;
|
||||
grub_afs_bigtime modified_time;
|
||||
struct grub_afs_blockrun parent;
|
||||
struct grub_afs_blockrun attrib_dir;
|
||||
grub_uint32_t index_type; /* Key data-key only used for index files. */
|
||||
grub_uint32_t inode_size;
|
||||
grub_uint32_t unused;
|
||||
struct grub_afs_datastream stream;
|
||||
grub_uint32_t pad[4];
|
||||
grub_uint32_t small_data[1];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_fshelp_node
|
||||
{
|
||||
struct grub_afs_data *data;
|
||||
struct grub_afs_inode inode;
|
||||
};
|
||||
|
||||
struct grub_afs_data
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_afs_sblock sblock;
|
||||
struct grub_afs_inode *inode;
|
||||
struct grub_fshelp_node diropen;
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
static grub_afs_off_t
|
||||
grub_afs_run_to_num (struct grub_afs_sblock *sb,
|
||||
struct grub_afs_blockrun *run)
|
||||
{
|
||||
return ((grub_afs_off_t) grub_afs_to_cpu32 (run->group)
|
||||
* sb->block_per_group + grub_afs_to_cpu16 (run->start));
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_afs_read_inode (struct grub_afs_data *data,
|
||||
grub_uint32_t ino, struct grub_afs_inode *inode)
|
||||
{
|
||||
return grub_disk_read (data->disk,
|
||||
ino *
|
||||
(data->sblock.block_size >> GRUB_DISK_SECTOR_BITS),
|
||||
0, sizeof (struct grub_afs_inode),
|
||||
inode);
|
||||
}
|
||||
|
||||
static grub_disk_addr_t
|
||||
grub_afs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||
{
|
||||
struct grub_afs_sblock *sb = &node->data->sblock;
|
||||
struct grub_afs_datastream *ds = &node->inode.stream;
|
||||
|
||||
if (fileblock < grub_afs_to_cpu64 (ds->max_direct_range))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GRUB_AFS_DIRECT_BLOCK_COUNT; i++)
|
||||
{
|
||||
if (fileblock < grub_afs_to_cpu16 (ds->direct[i].len))
|
||||
return grub_afs_run_to_num (sb, &ds->direct[i]) + fileblock;
|
||||
fileblock -= grub_afs_to_cpu16 (ds->direct[i].len);
|
||||
}
|
||||
}
|
||||
else if (fileblock < grub_afs_to_cpu64 (ds->max_indirect_range))
|
||||
{
|
||||
int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun);
|
||||
struct grub_afs_blockrun indir[ptrs_per_blk];
|
||||
grub_afs_off_t blk = grub_afs_run_to_num (sb, &ds->indirect);
|
||||
int i;
|
||||
|
||||
fileblock -= grub_afs_to_cpu64 (ds->max_direct_range);
|
||||
for (i = 0; i < ds->indirect.len; i++, blk++)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (grub_disk_read (node->data->disk,
|
||||
blk * (sb->block_size >> GRUB_DISK_SECTOR_BITS),
|
||||
0, sizeof (indir),
|
||||
indir))
|
||||
return 0;
|
||||
|
||||
for (j = 0; j < ptrs_per_blk; j++)
|
||||
{
|
||||
if (fileblock < grub_afs_to_cpu16 (indir[j].len))
|
||||
return grub_afs_run_to_num (sb, &indir[j]) + fileblock;
|
||||
|
||||
fileblock -= grub_afs_to_cpu16 (indir[j].len);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun);
|
||||
struct grub_afs_blockrun indir[ptrs_per_blk];
|
||||
|
||||
/* ([idblk][idptr]) ([dblk][dptr]) [blk] */
|
||||
int cur_pos = fileblock - grub_afs_to_cpu64 (ds->max_indirect_range);
|
||||
|
||||
int dptr_size = GRUB_AFS_BLOCKS_PER_DI_RUN;
|
||||
int dblk_size = dptr_size * ptrs_per_blk;
|
||||
int idptr_size = dblk_size * GRUB_AFS_BLOCKS_PER_DI_RUN;
|
||||
int idblk_size = idptr_size * ptrs_per_blk;
|
||||
|
||||
int off = cur_pos % GRUB_AFS_BLOCKS_PER_DI_RUN;
|
||||
int dptr = (cur_pos / dptr_size) % ptrs_per_blk;
|
||||
int dblk = (cur_pos / dblk_size) % GRUB_AFS_BLOCKS_PER_DI_RUN;
|
||||
int idptr = (cur_pos / idptr_size) % ptrs_per_blk;
|
||||
int idblk = (cur_pos / idblk_size);
|
||||
|
||||
if (grub_disk_read (node->data->disk,
|
||||
(grub_afs_run_to_num (sb, &ds->double_indirect)
|
||||
+ idblk) *
|
||||
(sb->block_size >> GRUB_DISK_SECTOR_BITS),
|
||||
0, sizeof (indir),
|
||||
indir))
|
||||
return 0;
|
||||
|
||||
if (grub_disk_read (node->data->disk,
|
||||
(grub_afs_run_to_num (sb, &indir[idptr]) + dblk) *
|
||||
(sb->block_size >> GRUB_DISK_SECTOR_BITS),
|
||||
0, sizeof (indir),
|
||||
indir))
|
||||
return 0;
|
||||
|
||||
return grub_afs_run_to_num (sb, &indir[dptr]) + off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_afs_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_afs_read_block,
|
||||
grub_afs_to_cpu64 (node->inode.stream.size),
|
||||
node->data->sblock.block_shift
|
||||
- GRUB_DISK_SECTOR_BITS);
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_afs_read_symlink (grub_fshelp_node_t node)
|
||||
{
|
||||
char *ret;
|
||||
grub_afs_off_t size = grub_afs_to_cpu64 (node->inode.stream.size);
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
size = sizeof (node->inode.stream);
|
||||
ret = grub_zalloc (size + 1);
|
||||
if (! ret)
|
||||
return 0;
|
||||
grub_memcpy (ret, (char *) &(node->inode.stream),
|
||||
sizeof (node->inode.stream));
|
||||
return ret;
|
||||
}
|
||||
ret = grub_zalloc (size + 1);
|
||||
if (! ret)
|
||||
return 0;
|
||||
grub_afs_read_file (node, 0, 0, size, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_afs_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
{
|
||||
struct grub_afs_btree head;
|
||||
char node_data [GRUB_AFS_BNODE_SIZE];
|
||||
struct grub_afs_bnode *node = (struct grub_afs_bnode *) node_data;
|
||||
int i;
|
||||
|
||||
if ((dir->inode.stream.size == 0)
|
||||
|| ((grub_afs_to_cpu32 (dir->inode.mode) & GRUB_AFS_S_IFMT)
|
||||
!= GRUB_AFS_S_IFDIR))
|
||||
return 0;
|
||||
|
||||
grub_afs_read_file (dir, 0, 0, sizeof (head), (char *) &head);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
||||
grub_afs_read_file (dir, 0, grub_afs_to_cpu64 (head.root),
|
||||
GRUB_AFS_BNODE_SIZE, (char *) node);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < (int) grub_afs_to_cpu32 (head.tree_depth) - 1; i++)
|
||||
{
|
||||
grub_afs_bvalue_t blk;
|
||||
|
||||
blk = grub_afs_to_cpu64(B_KEY_VALUE_OFFSET (node) [0]);
|
||||
grub_afs_read_file (dir, 0, blk, GRUB_AFS_BNODE_SIZE, (char *) node);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (node->key_count)
|
||||
{
|
||||
grub_uint32_t cur_key = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int key_start, key_size;
|
||||
grub_uint16_t *index;
|
||||
|
||||
index = B_KEY_INDEX_OFFSET (node);
|
||||
|
||||
key_start = (cur_key > 0)
|
||||
? grub_afs_to_cpu16 (index[cur_key - 1]) : 0;
|
||||
key_size = grub_afs_to_cpu16 (index[cur_key]) - key_start;
|
||||
if (key_size > 0)
|
||||
{
|
||||
char filename [key_size + 1];
|
||||
struct grub_fshelp_node *fdiro;
|
||||
int mode, type;
|
||||
|
||||
fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
|
||||
if (! fdiro)
|
||||
return 0;
|
||||
|
||||
fdiro->data = dir->data;
|
||||
if (grub_afs_read_inode (dir->data,
|
||||
grub_afs_to_cpu64
|
||||
(B_KEY_VALUE_OFFSET (node) [cur_key]),
|
||||
&fdiro->inode))
|
||||
return 0;
|
||||
|
||||
grub_memcpy (filename, &node->key_data[key_start], key_size);
|
||||
filename [key_size] = 0;
|
||||
|
||||
mode = (grub_afs_to_cpu32 (fdiro->inode.mode) & GRUB_AFS_S_IFMT);
|
||||
if (mode == GRUB_AFS_S_IFDIR)
|
||||
type = GRUB_FSHELP_DIR;
|
||||
else if (mode == GRUB_AFS_S_IFREG)
|
||||
type = GRUB_FSHELP_REG;
|
||||
else if (mode == GRUB_AFS_S_IFLNK)
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
else
|
||||
type = GRUB_FSHELP_UNKNOWN;
|
||||
|
||||
if (hook (filename, type, fdiro))
|
||||
return 1;
|
||||
}
|
||||
|
||||
cur_key++;
|
||||
if (cur_key >= grub_afs_to_cpu32 (node->key_count))
|
||||
{
|
||||
if (node->right == GRUB_AFS_NULL_VAL)
|
||||
break;
|
||||
|
||||
grub_afs_read_file (dir, 0, grub_afs_to_cpu64 (node->right),
|
||||
GRUB_AFS_BNODE_SIZE, (char *) node);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
||||
cur_key = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_afs_validate_sblock (struct grub_afs_sblock *sb)
|
||||
{
|
||||
if (grub_afs_to_cpu32 (sb->magic1) == GRUB_AFS_SBLOCK_MAGIC1)
|
||||
{
|
||||
sb->magic2 = grub_afs_to_cpu32 (sb->magic2);
|
||||
sb->magic3 = grub_afs_to_cpu32 (sb->magic3);
|
||||
sb->block_shift = grub_afs_to_cpu32 (sb->block_shift);
|
||||
sb->block_size = grub_afs_to_cpu32 (sb->block_size);
|
||||
sb->used_blocks = grub_afs_to_cpu64 (sb->used_blocks);
|
||||
sb->num_blocks = grub_afs_to_cpu64 (sb->num_blocks);
|
||||
sb->inode_size = grub_afs_to_cpu32 (sb->inode_size);
|
||||
sb->alloc_group_count = grub_afs_to_cpu32 (sb->alloc_group_count);
|
||||
sb->alloc_group_shift = grub_afs_to_cpu32 (sb->alloc_group_shift);
|
||||
sb->block_per_group = grub_afs_to_cpu32 (sb->block_per_group);
|
||||
sb->alloc_group_count = grub_afs_to_cpu32 (sb->alloc_group_count);
|
||||
sb->log_size = grub_afs_to_cpu32 (sb->log_size);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if ((sb->magic2 != GRUB_AFS_SBLOCK_MAGIC2) ||
|
||||
(sb->magic3 != GRUB_AFS_SBLOCK_MAGIC3))
|
||||
return 0;
|
||||
|
||||
#ifdef MODE_BFS
|
||||
sb->block_per_group = 1 << (sb->alloc_group_shift);
|
||||
#endif
|
||||
|
||||
if (((grub_uint32_t) (1 << sb->block_shift) != sb->block_size)
|
||||
|| (sb->used_blocks > sb->num_blocks )
|
||||
|| (sb->inode_size != sb->block_size)
|
||||
|| (0 == sb->block_size)
|
||||
#ifndef MODE_BFS
|
||||
|| ((grub_uint32_t) (1 << sb->alloc_group_shift) !=
|
||||
sb->block_per_group * sb->block_size)
|
||||
|| (sb->alloc_group_count * sb->block_per_group < sb->num_blocks)
|
||||
|| (grub_afs_to_cpu16 (sb->log_block.len) != sb->log_size)
|
||||
|| (grub_afs_to_cpu32 (sb->valid_log_blocks) > sb->log_size)
|
||||
#endif
|
||||
)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct grub_afs_data *
|
||||
grub_afs_mount (grub_disk_t disk)
|
||||
{
|
||||
struct grub_afs_data *data = 0;
|
||||
|
||||
data = grub_malloc (sizeof (struct grub_afs_data));
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
/* Read the superblock. */
|
||||
if (grub_disk_read (disk, GRUB_AFS_SBLOCK_SECTOR, 0,
|
||||
sizeof (struct grub_afs_sblock), &data->sblock))
|
||||
goto fail;
|
||||
|
||||
if (! grub_afs_validate_sblock (&data->sblock))
|
||||
goto fail;
|
||||
|
||||
data->diropen.data = data;
|
||||
data->inode = &data->diropen.inode;
|
||||
data->disk = disk;
|
||||
|
||||
if (grub_afs_read_inode (data,
|
||||
grub_afs_run_to_num (&data->sblock,
|
||||
&data->sblock.root_dir),
|
||||
data->inode))
|
||||
goto fail;
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
grub_error (GRUB_ERR_BAD_FS, "not an " GRUB_AFS_FSNAME " filesystem");
|
||||
|
||||
grub_free (data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_afs_open (struct grub_file *file, const char *name)
|
||||
{
|
||||
struct grub_afs_data *data;
|
||||
struct grub_fshelp_node *fdiro = 0;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
data = grub_afs_mount (file->device->disk);
|
||||
if (! data)
|
||||
goto fail;
|
||||
|
||||
grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_afs_iterate_dir,
|
||||
grub_afs_read_symlink, GRUB_FSHELP_REG);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_afs_inode));
|
||||
grub_free (fdiro);
|
||||
|
||||
file->size = grub_afs_to_cpu64 (data->inode->stream.size);
|
||||
file->data = data;
|
||||
file->offset = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_afs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_afs_data *data = (struct grub_afs_data *) file->data;
|
||||
|
||||
return grub_afs_read_file (&data->diropen, file->read_hook,
|
||||
file->offset, len, buf);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_afs_close (grub_file_t file)
|
||||
{
|
||||
grub_free (file->data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_afs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
struct grub_afs_data *data = 0;
|
||||
struct grub_fshelp_node *fdiro = 0;
|
||||
|
||||
auto int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node);
|
||||
|
||||
int NESTED_FUNC_ATTR iterate (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = 1;
|
||||
#ifdef MODE_BFS
|
||||
info.mtime = grub_afs_to_cpu64 (node->inode.modified_time) >> 16;
|
||||
#else
|
||||
info.mtime = grub_divmod64 (grub_afs_to_cpu64 (node->inode.modified_time),
|
||||
1000000, 0);
|
||||
#endif
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
}
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
data = grub_afs_mount (device->disk);
|
||||
if (! data)
|
||||
goto fail;
|
||||
|
||||
grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_afs_iterate_dir,
|
||||
grub_afs_read_symlink, GRUB_FSHELP_DIR);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
grub_afs_iterate_dir (fdiro, iterate);
|
||||
|
||||
if (fdiro != &data->diropen)
|
||||
grub_free (fdiro);
|
||||
|
||||
fail:
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_afs_label (grub_device_t device, char **label)
|
||||
{
|
||||
struct grub_afs_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
data = grub_afs_mount (disk);
|
||||
if (data)
|
||||
*label = grub_strndup (data->sblock.name, sizeof (data->sblock.name));
|
||||
else
|
||||
*label = NULL;
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
grub_free (data);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
||||
static struct grub_fs grub_afs_fs = {
|
||||
.name = GRUB_AFS_FSNAME,
|
||||
.dir = grub_afs_dir,
|
||||
.open = grub_afs_open,
|
||||
.read = grub_afs_read,
|
||||
.close = grub_afs_close,
|
||||
.label = grub_afs_label,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
#if defined (MODE_BIGENDIAN) && defined (MODE_BFS)
|
||||
GRUB_MOD_INIT (befs_be)
|
||||
#elif defined (MODE_BFS)
|
||||
GRUB_MOD_INIT (befs)
|
||||
#elif defined (MODE_BIGENDIAN)
|
||||
GRUB_MOD_INIT (afs_be)
|
||||
#else
|
||||
GRUB_MOD_INIT (afs)
|
||||
#endif
|
||||
{
|
||||
grub_fs_register (&grub_afs_fs);
|
||||
my_mod = mod;
|
||||
}
|
||||
|
||||
#if defined (MODE_BIGENDIAN) && defined (MODE_BFS)
|
||||
GRUB_MOD_FINI (befs_be)
|
||||
#elif defined (MODE_BFS)
|
||||
GRUB_MOD_FINI (befs)
|
||||
#elif defined (MODE_BIGENDIAN)
|
||||
GRUB_MOD_FINI (afs_be)
|
||||
#else
|
||||
GRUB_MOD_FINI (afs)
|
||||
#endif
|
||||
{
|
||||
grub_fs_unregister (&grub_afs_fs);
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
/* befs.c - The native BeOS/Haiku file-system. */
|
||||
#define MODE_BFS 1
|
||||
#include "afs.c"
|
|
@ -1,4 +0,0 @@
|
|||
/* befs.c - The native BeOS/Haiku file-system. */
|
||||
#define MODE_BFS 1
|
||||
#define MODE_BIGENDIAN 1
|
||||
#include "afs.c"
|
1050
grub-core/fs/bfs.c
Normal file
1050
grub-core/fs/bfs.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -26,11 +26,23 @@
|
|||
#include <grub/types.h>
|
||||
#include <grub/lib/crc.h>
|
||||
#include <grub/deflate.h>
|
||||
#include <minilzo.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_BTRFS_SIGNATURE "_BHRfS_M"
|
||||
|
||||
/* From http://www.oberhumer.com/opensource/lzo/lzofaq.php
|
||||
* LZO will expand incompressible data by a little amount. I still haven't
|
||||
* computed the exact values, but I suggest using these formulas for
|
||||
* a worst-case expansion calculation:
|
||||
*
|
||||
* output_block_size = input_block_size + (input_block_size / 16) + 64 + 3
|
||||
* */
|
||||
#define GRUB_BTRFS_LZO_BLOCK_SIZE 4096
|
||||
#define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
|
||||
(GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
|
||||
|
||||
typedef grub_uint8_t grub_btrfs_checksum_t[0x20];
|
||||
typedef grub_uint16_t grub_btrfs_uuid_t[8];
|
||||
|
||||
|
@ -41,7 +53,7 @@ struct grub_btrfs_device
|
|||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_btrfs_superblock
|
||||
{
|
||||
{
|
||||
grub_btrfs_checksum_t checksum;
|
||||
grub_btrfs_uuid_t uuid;
|
||||
grub_uint8_t dummy[0x10];
|
||||
|
@ -160,7 +172,8 @@ struct grub_btrfs_leaf_descriptor
|
|||
{
|
||||
unsigned depth;
|
||||
unsigned allocated;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
grub_disk_addr_t addr;
|
||||
unsigned iter;
|
||||
unsigned maxiter;
|
||||
|
@ -179,7 +192,7 @@ struct grub_btrfs_time
|
|||
{
|
||||
grub_int64_t sec;
|
||||
grub_uint32_t nanosec;
|
||||
} __attribute__ ((aligned(4)));
|
||||
} __attribute__ ((aligned (4)));
|
||||
|
||||
struct grub_btrfs_inode
|
||||
{
|
||||
|
@ -215,12 +228,13 @@ struct grub_btrfs_extent_data
|
|||
|
||||
#define GRUB_BTRFS_COMPRESSION_NONE 0
|
||||
#define GRUB_BTRFS_COMPRESSION_ZLIB 1
|
||||
#define GRUB_BTRFS_COMPRESSION_LZO 2
|
||||
|
||||
#define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
|
||||
|
||||
static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2,
|
||||
256 * 1048576 * 2,
|
||||
1048576ULL * 1048576ULL * 2 };
|
||||
256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
||||
|
@ -283,7 +297,7 @@ free_iterator (struct grub_btrfs_leaf_descriptor *desc)
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
save_ref (struct grub_btrfs_leaf_descriptor *desc,
|
||||
save_ref (struct grub_btrfs_leaf_descriptor *desc,
|
||||
grub_disk_addr_t addr, unsigned i, unsigned m, int l)
|
||||
{
|
||||
desc->depth++;
|
||||
|
@ -307,7 +321,7 @@ save_ref (struct grub_btrfs_leaf_descriptor *desc,
|
|||
static int
|
||||
next (struct grub_btrfs_data *data,
|
||||
struct grub_btrfs_leaf_descriptor *desc,
|
||||
grub_disk_addr_t *outaddr, grub_size_t *outsize,
|
||||
grub_disk_addr_t * outaddr, grub_size_t * outsize,
|
||||
struct grub_btrfs_key *key_out)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
@ -330,17 +344,17 @@ next (struct grub_btrfs_data *data,
|
|||
err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter
|
||||
* sizeof (node)
|
||||
+ sizeof (struct btrfs_header)
|
||||
+ desc->data[desc->depth - 1].addr, &node,
|
||||
sizeof (node));
|
||||
+ desc->data[desc->depth - 1].addr,
|
||||
&node, sizeof (node));
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (node.addr), &head,
|
||||
sizeof (head));
|
||||
err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (node.addr),
|
||||
&head, sizeof (head));
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
save_ref (desc, grub_le_to_cpu64 (node.addr), 0,
|
||||
save_ref (desc, grub_le_to_cpu64 (node.addr), 0,
|
||||
grub_le_to_cpu32 (head.nitems), !head.level);
|
||||
}
|
||||
err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter
|
||||
|
@ -354,12 +368,12 @@ next (struct grub_btrfs_data *data,
|
|||
*outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header)
|
||||
+ grub_le_to_cpu32 (leaf.offset);
|
||||
*key_out = leaf.key;
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
lower_bound (struct grub_btrfs_data *data,
|
||||
const struct grub_btrfs_key *key_in,
|
||||
const struct grub_btrfs_key *key_in,
|
||||
struct grub_btrfs_key *key_out,
|
||||
grub_disk_addr_t root,
|
||||
grub_disk_addr_t *outaddr, grub_size_t *outsize,
|
||||
|
@ -410,8 +424,9 @@ lower_bound (struct grub_btrfs_data *data,
|
|||
grub_dprintf ("btrfs",
|
||||
"internal node (depth %d) %" PRIxGRUB_UINT64_T
|
||||
" %x %" PRIxGRUB_UINT64_T "\n", depth,
|
||||
node.key.object_id, node.key.type, node.key.offset);
|
||||
|
||||
node.key.object_id, node.key.type,
|
||||
node.key.offset);
|
||||
|
||||
if (key_cmp (&node.key, key_in) == 0)
|
||||
{
|
||||
err = GRUB_ERR_NONE;
|
||||
|
@ -433,7 +448,7 @@ lower_bound (struct grub_btrfs_data *data,
|
|||
err = GRUB_ERR_NONE;
|
||||
if (desc)
|
||||
err = save_ref (desc, addr - sizeof (head), i - 1,
|
||||
grub_le_to_cpu32 (head.nitems), 0);
|
||||
grub_le_to_cpu32 (head.nitems), 0);
|
||||
if (err)
|
||||
return err;
|
||||
addr = grub_le_to_cpu64 (node_last.addr);
|
||||
|
@ -457,7 +472,7 @@ lower_bound (struct grub_btrfs_data *data,
|
|||
&leaf, sizeof (leaf));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
grub_dprintf ("btrfs",
|
||||
"leaf (depth %d) %" PRIxGRUB_UINT64_T
|
||||
" %x %" PRIxGRUB_UINT64_T "\n", depth,
|
||||
|
@ -465,31 +480,31 @@ lower_bound (struct grub_btrfs_data *data,
|
|||
|
||||
if (key_cmp (&leaf.key, key_in) == 0)
|
||||
{
|
||||
grub_memcpy (key_out, &leaf.key, sizeof(*key_out));
|
||||
grub_memcpy (key_out, &leaf.key, sizeof (*key_out));
|
||||
*outsize = grub_le_to_cpu32 (leaf.size);
|
||||
*outaddr = addr + grub_le_to_cpu32 (leaf.offset);
|
||||
if (desc)
|
||||
return save_ref (desc, addr - sizeof (head), i,
|
||||
grub_le_to_cpu32 (head.nitems), 1);
|
||||
return GRUB_ERR_NONE;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
if (key_cmp (&leaf.key, key_in) > 0)
|
||||
break;
|
||||
|
||||
|
||||
have_last = 1;
|
||||
leaf_last = leaf;
|
||||
}
|
||||
|
||||
if (have_last)
|
||||
{
|
||||
grub_memcpy (key_out, &leaf_last.key, sizeof(*key_out));
|
||||
grub_memcpy (key_out, &leaf_last.key, sizeof (*key_out));
|
||||
*outsize = grub_le_to_cpu32 (leaf_last.size);
|
||||
*outaddr = addr + grub_le_to_cpu32 (leaf_last.offset);
|
||||
if (desc)
|
||||
return save_ref (desc, addr - sizeof (head), i - 1,
|
||||
grub_le_to_cpu32 (head.nitems), 1);
|
||||
return GRUB_ERR_NONE;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
*outsize = 0;
|
||||
*outaddr = 0;
|
||||
|
@ -503,8 +518,7 @@ lower_bound (struct grub_btrfs_data *data,
|
|||
}
|
||||
|
||||
static grub_device_t
|
||||
find_device (struct grub_btrfs_data *data, grub_uint64_t id,
|
||||
int do_rescan)
|
||||
find_device (struct grub_btrfs_data *data, grub_uint64_t id, int do_rescan)
|
||||
{
|
||||
grub_device_t dev_found = NULL;
|
||||
auto int hook (const char *name);
|
||||
|
@ -540,7 +554,7 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t id,
|
|||
grub_device_close (dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
dev_found = dev;
|
||||
return 1;
|
||||
}
|
||||
|
@ -579,17 +593,16 @@ find_device (struct grub_btrfs_data *data, grub_uint64_t id,
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
||||
grub_disk_addr_t addr,
|
||||
grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
|
||||
void *buf, grub_size_t size)
|
||||
{
|
||||
while (size > 0)
|
||||
{
|
||||
grub_uint8_t *ptr;
|
||||
struct grub_btrfs_key *key;
|
||||
struct grub_btrfs_chunk_item *chunk;
|
||||
struct grub_btrfs_chunk_item *chunk;
|
||||
grub_uint64_t csize;
|
||||
grub_err_t err = 0;
|
||||
grub_err_t err = 0;
|
||||
struct grub_btrfs_key key_out;
|
||||
int challoc = 0;
|
||||
grub_device_t dev;
|
||||
|
@ -601,15 +614,15 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
|||
addr);
|
||||
for (ptr = data->sblock.bootstrap_mapping;
|
||||
ptr < data->sblock.bootstrap_mapping
|
||||
+ sizeof (data->sblock.bootstrap_mapping)
|
||||
- sizeof (struct grub_btrfs_key);
|
||||
)
|
||||
+ sizeof (data->sblock.bootstrap_mapping)
|
||||
- sizeof (struct grub_btrfs_key);)
|
||||
{
|
||||
key = (struct grub_btrfs_key *) ptr;
|
||||
if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK)
|
||||
break;
|
||||
chunk = (struct grub_btrfs_chunk_item *) (key + 1);
|
||||
grub_dprintf ("btrfs", "%" PRIxGRUB_UINT64_T " %" PRIxGRUB_UINT64_T " \n",
|
||||
grub_dprintf ("btrfs",
|
||||
"%" PRIxGRUB_UINT64_T " %" PRIxGRUB_UINT64_T " \n",
|
||||
grub_le_to_cpu64 (key->offset),
|
||||
grub_le_to_cpu64 (chunk->size));
|
||||
if (grub_le_to_cpu64 (key->offset) <= addr
|
||||
|
@ -704,11 +717,11 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
|||
middle = grub_divmod64 (off,
|
||||
grub_le_to_cpu64 (chunk->stripe_length),
|
||||
&low);
|
||||
|
||||
|
||||
high = grub_divmod64 (middle, grub_le_to_cpu16 (chunk->nstripes),
|
||||
&stripen);
|
||||
stripe_offset = low + grub_le_to_cpu64 (chunk->stripe_length)
|
||||
* high;
|
||||
stripe_offset =
|
||||
low + grub_le_to_cpu64 (chunk->stripe_length) * high;
|
||||
csize = grub_le_to_cpu64 (chunk->stripe_length) - low;
|
||||
break;
|
||||
}
|
||||
|
@ -719,14 +732,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
|||
middle = grub_divmod64 (off,
|
||||
grub_le_to_cpu64 (chunk->stripe_length),
|
||||
&low);
|
||||
|
||||
|
||||
high = grub_divmod64 (middle,
|
||||
grub_le_to_cpu16 (chunk->nsubstripes),
|
||||
grub_le_to_cpu16 (chunk->nstripes)
|
||||
/ grub_le_to_cpu16 (chunk->nsubstripes),
|
||||
&stripen);
|
||||
stripen *= grub_le_to_cpu16 (chunk->nstripes)
|
||||
/ grub_le_to_cpu16 (chunk->nsubstripes);
|
||||
redundancy = grub_le_to_cpu16 (chunk->nstripes)
|
||||
/ grub_le_to_cpu16 (chunk->nsubstripes);
|
||||
stripen *= grub_le_to_cpu16 (chunk->nsubstripes);
|
||||
redundancy = grub_le_to_cpu16 (chunk->nsubstripes);
|
||||
stripe_offset = low + grub_le_to_cpu64 (chunk->stripe_length)
|
||||
* high;
|
||||
csize = grub_le_to_cpu64 (chunk->stripe_length) - low;
|
||||
|
@ -759,7 +771,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
|||
paddr = stripe->offset + stripe_offset;
|
||||
|
||||
grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
|
||||
"+0x%" PRIxGRUB_UINT64_T " (%d stripes (%d substripes) of %"
|
||||
"+0x%" PRIxGRUB_UINT64_T
|
||||
" (%d stripes (%d substripes) of %"
|
||||
PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT64_T
|
||||
" maps to 0x%" PRIxGRUB_UINT64_T "\n",
|
||||
grub_le_to_cpu64 (key->offset),
|
||||
|
@ -769,7 +782,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data,
|
|||
grub_le_to_cpu64 (chunk->stripe_length),
|
||||
stripen, stripe->offset);
|
||||
grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T
|
||||
" for laddr 0x%" PRIxGRUB_UINT64_T"\n", paddr,
|
||||
" for laddr 0x%" PRIxGRUB_UINT64_T "\n", paddr,
|
||||
addr);
|
||||
|
||||
dev = find_device (data, stripe->device_id, j);
|
||||
|
@ -815,7 +828,7 @@ grub_btrfs_mount (grub_device_t dev)
|
|||
}
|
||||
|
||||
data = grub_zalloc (sizeof (*data));
|
||||
if (! data)
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
err = read_sblock (dev->disk, &data->sblock);
|
||||
|
@ -866,8 +879,7 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data,
|
|||
key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM;
|
||||
key_in.offset = 0;
|
||||
|
||||
err = lower_bound (data, &key_in, &key_out, tree,
|
||||
&elemaddr, &elemsize, NULL);
|
||||
err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
if (num != key_out.object_id
|
||||
|
@ -877,6 +889,76 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data,
|
|||
return grub_btrfs_read_logical (data, elemaddr, inode, sizeof (*inode));
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_btrfs_lzo_decompress(char *ibuf, grub_size_t isize, grub_off_t off,
|
||||
char *obuf, grub_size_t osize)
|
||||
{
|
||||
grub_uint32_t total_size, cblock_size, ret = 0;
|
||||
unsigned char buf[GRUB_BTRFS_LZO_BLOCK_SIZE];
|
||||
|
||||
total_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
|
||||
ibuf += sizeof (total_size);
|
||||
|
||||
if (isize < total_size)
|
||||
return -1;
|
||||
|
||||
/* Jump forward to first block with requested data. */
|
||||
while (off >= GRUB_BTRFS_LZO_BLOCK_SIZE)
|
||||
{
|
||||
cblock_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
|
||||
ibuf += sizeof (cblock_size);
|
||||
|
||||
if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE)
|
||||
return -1;
|
||||
|
||||
off -= GRUB_BTRFS_LZO_BLOCK_SIZE;
|
||||
ibuf += cblock_size;
|
||||
}
|
||||
|
||||
while (osize > 0)
|
||||
{
|
||||
lzo_uint usize = GRUB_BTRFS_LZO_BLOCK_SIZE;
|
||||
|
||||
cblock_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
|
||||
ibuf += sizeof (cblock_size);
|
||||
|
||||
if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE)
|
||||
return -1;
|
||||
|
||||
/* Block partially filled with requested data. */
|
||||
if (off > 0 || osize < GRUB_BTRFS_LZO_BLOCK_SIZE)
|
||||
{
|
||||
grub_size_t to_copy = grub_min(osize, GRUB_BTRFS_LZO_BLOCK_SIZE - off);
|
||||
|
||||
if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, buf, &usize,
|
||||
NULL) != LZO_E_OK)
|
||||
return -1;
|
||||
|
||||
to_copy = grub_min(to_copy, usize);
|
||||
grub_memcpy(obuf, buf + off, to_copy);
|
||||
|
||||
osize -= to_copy;
|
||||
ret += to_copy;
|
||||
obuf += to_copy;
|
||||
ibuf += cblock_size;
|
||||
off = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Decompress whole block directly to output buffer. */
|
||||
if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)obuf,
|
||||
&usize, NULL) != LZO_E_OK)
|
||||
return -1;
|
||||
|
||||
osize -= usize;
|
||||
ret += usize;
|
||||
obuf += usize;
|
||||
ibuf += cblock_size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
||||
grub_uint64_t ino, grub_uint64_t tree,
|
||||
|
@ -909,6 +991,12 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
||||
return -1;
|
||||
}
|
||||
if ((grub_ssize_t) elemsize < ((char *) &data->extent->inl
|
||||
- (char *) data->extent))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "extent descriptor is too short");
|
||||
return -1;
|
||||
}
|
||||
data->extstart = grub_le_to_cpu64 (key_out.offset);
|
||||
data->extsize = elemsize;
|
||||
data->extent = grub_malloc (elemsize);
|
||||
|
@ -917,26 +1005,22 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
if (!data->extent)
|
||||
return grub_errno;
|
||||
|
||||
err = grub_btrfs_read_logical (data, elemaddr,
|
||||
data->extent, elemsize);
|
||||
err = grub_btrfs_read_logical (data, elemaddr, data->extent,
|
||||
elemsize);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->extend = data->extstart
|
||||
+ grub_le_to_cpu64 (data->extent->size);
|
||||
data->extend = data->extstart + grub_le_to_cpu64 (data->extent->size);
|
||||
if (data->extent->type == GRUB_BTRFS_EXTENT_REGULAR
|
||||
&& (char *) &data->extent + elemsize
|
||||
>= (char *) &data->extent->filled
|
||||
+ sizeof (data->extent->filled))
|
||||
data->extend = data->extstart
|
||||
+ grub_le_to_cpu64 (data->extent->filled);
|
||||
>= (char *) &data->extent->filled + sizeof (data->extent->filled))
|
||||
data->extend =
|
||||
data->extstart + grub_le_to_cpu64 (data->extent->filled);
|
||||
|
||||
grub_dprintf ("btrfs", "extent 0x%" PRIxGRUB_UINT64_T "+0x%"
|
||||
PRIxGRUB_UINT64_T " (0x%"
|
||||
PRIxGRUB_UINT64_T ")\n",
|
||||
grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T "+0x%"
|
||||
PRIxGRUB_UINT64_T "\n",
|
||||
grub_le_to_cpu64 (key_out.offset),
|
||||
grub_le_to_cpu64 (data->extent->size),
|
||||
grub_le_to_cpu64 (data->extent->filled));
|
||||
grub_le_to_cpu64 (data->extent->size));
|
||||
if (data->extend <= pos)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "extent not found");
|
||||
|
@ -956,7 +1040,8 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
}
|
||||
|
||||
if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE
|
||||
&& data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB)
|
||||
&& data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB
|
||||
&& data->extent->compression != GRUB_BTRFS_COMPRESSION_LZO)
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"compression type 0x%x not supported",
|
||||
|
@ -966,8 +1051,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
|
||||
if (data->extent->encoding)
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"encoding not supported");
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "encoding not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -983,6 +1067,15 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
!= (grub_ssize_t) csize)
|
||||
return -1;
|
||||
}
|
||||
else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
|
||||
{
|
||||
if (grub_btrfs_lzo_decompress(data->extent->inl, data->extsize -
|
||||
((grub_uint8_t *) data->extent->inl
|
||||
- (grub_uint8_t *) data->extent),
|
||||
extoff, buf, csize)
|
||||
!= (grub_ssize_t) csize)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
grub_memcpy (buf, data->extent->inl + extoff, csize);
|
||||
break;
|
||||
|
@ -992,10 +1085,13 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
grub_memset (buf, 0, csize);
|
||||
break;
|
||||
}
|
||||
if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
|
||||
|
||||
if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE)
|
||||
{
|
||||
char *tmp;
|
||||
grub_uint64_t zsize;
|
||||
grub_ssize_t ret;
|
||||
|
||||
zsize = grub_le_to_cpu64 (data->extent->compressed_size);
|
||||
tmp = grub_malloc (zsize);
|
||||
if (!tmp)
|
||||
|
@ -1008,27 +1104,35 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
|
|||
grub_free (tmp);
|
||||
return -1;
|
||||
}
|
||||
if (grub_zlib_decompress (tmp, zsize, extoff
|
||||
+ grub_le_to_cpu64 (data->extent->offset),
|
||||
buf, csize) != (grub_ssize_t) csize)
|
||||
{
|
||||
grub_free (tmp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
|
||||
ret = grub_zlib_decompress (tmp, zsize, extoff
|
||||
+ grub_le_to_cpu64 (data->extent->offset),
|
||||
buf, csize);
|
||||
else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
|
||||
ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff
|
||||
+ grub_le_to_cpu64 (data->extent->offset),
|
||||
buf, csize);
|
||||
else
|
||||
ret = -1;
|
||||
|
||||
grub_free (tmp);
|
||||
|
||||
if (ret != (grub_ssize_t) csize)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
err = grub_btrfs_read_logical (data,
|
||||
grub_le_to_cpu64 (data->extent->laddr)
|
||||
+ grub_le_to_cpu64 (data->extent->offset)
|
||||
+ extoff,
|
||||
buf, csize);
|
||||
+ extoff, buf, csize);
|
||||
if (err)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported extent type 0x%x", data->extent->type);
|
||||
"unsupported extent type 0x%x", data->extent->type);
|
||||
return -1;
|
||||
}
|
||||
buf += csize;
|
||||
|
@ -1054,6 +1158,7 @@ find_path (struct grub_btrfs_data *data,
|
|||
const char *ctoken;
|
||||
grub_size_t ctokenlen;
|
||||
char *path_alloc = NULL;
|
||||
char *origpath = NULL;
|
||||
unsigned symlinks_max = 32;
|
||||
|
||||
*type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
|
||||
|
@ -1062,6 +1167,9 @@ find_path (struct grub_btrfs_data *data,
|
|||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||
key->offset = 0;
|
||||
skip_default = 1;
|
||||
origpath = grub_strdup (path);
|
||||
if (!origpath)
|
||||
return grub_errno;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
@ -1086,25 +1194,29 @@ find_path (struct grub_btrfs_data *data,
|
|||
if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
||||
{
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
}
|
||||
|
||||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||
key->offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
|
||||
|
||||
err = lower_bound (data, key, &key_out, *tree,
|
||||
&elemaddr, &elemsize, NULL);
|
||||
|
||||
err = lower_bound (data, key, &key_out, *tree, &elemaddr, &elemsize,
|
||||
NULL);
|
||||
if (err)
|
||||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
if (key_cmp (key, &key_out) != 0)
|
||||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct grub_btrfs_dir_item *cdirel;
|
||||
|
@ -1116,6 +1228,7 @@ find_path (struct grub_btrfs_data *data,
|
|||
if (!direl)
|
||||
{
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
|
@ -1125,12 +1238,13 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (cdirel = direl;
|
||||
(grub_uint8_t *) cdirel - (grub_uint8_t *) direl
|
||||
< (grub_ssize_t) elemsize;
|
||||
< (grub_ssize_t) elemsize;
|
||||
cdirel = (void *) ((grub_uint8_t *) (direl + 1)
|
||||
+ grub_le_to_cpu16 (cdirel->n)
|
||||
+ grub_le_to_cpu16 (cdirel->m)))
|
||||
|
@ -1144,7 +1258,9 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!skip_default)
|
||||
|
@ -1158,16 +1274,18 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return grub_error (GRUB_ERR_SYMLINK_LOOP,
|
||||
"too deep nesting of symlinks");
|
||||
}
|
||||
|
||||
|
||||
err = grub_btrfs_read_inode (data, &inode,
|
||||
cdirel->key.object_id, *tree);
|
||||
if (err)
|
||||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
tmp = grub_malloc (grub_le_to_cpu64 (inode.size)
|
||||
|
@ -1176,6 +1294,7 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
@ -1186,10 +1305,11 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
grub_free (tmp);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_memcpy (tmp + grub_le_to_cpu64 (inode.size), path,
|
||||
grub_memcpy (tmp + grub_le_to_cpu64 (inode.size), path,
|
||||
grub_strlen (path) + 1);
|
||||
grub_free (path_alloc);
|
||||
path = path_alloc = tmp;
|
||||
|
@ -1218,6 +1338,7 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
if (cdirel->key.object_id != key_out.object_id
|
||||
|
@ -1225,14 +1346,16 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
err = grub_btrfs_read_logical (data, elemaddr,
|
||||
&ri, sizeof (ri));
|
||||
err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri));
|
||||
if (err)
|
||||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
|
||||
|
@ -1246,7 +1369,9 @@ find_path (struct grub_btrfs_data *data,
|
|||
{
|
||||
grub_free (direl);
|
||||
grub_free (path_alloc);
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
grub_free (origpath);
|
||||
return err;
|
||||
}
|
||||
*key = cdirel->key;
|
||||
if (*type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
||||
|
@ -1254,20 +1379,23 @@ find_path (struct grub_btrfs_data *data,
|
|||
break;
|
||||
default:
|
||||
grub_free (path_alloc);
|
||||
grub_free (origpath);
|
||||
grub_free (direl);
|
||||
return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x",
|
||||
return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x",
|
||||
cdirel->key.type);
|
||||
}
|
||||
}
|
||||
|
||||
grub_free (direl);
|
||||
grub_free (origpath);
|
||||
grub_free (path_alloc);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_btrfs_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
struct grub_btrfs_data *data = grub_btrfs_mount (device);
|
||||
struct grub_btrfs_key key_in, key_out;
|
||||
|
@ -1286,23 +1414,28 @@ grub_btrfs_dir (grub_device_t device, const char *path,
|
|||
|
||||
err = find_path (data, path, &key_in, &tree, &type);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
grub_btrfs_unmount (data);
|
||||
return err;
|
||||
}
|
||||
if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
{
|
||||
grub_btrfs_unmount (data);
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
}
|
||||
|
||||
err = lower_bound (data, &key_in, &key_out, tree,
|
||||
&elemaddr, &elemsize, &desc);
|
||||
err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
grub_btrfs_unmount (data);
|
||||
return err;
|
||||
}
|
||||
if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
|
||||
|| key_out.object_id != key_in.object_id)
|
||||
{
|
||||
r = next (data, &desc, &elemaddr, &elemsize, &key_out);
|
||||
if (r <= 0)
|
||||
{
|
||||
free_iterator (&desc);
|
||||
return -r;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
do
|
||||
{
|
||||
|
@ -1320,18 +1453,21 @@ grub_btrfs_dir (grub_device_t device, const char *path,
|
|||
direl = grub_malloc (allocated + 1);
|
||||
if (!direl)
|
||||
{
|
||||
free_iterator (&desc);
|
||||
return grub_errno;
|
||||
r = -grub_errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
r = -err;
|
||||
break;
|
||||
}
|
||||
|
||||
for (cdirel = direl;
|
||||
(grub_uint8_t *) cdirel - (grub_uint8_t *) direl
|
||||
< (grub_ssize_t) elemsize;
|
||||
< (grub_ssize_t) elemsize;
|
||||
cdirel = (void *) ((grub_uint8_t *) (direl + 1)
|
||||
+ grub_le_to_cpu16 (cdirel->n)
|
||||
+ grub_le_to_cpu16 (cdirel->m)))
|
||||
|
@ -1360,7 +1496,7 @@ grub_btrfs_dir (grub_device_t device, const char *path,
|
|||
}
|
||||
while (r > 0);
|
||||
|
||||
out:
|
||||
out:
|
||||
grub_free (direl);
|
||||
|
||||
free_iterator (&desc);
|
||||
|
@ -1432,7 +1568,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid)
|
|||
*uuid = NULL;
|
||||
|
||||
data = grub_btrfs_mount (device);
|
||||
if (! data)
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
*uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
|
||||
|
@ -1458,7 +1594,7 @@ grub_btrfs_label (grub_device_t device, char **label)
|
|||
*label = NULL;
|
||||
|
||||
data = grub_btrfs_mount (device);
|
||||
if (! data)
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
*label = grub_strndup (data->sblock.label, sizeof (data->sblock.label));
|
||||
|
@ -1468,26 +1604,55 @@ grub_btrfs_label (grub_device_t device, char **label)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
static struct grub_fs grub_btrfs_fs =
|
||||
{
|
||||
.name = "btrfs",
|
||||
.dir = grub_btrfs_dir,
|
||||
.open = grub_btrfs_open,
|
||||
.read = grub_btrfs_read,
|
||||
.close = grub_btrfs_close,
|
||||
.uuid = grub_btrfs_uuid,
|
||||
.label = grub_btrfs_label,
|
||||
#ifdef GRUB_UTIL
|
||||
.reserved_first_sector = 1,
|
||||
#endif
|
||||
};
|
||||
static grub_err_t
|
||||
grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
|
||||
unsigned int *nsectors,
|
||||
grub_embed_type_t embed_type,
|
||||
grub_disk_addr_t **sectors)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
GRUB_MOD_INIT(btrfs)
|
||||
if (embed_type != GRUB_EMBED_PCBIOS)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"BtrFS currently supports only PC-BIOS embedding");
|
||||
|
||||
if (64 * 2 - 1 < *nsectors)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"Your core.img is unusually large. "
|
||||
"It won't fit in the embedding area.");
|
||||
|
||||
*nsectors = 64 * 2 - 1;
|
||||
*sectors = grub_malloc (*nsectors * sizeof (**sectors));
|
||||
if (!*sectors)
|
||||
return grub_errno;
|
||||
for (i = 0; i < *nsectors; i++)
|
||||
(*sectors)[i] = i + 1;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct grub_fs grub_btrfs_fs = {
|
||||
.name = "btrfs",
|
||||
.dir = grub_btrfs_dir,
|
||||
.open = grub_btrfs_open,
|
||||
.read = grub_btrfs_read,
|
||||
.close = grub_btrfs_close,
|
||||
.uuid = grub_btrfs_uuid,
|
||||
.label = grub_btrfs_label,
|
||||
#ifdef GRUB_UTIL
|
||||
.embed = grub_btrfs_embed,
|
||||
.reserved_first_sector = 1,
|
||||
#endif
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (btrfs)
|
||||
{
|
||||
grub_fs_register (&grub_btrfs_fs);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(btrfs)
|
||||
GRUB_MOD_FINI (btrfs)
|
||||
{
|
||||
grub_fs_unregister (&grub_btrfs_fs);
|
||||
}
|
||||
|
|
|
@ -25,28 +25,74 @@
|
|||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#ifndef MODE_USTAR
|
||||
/* cpio support */
|
||||
#define MAGIC_BCPIO 070707
|
||||
#define ATTR_TYPE 0160000
|
||||
#define ATTR_FILE 0100000
|
||||
#define ATTR_DIR 0040000
|
||||
#define ATTR_LNK 0120000
|
||||
|
||||
#ifdef MODE_ODC
|
||||
#define ALIGN_CPIO(x) x
|
||||
#define MAGIC "070707"
|
||||
struct head
|
||||
{
|
||||
grub_uint16_t magic;
|
||||
char magic[6];
|
||||
char dev[6];
|
||||
char ino[6];
|
||||
char mode[6];
|
||||
char uid[6];
|
||||
char gid[6];
|
||||
char nlink[6];
|
||||
char rdev[6];
|
||||
char mtime[11];
|
||||
char namesize[6];
|
||||
char filesize[11];
|
||||
} __attribute__ ((packed));
|
||||
#elif defined (MODE_NEWC)
|
||||
#define ALIGN_CPIO(x) (ALIGN_UP ((x), 4))
|
||||
#define MAGIC "070701"
|
||||
#define MAGIC2 "070702"
|
||||
struct head
|
||||
{
|
||||
char magic[6];
|
||||
char ino[8];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char nlink[8];
|
||||
char mtime[8];
|
||||
char filesize[8];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
char rdevmajor[8];
|
||||
char rdevminor[8];
|
||||
char namesize[8];
|
||||
char check[8];
|
||||
} __attribute__ ((packed));
|
||||
#elif !defined (MODE_USTAR)
|
||||
/* cpio support */
|
||||
#define ALIGN_CPIO(x) (ALIGN_UP ((x), 2))
|
||||
#ifdef MODE_BIGENDIAN
|
||||
#define MAGIC "\x71\xc7"
|
||||
#else
|
||||
#define MAGIC "\xc7\x71"
|
||||
#endif
|
||||
struct head
|
||||
{
|
||||
grub_uint16_t magic[1];
|
||||
grub_uint16_t dev;
|
||||
grub_uint16_t ino;
|
||||
grub_uint16_t mode;
|
||||
grub_uint16_t mode[1];
|
||||
grub_uint16_t uid;
|
||||
grub_uint16_t gid;
|
||||
grub_uint16_t nlink;
|
||||
grub_uint16_t rdev;
|
||||
grub_uint16_t mtime_1;
|
||||
grub_uint16_t mtime_2;
|
||||
grub_uint16_t namesize;
|
||||
grub_uint16_t filesize_1;
|
||||
grub_uint16_t filesize_2;
|
||||
grub_uint16_t mtime[2];
|
||||
grub_uint16_t namesize[1];
|
||||
grub_uint16_t filesize[2];
|
||||
} __attribute__ ((packed));
|
||||
#else
|
||||
/* tar support */
|
||||
#define MAGIC_USTAR "ustar"
|
||||
#define MAGIC "ustar"
|
||||
struct head
|
||||
{
|
||||
char name[100];
|
||||
|
@ -71,60 +117,140 @@ struct head
|
|||
struct grub_cpio_data
|
||||
{
|
||||
grub_disk_t disk;
|
||||
grub_uint32_t hofs;
|
||||
grub_uint32_t dofs;
|
||||
grub_uint32_t size;
|
||||
grub_off_t hofs;
|
||||
grub_off_t dofs;
|
||||
grub_off_t size;
|
||||
#ifdef MODE_USTAR
|
||||
char *linkname;
|
||||
grub_size_t linkname_alloc;
|
||||
#endif
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
static inline void
|
||||
canonicalize (char *name)
|
||||
{
|
||||
char *iptr, *optr;
|
||||
for (iptr = name, optr = name; *iptr; )
|
||||
{
|
||||
while (*iptr == '/')
|
||||
iptr++;
|
||||
if (iptr[0] == '.' && (iptr[1] == '/' || iptr[1] == 0))
|
||||
{
|
||||
iptr += 2;
|
||||
continue;
|
||||
}
|
||||
while (*iptr && *iptr != '/')
|
||||
*optr++ = *iptr++;
|
||||
if (*iptr)
|
||||
*optr++ = *iptr++;
|
||||
}
|
||||
*optr = 0;
|
||||
}
|
||||
|
||||
#if defined (MODE_ODC) || defined (MODE_USTAR)
|
||||
static inline unsigned long long
|
||||
read_number (const char *str, grub_size_t size)
|
||||
{
|
||||
unsigned long long ret = 0;
|
||||
while (size-- && *str >= '0' && *str <= '7')
|
||||
ret = (ret << 3) | (*str++ & 0xf);
|
||||
return ret;
|
||||
}
|
||||
#elif defined (MODE_NEWC)
|
||||
static inline unsigned long long
|
||||
read_number (const char *str, grub_size_t size)
|
||||
{
|
||||
unsigned long long ret = 0;
|
||||
while (size-- && grub_isxdigit (*str))
|
||||
{
|
||||
char dig = *str++;
|
||||
if (dig >= '0' && dig <= '9')
|
||||
dig &= 0xf;
|
||||
else if (dig >= 'a' && dig <= 'f')
|
||||
dig -= 'a' - 10;
|
||||
else
|
||||
dig -= 'A' - 10;
|
||||
ret = (ret << 4) | (dig);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static inline unsigned long long
|
||||
read_number (const grub_uint16_t *arr, grub_size_t size)
|
||||
{
|
||||
long long ret = 0;
|
||||
#ifdef MODE_BIGENDIAN
|
||||
while (size--)
|
||||
ret = (ret << 16) | grub_be_to_cpu16 (*arr++);
|
||||
#else
|
||||
while (size--)
|
||||
ret = (ret << 16) | grub_le_to_cpu16 (*arr++);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_cpio_find_file (struct grub_cpio_data *data, char **name,
|
||||
grub_int32_t *mtime, grub_uint32_t * ofs)
|
||||
grub_int32_t *mtime, grub_disk_addr_t *ofs,
|
||||
grub_uint32_t *mode)
|
||||
{
|
||||
#ifndef MODE_USTAR
|
||||
struct head hd;
|
||||
struct head hd;
|
||||
grub_size_t namesize;
|
||||
grub_uint32_t modeval;
|
||||
|
||||
if (grub_disk_read
|
||||
(data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
|
||||
if (hd.magic != MAGIC_BCPIO)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
|
||||
if (grub_memcmp (hd.magic, MAGIC, sizeof (hd.magic)) != 0
|
||||
#ifdef MAGIC2
|
||||
&& grub_memcmp (hd.magic, MAGIC2, sizeof (hd.magic)) != 0
|
||||
#endif
|
||||
)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive");
|
||||
data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize));
|
||||
if (mtime)
|
||||
*mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime));
|
||||
modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode));
|
||||
namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize));
|
||||
|
||||
data->size = (((grub_uint32_t) hd.filesize_1) << 16) + hd.filesize_2;
|
||||
if (mtime)
|
||||
*mtime = (((grub_uint32_t) hd.mtime_1) << 16) + hd.mtime_2;
|
||||
if (mode)
|
||||
*mode = modeval;
|
||||
|
||||
if (hd.namesize & 1)
|
||||
hd.namesize++;
|
||||
*name = grub_malloc (namesize + 1);
|
||||
if (*name == NULL)
|
||||
return grub_errno;
|
||||
|
||||
if ((*name = grub_malloc (hd.namesize)) == NULL)
|
||||
return grub_errno;
|
||||
if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
|
||||
namesize, *name))
|
||||
{
|
||||
grub_free (*name);
|
||||
return grub_errno;
|
||||
}
|
||||
(*name)[namesize] = 0;
|
||||
|
||||
if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
|
||||
hd.namesize, *name))
|
||||
{
|
||||
grub_free (*name);
|
||||
return grub_errno;
|
||||
}
|
||||
if (data->size == 0 && modeval == 0 && namesize == 11
|
||||
&& grub_memcmp(*name, "TRAILER!!!", 11) == 0)
|
||||
{
|
||||
*ofs = 0;
|
||||
grub_free (*name);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (data->size == 0 && hd.mode == 0 && hd.namesize == 11 + 1
|
||||
&& ! grub_memcmp(*name, "TRAILER!!!", 11))
|
||||
{
|
||||
*ofs = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
canonicalize (*name);
|
||||
|
||||
data->dofs = data->hofs + sizeof (hd) + hd.namesize;
|
||||
*ofs = data->dofs + data->size;
|
||||
if (data->size & 1)
|
||||
(*ofs)++;
|
||||
data->dofs = data->hofs + ALIGN_CPIO (sizeof (hd) + namesize);
|
||||
*ofs = data->dofs + ALIGN_CPIO (data->size);
|
||||
#else
|
||||
struct head hd;
|
||||
struct head hd;
|
||||
int reread = 0, have_longname = 0, have_longlink = 0;
|
||||
|
||||
if (grub_disk_read
|
||||
(data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
for (reread = 0; reread < 3; reread++)
|
||||
{
|
||||
if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
|
||||
return grub_errno;
|
||||
|
||||
if (!hd.name[0])
|
||||
|
@ -133,18 +259,105 @@ grub_cpio_find_file (struct grub_cpio_data *data, char **name,
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (grub_memcmp (hd.magic, MAGIC_USTAR, sizeof (MAGIC_USTAR) - 1))
|
||||
if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
|
||||
return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");
|
||||
|
||||
if ((*name = grub_strdup (hd.name)) == NULL)
|
||||
return grub_errno;
|
||||
if (hd.typeflag == 'L')
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
|
||||
*name = grub_malloc (namesize + 1);
|
||||
if (*name == NULL)
|
||||
return grub_errno;
|
||||
err = grub_disk_read (data->disk, 0,
|
||||
data->hofs + GRUB_DISK_SECTOR_SIZE, namesize,
|
||||
*name);
|
||||
(*name)[namesize] = 0;
|
||||
if (err)
|
||||
return err;
|
||||
data->hofs += GRUB_DISK_SECTOR_SIZE
|
||||
+ ((namesize + GRUB_DISK_SECTOR_SIZE - 1) &
|
||||
~(GRUB_DISK_SECTOR_SIZE - 1));
|
||||
have_longname = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
data->size = grub_strtoul (hd.size, NULL, 8);
|
||||
if (hd.typeflag == 'K')
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
|
||||
if (data->linkname_alloc < linksize + 1)
|
||||
{
|
||||
char *n;
|
||||
n = grub_malloc (2 * (linksize + 1));
|
||||
if (!n)
|
||||
return grub_errno;
|
||||
grub_free (data->linkname);
|
||||
data->linkname = n;
|
||||
data->linkname_alloc = 2 * (linksize + 1);
|
||||
}
|
||||
|
||||
err = grub_disk_read (data->disk, 0,
|
||||
data->hofs + GRUB_DISK_SECTOR_SIZE, linksize,
|
||||
data->linkname);
|
||||
if (err)
|
||||
return err;
|
||||
data->linkname[linksize] = 0;
|
||||
data->hofs += GRUB_DISK_SECTOR_SIZE
|
||||
+ ((linksize + GRUB_DISK_SECTOR_SIZE - 1) &
|
||||
~(GRUB_DISK_SECTOR_SIZE - 1));
|
||||
have_longlink = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!have_longname)
|
||||
{
|
||||
*name = grub_strndup (hd.name, sizeof (hd.name));
|
||||
if (*name == NULL)
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
data->size = read_number (hd.size, sizeof (hd.size));
|
||||
data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
|
||||
*ofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
|
||||
~(GRUB_DISK_SECTOR_SIZE - 1));
|
||||
if (mtime)
|
||||
*mtime = grub_strtoul (hd.mtime, NULL, 8);
|
||||
*mtime = read_number (hd.mtime, sizeof (hd.mtime));
|
||||
if (mode)
|
||||
{
|
||||
*mode = read_number (hd.mode, sizeof (hd.mode));
|
||||
switch (hd.typeflag)
|
||||
{
|
||||
case '2':
|
||||
*mode |= ATTR_LNK;
|
||||
break;
|
||||
case '0':
|
||||
*mode |= ATTR_FILE;
|
||||
break;
|
||||
case '5':
|
||||
*mode |= ATTR_DIR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!have_longlink)
|
||||
{
|
||||
if (data->linkname_alloc < 101)
|
||||
{
|
||||
char *n;
|
||||
n = grub_malloc (101);
|
||||
if (!n)
|
||||
return grub_errno;
|
||||
grub_free (data->linkname);
|
||||
data->linkname = n;
|
||||
data->linkname_alloc = 101;
|
||||
}
|
||||
grub_memcpy (data->linkname, hd.linkname, sizeof (hd.linkname));
|
||||
data->linkname[100] = 0;
|
||||
}
|
||||
|
||||
canonicalize (*name);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
#endif
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -158,15 +371,14 @@ grub_cpio_mount (grub_disk_t disk)
|
|||
if (grub_disk_read (disk, 0, 0, sizeof (hd), &hd))
|
||||
goto fail;
|
||||
|
||||
#ifndef MODE_USTAR
|
||||
if (hd.magic != MAGIC_BCPIO)
|
||||
#else
|
||||
if (grub_memcmp (hd.magic, MAGIC_USTAR,
|
||||
sizeof (MAGIC_USTAR) - 1))
|
||||
if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1)
|
||||
#ifdef MAGIC2
|
||||
&& grub_memcmp (hd.magic, MAGIC2, sizeof (MAGIC2) - 1)
|
||||
#endif
|
||||
)
|
||||
goto fail;
|
||||
|
||||
data = (struct grub_cpio_data *) grub_malloc (sizeof (*data));
|
||||
data = (struct grub_cpio_data *) grub_zalloc (sizeof (*data));
|
||||
if (!data)
|
||||
goto fail;
|
||||
|
||||
|
@ -186,15 +398,107 @@ fail:
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cpio_dir (grub_device_t device, const char *path,
|
||||
handle_symlink (struct grub_cpio_data *data,
|
||||
const char *fn, char **name,
|
||||
grub_uint32_t mode, int *restart)
|
||||
{
|
||||
grub_size_t flen;
|
||||
char *target;
|
||||
#ifndef MODE_USTAR
|
||||
grub_err_t err;
|
||||
#endif
|
||||
char *ptr;
|
||||
char *lastslash;
|
||||
grub_size_t prefixlen;
|
||||
char *rest;
|
||||
grub_size_t size;
|
||||
|
||||
*restart = 0;
|
||||
|
||||
if ((mode & ATTR_TYPE) != ATTR_LNK)
|
||||
return GRUB_ERR_NONE;
|
||||
flen = grub_strlen (fn);
|
||||
if (grub_memcmp (*name, fn, flen) != 0
|
||||
|| ((*name)[flen] != 0 && (*name)[flen] != '/'))
|
||||
return GRUB_ERR_NONE;
|
||||
rest = *name + flen;
|
||||
lastslash = rest;
|
||||
if (*rest)
|
||||
rest++;
|
||||
while (lastslash >= *name && *lastslash != '/')
|
||||
lastslash--;
|
||||
if (lastslash >= *name)
|
||||
prefixlen = lastslash - *name;
|
||||
else
|
||||
prefixlen = 0;
|
||||
|
||||
if (prefixlen)
|
||||
prefixlen++;
|
||||
|
||||
#ifdef MODE_USTAR
|
||||
size = grub_strlen (data->linkname);
|
||||
#else
|
||||
size = data->size;
|
||||
#endif
|
||||
if (size == 0)
|
||||
return GRUB_ERR_NONE;
|
||||
target = grub_malloc (size + grub_strlen (*name) + 2);
|
||||
if (!target)
|
||||
return grub_errno;
|
||||
|
||||
#ifdef MODE_USTAR
|
||||
grub_memcpy (target + prefixlen, data->linkname, size);
|
||||
#else
|
||||
err = grub_disk_read (data->disk, 0, data->dofs, data->size,
|
||||
target + prefixlen);
|
||||
if (err)
|
||||
return err;
|
||||
#endif
|
||||
if (target[prefixlen] == '/')
|
||||
{
|
||||
grub_memmove (target, target + prefixlen, data->size - 1);
|
||||
ptr = target + data->size - 1;
|
||||
ptr = grub_stpcpy (ptr, rest);
|
||||
*ptr = 0;
|
||||
grub_dprintf ("cpio", "symlink redirected %s to %s\n",
|
||||
*name, target);
|
||||
grub_free (*name);
|
||||
*name = target;
|
||||
*restart = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (prefixlen)
|
||||
{
|
||||
grub_memcpy (target, *name, prefixlen);
|
||||
target[prefixlen] = '/';
|
||||
}
|
||||
ptr = target + prefixlen + size;
|
||||
ptr = grub_stpcpy (ptr, rest);
|
||||
*ptr = 0;
|
||||
grub_dprintf ("cpio", "symlink redirected %s to %s\n",
|
||||
*name, target);
|
||||
grub_free (*name);
|
||||
*name = target;
|
||||
*restart = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cpio_dir (grub_device_t device, const char *path_in,
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
struct grub_cpio_data *data;
|
||||
grub_uint32_t ofs;
|
||||
char *prev, *name;
|
||||
const char *np;
|
||||
int len;
|
||||
grub_disk_addr_t ofs;
|
||||
char *prev, *name, *path, *ptr;
|
||||
grub_size_t len;
|
||||
int symlinknest = 0;
|
||||
|
||||
path = grub_strdup (path_in + 1);
|
||||
if (!path)
|
||||
return grub_errno;
|
||||
for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--)
|
||||
*ptr = 0;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
|
@ -202,35 +506,39 @@ grub_cpio_dir (grub_device_t device, const char *path,
|
|||
|
||||
data = grub_cpio_mount (device->disk);
|
||||
if (!data)
|
||||
goto fail;
|
||||
|
||||
np = path + 1;
|
||||
len = grub_strlen (path) - 1;
|
||||
{
|
||||
grub_free (path);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
len = grub_strlen (path);
|
||||
data->hofs = 0;
|
||||
while (1)
|
||||
{
|
||||
grub_int32_t mtime;
|
||||
grub_uint32_t mode;
|
||||
grub_err_t err;
|
||||
|
||||
if (grub_cpio_find_file (data, &name, &mtime, &ofs))
|
||||
if (grub_cpio_find_file (data, &name, &mtime, &ofs, &mode))
|
||||
goto fail;
|
||||
|
||||
if (!ofs)
|
||||
break;
|
||||
|
||||
if (grub_memcmp (np, name, len) == 0)
|
||||
if (grub_memcmp (path, name, len) == 0
|
||||
&& (name[len] == 0 || name[len] == '/' || len == 0))
|
||||
{
|
||||
char *p, *n;
|
||||
|
||||
n = name + len;
|
||||
if (*n == '/')
|
||||
while (*n == '/')
|
||||
n++;
|
||||
|
||||
p = grub_strchr (name + len, '/');
|
||||
p = grub_strchr (n, '/');
|
||||
if (p)
|
||||
*p = 0;
|
||||
|
||||
if ((!prev) || (grub_strcmp (prev, name) != 0))
|
||||
if (((!prev) || (grub_strcmp (prev, n) != 0)) && *n != 0)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
|
@ -238,24 +546,44 @@ grub_cpio_dir (grub_device_t device, const char *path,
|
|||
info.mtime = mtime;
|
||||
info.mtimeset = 1;
|
||||
|
||||
hook (name + len, &info);
|
||||
if (prev)
|
||||
grub_free (prev);
|
||||
if (hook (n, &info))
|
||||
goto fail;
|
||||
grub_free (prev);
|
||||
prev = name;
|
||||
}
|
||||
else
|
||||
grub_free (name);
|
||||
{
|
||||
int restart;
|
||||
err = handle_symlink (data, name, &path, mode, &restart);
|
||||
grub_free (name);
|
||||
if (err)
|
||||
goto fail;
|
||||
if (restart)
|
||||
{
|
||||
len = grub_strlen (path);
|
||||
if (++symlinknest == 8)
|
||||
{
|
||||
grub_error (GRUB_ERR_SYMLINK_LOOP,
|
||||
"too deep nesting of symlinks");
|
||||
goto fail;
|
||||
}
|
||||
ofs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
grub_free (name);
|
||||
data->hofs = ofs;
|
||||
}
|
||||
|
||||
fail:
|
||||
|
||||
if (prev)
|
||||
grub_free (prev);
|
||||
|
||||
if (data)
|
||||
grub_free (data);
|
||||
grub_free (path);
|
||||
grub_free (prev);
|
||||
#ifdef MODE_USTAR
|
||||
grub_free (data->linkname);
|
||||
#endif
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -263,23 +591,33 @@ fail:
|
|||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cpio_open (grub_file_t file, const char *name)
|
||||
grub_cpio_open (grub_file_t file, const char *name_in)
|
||||
{
|
||||
struct grub_cpio_data *data;
|
||||
grub_uint32_t ofs;
|
||||
grub_disk_addr_t ofs;
|
||||
char *fn;
|
||||
int i, j;
|
||||
char *name = grub_strdup (name_in + 1);
|
||||
int symlinknest = 0;
|
||||
|
||||
if (!name)
|
||||
return grub_errno;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
data = grub_cpio_mount (file->device->disk);
|
||||
if (!data)
|
||||
goto fail;
|
||||
{
|
||||
grub_free (name);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
data->hofs = 0;
|
||||
while (1)
|
||||
{
|
||||
if (grub_cpio_find_file (data, &fn, NULL, &ofs))
|
||||
grub_uint32_t mode;
|
||||
int restart;
|
||||
|
||||
if (grub_cpio_find_file (data, &fn, NULL, &ofs, &mode))
|
||||
goto fail;
|
||||
|
||||
if (!ofs)
|
||||
|
@ -288,33 +626,31 @@ grub_cpio_open (grub_file_t file, const char *name)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Compare NAME and FN by hand in order to cope with duplicate
|
||||
slashes. */
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (name[i] == '/')
|
||||
i++;
|
||||
while (1)
|
||||
if (handle_symlink (data, fn, &name, mode, &restart))
|
||||
{
|
||||
if (name[i] != fn[j])
|
||||
goto no_match;
|
||||
|
||||
if (name[i] == '\0')
|
||||
break;
|
||||
|
||||
while (name[i] == '/' && name[i+1] == '/')
|
||||
i++;
|
||||
|
||||
i++;
|
||||
j++;
|
||||
grub_free (fn);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (name[i] != fn[j])
|
||||
if (restart)
|
||||
{
|
||||
ofs = 0;
|
||||
if (++symlinknest == 8)
|
||||
{
|
||||
grub_error (GRUB_ERR_SYMLINK_LOOP,
|
||||
"too deep nesting of symlinks");
|
||||
goto fail;
|
||||
}
|
||||
goto no_match;
|
||||
}
|
||||
|
||||
if (grub_strcmp (name, fn) != 0)
|
||||
goto no_match;
|
||||
|
||||
file->data = data;
|
||||
file->size = data->size;
|
||||
grub_free (fn);
|
||||
grub_free (name);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
|
@ -325,9 +661,11 @@ grub_cpio_open (grub_file_t file, const char *name)
|
|||
}
|
||||
|
||||
fail:
|
||||
|
||||
if (data)
|
||||
grub_free (data);
|
||||
#ifdef MODE_USTAR
|
||||
grub_free (data->linkname);
|
||||
#endif
|
||||
grub_free (data);
|
||||
grub_free (name);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -347,7 +685,13 @@ grub_cpio_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
static grub_err_t
|
||||
grub_cpio_close (grub_file_t file)
|
||||
{
|
||||
grub_free (file->data);
|
||||
struct grub_cpio_data *data;
|
||||
|
||||
data = file->data;
|
||||
#ifdef MODE_USTAR
|
||||
grub_free (data->linkname);
|
||||
#endif
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -357,6 +701,10 @@ grub_cpio_close (grub_file_t file)
|
|||
static struct grub_fs grub_cpio_fs = {
|
||||
#ifdef MODE_USTAR
|
||||
.name = "tarfs",
|
||||
#elif defined (MODE_ODC)
|
||||
.name = "odc",
|
||||
#elif defined (MODE_NEWC)
|
||||
.name = "newc",
|
||||
#else
|
||||
.name = "cpiofs",
|
||||
#endif
|
||||
|
@ -371,6 +719,10 @@ static struct grub_fs grub_cpio_fs = {
|
|||
|
||||
#ifdef MODE_USTAR
|
||||
GRUB_MOD_INIT (tar)
|
||||
#elif defined (MODE_ODC)
|
||||
GRUB_MOD_INIT (odc)
|
||||
#elif defined (MODE_NEWC)
|
||||
GRUB_MOD_INIT (newc)
|
||||
#else
|
||||
GRUB_MOD_INIT (cpio)
|
||||
#endif
|
||||
|
@ -381,6 +733,10 @@ GRUB_MOD_INIT (cpio)
|
|||
|
||||
#ifdef MODE_USTAR
|
||||
GRUB_MOD_FINI (tar)
|
||||
#elif defined (MODE_ODC)
|
||||
GRUB_MOD_FINI (odc)
|
||||
#elif defined (MODE_NEWC)
|
||||
GRUB_MOD_FINI (newc)
|
||||
#else
|
||||
GRUB_MOD_FINI (cpio)
|
||||
#endif
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#define MODE_BIGENDIAN 1
|
||||
#include "afs.c"
|
||||
#include "cpio.c"
|
2
grub-core/fs/exfat.c
Normal file
2
grub-core/fs/exfat.c
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define MODE_EXFAT 1
|
||||
#include "fat.c"
|
|
@ -337,7 +337,7 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
|
|||
}
|
||||
|
||||
static struct grub_ext4_extent_header *
|
||||
grub_ext4_find_leaf (struct grub_ext2_data *data, char *buf,
|
||||
grub_ext4_find_leaf (struct grub_ext2_data *data, grub_properly_aligned_t *buf,
|
||||
struct grub_ext4_extent_header *ext_block,
|
||||
grub_uint32_t fileblock)
|
||||
{
|
||||
|
@ -387,7 +387,7 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
|
||||
if (grub_le_to_cpu32(inode->flags) & EXT4_EXTENTS_FLAG)
|
||||
{
|
||||
char buf[EXT2_BLOCK_SIZE(data)];
|
||||
GRUB_PROPERLY_ALIGNED_ARRAY (buf, EXT2_BLOCK_SIZE(data));
|
||||
struct grub_ext4_extent_header *leaf;
|
||||
struct grub_ext4_extent *ext;
|
||||
int i;
|
||||
|
|
|
@ -30,28 +30,117 @@
|
|||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define GRUB_FAT_DIR_ENTRY_SIZE 32
|
||||
enum
|
||||
{
|
||||
GRUB_FAT_ATTR_READ_ONLY = 0x01,
|
||||
GRUB_FAT_ATTR_HIDDEN = 0x02,
|
||||
GRUB_FAT_ATTR_SYSTEM = 0x04,
|
||||
#ifndef MODE_EXFAT
|
||||
GRUB_FAT_ATTR_VOLUME_ID = 0x08,
|
||||
#endif
|
||||
GRUB_FAT_ATTR_DIRECTORY = 0x10,
|
||||
GRUB_FAT_ATTR_ARCHIVE = 0x20,
|
||||
|
||||
#define GRUB_FAT_ATTR_READ_ONLY 0x01
|
||||
#define GRUB_FAT_ATTR_HIDDEN 0x02
|
||||
#define GRUB_FAT_ATTR_SYSTEM 0x04
|
||||
#define GRUB_FAT_ATTR_VOLUME_ID 0x08
|
||||
#define GRUB_FAT_ATTR_DIRECTORY 0x10
|
||||
#define GRUB_FAT_ATTR_ARCHIVE 0x20
|
||||
#ifndef MODE_EXFAT
|
||||
GRUB_FAT_ATTR_LONG_NAME = (GRUB_FAT_ATTR_READ_ONLY
|
||||
| GRUB_FAT_ATTR_HIDDEN
|
||||
| GRUB_FAT_ATTR_SYSTEM
|
||||
| GRUB_FAT_ATTR_VOLUME_ID),
|
||||
#endif
|
||||
GRUB_FAT_ATTR_VALID = (GRUB_FAT_ATTR_READ_ONLY
|
||||
| GRUB_FAT_ATTR_HIDDEN
|
||||
| GRUB_FAT_ATTR_SYSTEM
|
||||
| GRUB_FAT_ATTR_DIRECTORY
|
||||
| GRUB_FAT_ATTR_ARCHIVE
|
||||
#ifndef MODE_EXFAT
|
||||
| GRUB_FAT_ATTR_VOLUME_ID
|
||||
#endif
|
||||
)
|
||||
};
|
||||
|
||||
#define GRUB_FAT_MAXFILE 256
|
||||
#ifdef MODE_EXFAT
|
||||
struct grub_exfat_bpb
|
||||
{
|
||||
grub_uint8_t jmp_boot[3];
|
||||
grub_uint8_t oem_name[8];
|
||||
grub_uint8_t mbz[53];
|
||||
grub_uint64_t num_hidden_sectors;
|
||||
grub_uint64_t num_total_sectors;
|
||||
grub_uint32_t num_reserved_sectors;
|
||||
grub_uint32_t sectors_per_fat;
|
||||
grub_uint32_t cluster_offset;
|
||||
grub_uint32_t cluster_count;
|
||||
grub_uint32_t root_cluster;
|
||||
grub_uint32_t num_serial;
|
||||
grub_uint16_t fs_revision;
|
||||
grub_uint16_t volume_flags;
|
||||
grub_uint8_t bytes_per_sector_shift;
|
||||
grub_uint8_t sectors_per_cluster_shift;
|
||||
grub_uint8_t num_fats;
|
||||
grub_uint8_t num_ph_drive;
|
||||
grub_uint8_t reserved[8];
|
||||
} __attribute__ ((packed));
|
||||
typedef struct grub_exfat_bpb grub_current_fat_bpb_t;
|
||||
#else
|
||||
typedef struct grub_fat_bpb grub_current_fat_bpb_t;
|
||||
#endif
|
||||
|
||||
#define GRUB_FAT_ATTR_LONG_NAME (GRUB_FAT_ATTR_READ_ONLY \
|
||||
| GRUB_FAT_ATTR_HIDDEN \
|
||||
| GRUB_FAT_ATTR_SYSTEM \
|
||||
| GRUB_FAT_ATTR_VOLUME_ID)
|
||||
#define GRUB_FAT_ATTR_VALID (GRUB_FAT_ATTR_READ_ONLY \
|
||||
| GRUB_FAT_ATTR_HIDDEN \
|
||||
| GRUB_FAT_ATTR_SYSTEM \
|
||||
| GRUB_FAT_ATTR_DIRECTORY \
|
||||
| GRUB_FAT_ATTR_ARCHIVE \
|
||||
| GRUB_FAT_ATTR_VOLUME_ID)
|
||||
#ifdef MODE_EXFAT
|
||||
struct grub_fat_dir_entry
|
||||
{
|
||||
grub_uint8_t entry_type;
|
||||
union
|
||||
{
|
||||
grub_uint8_t placeholder[31];
|
||||
struct {
|
||||
grub_uint8_t secondary_count;
|
||||
grub_uint16_t checksum;
|
||||
grub_uint16_t attr;
|
||||
grub_uint16_t reserved1;
|
||||
grub_uint32_t c_time;
|
||||
grub_uint32_t m_time;
|
||||
grub_uint32_t a_time;
|
||||
grub_uint8_t c_time_tenth;
|
||||
grub_uint8_t m_time_tenth;
|
||||
grub_uint8_t a_time_tenth;
|
||||
grub_uint8_t reserved2[9];
|
||||
} __attribute__ ((packed)) file;
|
||||
struct {
|
||||
grub_uint8_t flags;
|
||||
grub_uint8_t reserved1;
|
||||
grub_uint8_t name_length;
|
||||
grub_uint16_t name_hash;
|
||||
grub_uint16_t reserved2;
|
||||
grub_uint64_t valid_size;
|
||||
grub_uint32_t reserved3;
|
||||
grub_uint32_t first_cluster;
|
||||
grub_uint64_t file_size;
|
||||
} __attribute__ ((packed)) stream_extension;
|
||||
struct {
|
||||
grub_uint8_t flags;
|
||||
grub_uint16_t str[15];
|
||||
} __attribute__ ((packed)) file_name;
|
||||
struct {
|
||||
grub_uint8_t character_count;
|
||||
grub_uint16_t str[11];
|
||||
grub_uint8_t reserved[8];
|
||||
} __attribute__ ((packed)) volume_label;
|
||||
} __attribute__ ((packed)) type_specific;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_fat_dir_node
|
||||
{
|
||||
grub_uint32_t attr;
|
||||
grub_uint32_t first_cluster;
|
||||
grub_uint64_t file_size;
|
||||
grub_uint64_t valid_size;
|
||||
int have_stream;
|
||||
int is_label;
|
||||
};
|
||||
|
||||
typedef struct grub_fat_dir_node grub_fat_dir_node_t;
|
||||
|
||||
#else
|
||||
struct grub_fat_dir_entry
|
||||
{
|
||||
grub_uint8_t name[11];
|
||||
|
@ -80,6 +169,10 @@ struct grub_fat_long_name_entry
|
|||
grub_uint16_t name3[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct grub_fat_dir_entry grub_fat_dir_node_t;
|
||||
|
||||
#endif
|
||||
|
||||
struct grub_fat_data
|
||||
{
|
||||
int logical_sector_bits;
|
||||
|
@ -90,8 +183,10 @@ struct grub_fat_data
|
|||
int fat_size;
|
||||
|
||||
grub_uint32_t root_cluster;
|
||||
#ifndef MODE_EXFAT
|
||||
grub_uint32_t root_sector;
|
||||
grub_uint32_t num_root_sectors;
|
||||
#endif
|
||||
|
||||
int cluster_bits;
|
||||
grub_uint32_t cluster_eof_mark;
|
||||
|
@ -109,6 +204,7 @@ struct grub_fat_data
|
|||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
static int
|
||||
fat_log2 (unsigned x)
|
||||
{
|
||||
|
@ -125,11 +221,12 @@ fat_log2 (unsigned x)
|
|||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct grub_fat_data *
|
||||
grub_fat_mount (grub_disk_t disk)
|
||||
{
|
||||
struct grub_fat_bpb bpb;
|
||||
grub_current_fat_bpb_t bpb;
|
||||
struct grub_fat_data *data = 0;
|
||||
grub_uint32_t first_fat, magic;
|
||||
|
||||
|
@ -144,20 +241,35 @@ grub_fat_mount (grub_disk_t disk)
|
|||
if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb))
|
||||
goto fail;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ",
|
||||
sizeof (bpb.oem_name)) != 0)
|
||||
goto fail;
|
||||
#else
|
||||
if (grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT12", 5)
|
||||
&& grub_strncmp((const char *) bpb.version_specific.fat12_or_fat16.fstype, "FAT16", 5)
|
||||
&& grub_strncmp((const char *) bpb.version_specific.fat32.fstype, "FAT32", 5))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* Get the sizes of logical sectors and clusters. */
|
||||
#ifdef MODE_EXFAT
|
||||
data->logical_sector_bits = bpb.bytes_per_sector_shift;
|
||||
#else
|
||||
data->logical_sector_bits =
|
||||
fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector));
|
||||
if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS)
|
||||
#endif
|
||||
if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS
|
||||
|| data->logical_sector_bits >= 16)
|
||||
goto fail;
|
||||
data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
data->cluster_bits = bpb.sectors_per_cluster_shift;
|
||||
#else
|
||||
data->cluster_bits = fat_log2 (bpb.sectors_per_cluster);
|
||||
if (data->cluster_bits < 0)
|
||||
#endif
|
||||
if (data->cluster_bits < 0 || data->cluster_bits > 25)
|
||||
goto fail;
|
||||
data->cluster_bits += data->logical_sector_bits;
|
||||
|
||||
|
@ -167,18 +279,28 @@ grub_fat_mount (grub_disk_t disk)
|
|||
if (data->fat_sector == 0)
|
||||
goto fail;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
data->sectors_per_fat = (grub_le_to_cpu32 (bpb.sectors_per_fat)
|
||||
<< data->logical_sector_bits);
|
||||
#else
|
||||
data->sectors_per_fat = ((bpb.sectors_per_fat_16
|
||||
? grub_le_to_cpu16 (bpb.sectors_per_fat_16)
|
||||
: grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32))
|
||||
<< data->logical_sector_bits);
|
||||
#endif
|
||||
if (data->sectors_per_fat == 0)
|
||||
goto fail;
|
||||
|
||||
/* Get the number of sectors in this volume. */
|
||||
#ifdef MODE_EXFAT
|
||||
data->num_sectors = ((grub_le_to_cpu64 (bpb.num_total_sectors))
|
||||
<< data->logical_sector_bits);
|
||||
#else
|
||||
data->num_sectors = ((bpb.num_total_sectors_16
|
||||
? grub_le_to_cpu16 (bpb.num_total_sectors_16)
|
||||
: grub_le_to_cpu32 (bpb.num_total_sectors_32))
|
||||
<< data->logical_sector_bits);
|
||||
#endif
|
||||
if (data->num_sectors == 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -186,22 +308,44 @@ grub_fat_mount (grub_disk_t disk)
|
|||
if (bpb.num_fats == 0)
|
||||
goto fail;
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat;
|
||||
data->num_root_sectors
|
||||
= ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries)
|
||||
* GRUB_FAT_DIR_ENTRY_SIZE
|
||||
* sizeof (struct grub_fat_dir_entry)
|
||||
+ grub_le_to_cpu16 (bpb.bytes_per_sector) - 1)
|
||||
>> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS))
|
||||
<< (data->logical_sector_bits));
|
||||
#endif
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset)
|
||||
<< data->logical_sector_bits);
|
||||
data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count)
|
||||
<< data->logical_sector_bits);
|
||||
#else
|
||||
data->cluster_sector = data->root_sector + data->num_root_sectors;
|
||||
data->num_clusters = (((data->num_sectors - data->cluster_sector)
|
||||
>> (data->cluster_bits + data->logical_sector_bits))
|
||||
+ 2);
|
||||
#endif
|
||||
|
||||
if (data->num_clusters <= 2)
|
||||
goto fail;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
{
|
||||
/* exFAT. */
|
||||
grub_uint16_t flags = grub_le_to_cpu16 (bpb.volume_flags);
|
||||
|
||||
data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster);
|
||||
data->fat_size = 32;
|
||||
data->cluster_eof_mark = 0xffffffff;
|
||||
|
||||
if ((flags & 0x1) && bpb.num_fats > 1)
|
||||
data->fat_sector += data->sectors_per_fat;
|
||||
}
|
||||
#else
|
||||
if (! bpb.sectors_per_fat_16)
|
||||
{
|
||||
/* FAT32. */
|
||||
|
@ -243,6 +387,7 @@ grub_fat_mount (grub_disk_t disk)
|
|||
data->cluster_eof_mark = 0xfff8;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* More sanity checks. */
|
||||
if (data->num_sectors <= data->fat_sector)
|
||||
|
@ -274,17 +419,25 @@ grub_fat_mount (grub_disk_t disk)
|
|||
}
|
||||
|
||||
/* Serial number. */
|
||||
#ifdef MODE_EXFAT
|
||||
data->uuid = grub_le_to_cpu32 (bpb.num_serial);
|
||||
#else
|
||||
if (bpb.sectors_per_fat_16)
|
||||
data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial);
|
||||
else
|
||||
data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial);
|
||||
#endif
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
/* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media
|
||||
descriptor, even if it is a so-called superfloppy (e.g. an USB key).
|
||||
The check may be too strict for this kind of stupid BIOSes, as
|
||||
they overwrite the media descriptor. */
|
||||
if ((first_fat | 0x8) != (magic | bpb.media | 0x8))
|
||||
goto fail;
|
||||
#else
|
||||
(void) magic;
|
||||
#endif
|
||||
|
||||
/* Start from the root directory. */
|
||||
data->file_cluster = data->root_cluster;
|
||||
|
@ -311,6 +464,7 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
|
|||
grub_ssize_t ret = 0;
|
||||
unsigned long sector;
|
||||
|
||||
#ifndef MODE_EXFAT
|
||||
/* This is a special case. FAT12 and FAT16 doesn't have the root directory
|
||||
in clusters. */
|
||||
if (data->file_cluster == ~0U)
|
||||
|
@ -324,13 +478,14 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate the logical cluster number and offset. */
|
||||
logical_cluster_bits = (data->cluster_bits
|
||||
+ data->logical_sector_bits
|
||||
+ GRUB_DISK_SECTOR_BITS);
|
||||
logical_cluster = offset >> logical_cluster_bits;
|
||||
offset &= (1 << logical_cluster_bits) - 1;
|
||||
offset &= (1ULL << logical_cluster_bits) - 1;
|
||||
|
||||
if (logical_cluster < data->cur_cluster_num)
|
||||
{
|
||||
|
@ -422,13 +577,116 @@ grub_fat_read_data (grub_disk_t disk, struct grub_fat_data *data,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
static grub_err_t
|
||||
grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
||||
int (*hook) (const char *filename,
|
||||
grub_fat_dir_node_t *node))
|
||||
{
|
||||
struct grub_fat_dir_entry dir;
|
||||
grub_ssize_t offset = -sizeof(dir);
|
||||
grub_uint16_t *unibuf;
|
||||
char *filename;
|
||||
|
||||
unibuf = grub_malloc (15 * 256 * 2);
|
||||
filename = grub_malloc (15 * 256 * GRUB_MAX_UTF8_PER_UTF16 + 1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
offset += sizeof (dir);
|
||||
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir))
|
||||
break;
|
||||
|
||||
if (dir.entry_type == 0)
|
||||
break;
|
||||
if (!(dir.entry_type & 0x80))
|
||||
continue;
|
||||
|
||||
if (dir.entry_type == 0x85)
|
||||
{
|
||||
unsigned i, nsec, slots = 0;
|
||||
grub_fat_dir_node_t node;
|
||||
|
||||
nsec = dir.type_specific.file.secondary_count;
|
||||
|
||||
node.attr = grub_cpu_to_le32 (dir.type_specific.file.attr);
|
||||
node.have_stream = 0;
|
||||
for (i = 0; i < nsec; i++)
|
||||
{
|
||||
struct grub_fat_dir_entry sec;
|
||||
offset += sizeof (sec);
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (sec), (char *) &sec)
|
||||
!= sizeof (sec))
|
||||
break;
|
||||
if (!(sec.entry_type & 0x80))
|
||||
continue;
|
||||
if (!(sec.entry_type & 0x40))
|
||||
break;
|
||||
switch (sec.entry_type)
|
||||
{
|
||||
case 0xc0:
|
||||
node.first_cluster = grub_cpu_to_le32 (sec.type_specific.stream_extension.first_cluster);
|
||||
node.valid_size
|
||||
= grub_cpu_to_le64 (sec.type_specific.stream_extension.valid_size);
|
||||
node.file_size
|
||||
= grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size);
|
||||
node.have_stream = 1;
|
||||
break;
|
||||
case 0xc1:
|
||||
grub_memcpy (unibuf + slots * 15,
|
||||
sec.type_specific.file_name.str, 30);
|
||||
slots++;
|
||||
break;
|
||||
default:
|
||||
grub_dprintf ("exfat", "unknown secondary type 0x%02x\n",
|
||||
sec.entry_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (i != nsec)
|
||||
{
|
||||
offset -= sizeof (dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
|
||||
slots * 15) = '\0';
|
||||
|
||||
if (hook (filename, &node))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
/* Allocation bitmap. */
|
||||
if (dir.entry_type == 0x81)
|
||||
continue;
|
||||
/* Upcase table. */
|
||||
if (dir.entry_type == 0x82)
|
||||
continue;
|
||||
/* Volume label. */
|
||||
if (dir.entry_type == 0x83)
|
||||
continue;
|
||||
grub_dprintf ("exfat", "unknown primary type 0x%02x\n", dir.entry_type);
|
||||
}
|
||||
grub_free (filename);
|
||||
grub_free (unibuf);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
||||
int (*hook) (const char *filename,
|
||||
struct grub_fat_dir_entry *dir))
|
||||
{
|
||||
struct grub_fat_dir_entry dir;
|
||||
char *filename, *filep = 0;
|
||||
char *filename;
|
||||
char *filep = 0;
|
||||
grub_uint16_t *unibuf;
|
||||
int slot = -1, slots = -1;
|
||||
int checksum = -1;
|
||||
|
@ -438,7 +696,7 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
|
||||
|
||||
/* Allocate space enough to hold a long name. */
|
||||
filename = grub_malloc (0x40 * 13 * 4 + 1);
|
||||
filename = grub_malloc (0x40 * 13 * GRUB_MAX_UTF8_PER_UTF16 + 1);
|
||||
unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
|
||||
if (! filename || ! unibuf)
|
||||
{
|
||||
|
@ -455,10 +713,11 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
offset += sizeof (dir);
|
||||
|
||||
/* Read a directory entry. */
|
||||
if ((grub_fat_read_data (disk, data, 0,
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir) || dir.name[0] == 0))
|
||||
!= sizeof (dir) || dir.name[0] == 0)
|
||||
break;
|
||||
|
||||
/* Handle long name entries. */
|
||||
if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
|
||||
{
|
||||
|
@ -543,7 +802,6 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
filep++;
|
||||
}
|
||||
*filep = '\0';
|
||||
|
||||
if (hook (filename, &dir))
|
||||
break;
|
||||
}
|
||||
|
@ -553,7 +811,7 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Find the underlying directory or file in PATH and return the
|
||||
next path. If there is no next path or an error occurs, return NULL.
|
||||
|
@ -565,11 +823,12 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
const struct grub_dirhook_info *info))
|
||||
{
|
||||
char *dirname, *dirp;
|
||||
char *origpath = NULL;
|
||||
int call_hook;
|
||||
int found = 0;
|
||||
|
||||
auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
|
||||
int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
|
||||
auto int iter_hook (const char *filename, grub_fat_dir_node_t *dir);
|
||||
int iter_hook (const char *filename, grub_fat_dir_node_t *dir)
|
||||
{
|
||||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
|
@ -577,8 +836,13 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
info.dir = !! (dir->attr & GRUB_FAT_ATTR_DIRECTORY);
|
||||
info.case_insensitive = 1;
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
if (!dir->have_stream)
|
||||
return 0;
|
||||
#else
|
||||
if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
|
||||
return 0;
|
||||
#endif
|
||||
if (*dirname == '\0' && call_hook)
|
||||
return hook (filename, &info);
|
||||
|
||||
|
@ -586,9 +850,14 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
{
|
||||
found = 1;
|
||||
data->attr = dir->attr;
|
||||
#ifdef MODE_EXFAT
|
||||
data->file_size = dir->file_size;
|
||||
data->file_cluster = dir->first_cluster;
|
||||
#else
|
||||
data->file_size = grub_le_to_cpu32 (dir->file_size);
|
||||
data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
|
||||
| grub_le_to_cpu16 (dir->first_cluster_low));
|
||||
#endif
|
||||
data->cur_cluster_num = ~0U;
|
||||
|
||||
if (call_hook)
|
||||
|
@ -605,6 +874,10 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
origpath = grub_strdup (path);
|
||||
if (!origpath)
|
||||
return 0;
|
||||
|
||||
/* Extract a directory name. */
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
@ -616,7 +889,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
dirname = grub_malloc (len + 1);
|
||||
if (! dirname)
|
||||
return 0;
|
||||
goto fail;
|
||||
|
||||
grub_memcpy (dirname, path, len);
|
||||
dirname[len] = '\0';
|
||||
|
@ -629,9 +902,11 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
|
|||
|
||||
grub_fat_iterate_dir (disk, data, iter_hook);
|
||||
if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
|
||||
fail:
|
||||
grub_free (dirname);
|
||||
grub_free (origpath);
|
||||
|
||||
return found ? dirp : 0;
|
||||
}
|
||||
|
@ -738,14 +1013,67 @@ grub_fat_close (grub_file_t file)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
static grub_err_t
|
||||
grub_fat_label (grub_device_t device, char **label)
|
||||
{
|
||||
struct grub_fat_dir_entry dir;
|
||||
grub_ssize_t offset = -sizeof(dir);
|
||||
struct grub_fat_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
|
||||
data = grub_fat_mount (disk);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
*label = NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
offset += sizeof (dir);
|
||||
|
||||
if (grub_fat_read_data (disk, data, 0,
|
||||
offset, sizeof (dir), (char *) &dir)
|
||||
!= sizeof (dir))
|
||||
break;
|
||||
|
||||
if (dir.entry_type == 0)
|
||||
break;
|
||||
if (!(dir.entry_type & 0x80))
|
||||
continue;
|
||||
|
||||
/* Volume label. */
|
||||
if (dir.entry_type == 0x83)
|
||||
{
|
||||
grub_size_t chc;
|
||||
*label = grub_malloc (11 * 4 + 1);
|
||||
if (!*label)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
chc = dir.type_specific.volume_label.character_count;
|
||||
if (chc > ARRAY_SIZE (dir.type_specific.volume_label.str))
|
||||
chc = ARRAY_SIZE (dir.type_specific.volume_label.str);
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) *label,
|
||||
dir.type_specific.volume_label.str, chc) = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_label (grub_device_t device, char **label)
|
||||
{
|
||||
struct grub_fat_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
|
||||
auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
|
||||
int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
|
||||
auto int iter_hook (const char *filename, grub_fat_dir_node_t *dir);
|
||||
int iter_hook (const char *filename, grub_fat_dir_node_t *dir)
|
||||
{
|
||||
if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
|
||||
{
|
||||
|
@ -780,6 +1108,8 @@ grub_fat_label (grub_device_t device, char **label)
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_fat_uuid (grub_device_t device, char **uuid)
|
||||
{
|
||||
|
@ -791,9 +1121,12 @@ grub_fat_uuid (grub_device_t device, char **uuid)
|
|||
data = grub_fat_mount (disk);
|
||||
if (data)
|
||||
{
|
||||
char *ptr;
|
||||
*uuid = grub_xasprintf ("%04x-%04x",
|
||||
(grub_uint16_t) (data->uuid >> 16),
|
||||
(grub_uint16_t) data->uuid);
|
||||
for (ptr = *uuid; ptr && *ptr; ptr++)
|
||||
*ptr = grub_toupper (*ptr);
|
||||
}
|
||||
else
|
||||
*uuid = NULL;
|
||||
|
@ -807,7 +1140,11 @@ grub_fat_uuid (grub_device_t device, char **uuid)
|
|||
|
||||
static struct grub_fs grub_fat_fs =
|
||||
{
|
||||
#ifdef MODE_EXFAT
|
||||
.name = "exfat",
|
||||
#else
|
||||
.name = "fat",
|
||||
#endif
|
||||
.dir = grub_fat_dir,
|
||||
.open = grub_fat_open,
|
||||
.read = grub_fat_read,
|
||||
|
@ -815,18 +1152,31 @@ static struct grub_fs grub_fat_fs =
|
|||
.label = grub_fat_label,
|
||||
.uuid = grub_fat_uuid,
|
||||
#ifdef GRUB_UTIL
|
||||
#ifdef MODE_EXFAT
|
||||
/* ExFAT BPB is 30 larger than FAT32 one. */
|
||||
.reserved_first_sector = 0,
|
||||
#else
|
||||
.reserved_first_sector = 1,
|
||||
#endif
|
||||
#endif
|
||||
.next = 0
|
||||
};
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
GRUB_MOD_INIT(exfat)
|
||||
#else
|
||||
GRUB_MOD_INIT(fat)
|
||||
#endif
|
||||
{
|
||||
COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32);
|
||||
grub_fs_register (&grub_fat_fs);
|
||||
my_mod = mod;
|
||||
}
|
||||
|
||||
#ifdef MODE_EXFAT
|
||||
GRUB_MOD_FINI(exfat)
|
||||
#else
|
||||
GRUB_MOD_FINI(fat)
|
||||
#endif
|
||||
{
|
||||
grub_fs_unregister (&grub_fat_fs);
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
|
|||
char fpath[grub_strlen (currpath) + 1];
|
||||
char *name = fpath;
|
||||
char *next;
|
||||
// unsigned int pos = 0;
|
||||
enum grub_fshelp_filetype type = GRUB_FSHELP_DIR;
|
||||
grub_fshelp_node_t currnode = currroot;
|
||||
grub_fshelp_node_t oldnode = currroot;
|
||||
|
@ -197,7 +196,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
|
|||
name = next;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
}
|
||||
|
||||
if (!path || path[0] != '/')
|
||||
|
|
|
@ -244,22 +244,24 @@ static grub_ssize_t
|
|||
grub_hfs_read_file (struct grub_hfs_data *data,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
int i;
|
||||
int blockcnt;
|
||||
grub_off_t i;
|
||||
grub_off_t blockcnt;
|
||||
|
||||
blockcnt = ((len + pos)
|
||||
+ data->blksz - 1) / data->blksz;
|
||||
blockcnt = grub_divmod64 (((len + pos)
|
||||
+ data->blksz - 1), data->blksz, 0);
|
||||
|
||||
for (i = pos / data->blksz; i < blockcnt; i++)
|
||||
for (i = grub_divmod64 (pos, data->blksz, 0); i < blockcnt; i++)
|
||||
{
|
||||
int blknr;
|
||||
int blockoff = pos % data->blksz;
|
||||
int blockend = data->blksz;
|
||||
grub_disk_addr_t blknr;
|
||||
grub_off_t blockoff;
|
||||
grub_off_t blockend = data->blksz;
|
||||
|
||||
int skipfirst = 0;
|
||||
|
||||
grub_divmod64 (pos, data->blksz, &blockoff);
|
||||
|
||||
blknr = grub_hfs_block (data, data->extents, data->fileid, i, 1);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
@ -267,7 +269,7 @@ grub_hfs_read_file (struct grub_hfs_data *data,
|
|||
/* Last block. */
|
||||
if (i == blockcnt - 1)
|
||||
{
|
||||
blockend = (len + pos) % data->blksz;
|
||||
grub_divmod64 ((len + pos), data->blksz, &blockend);
|
||||
|
||||
/* The last portion is exactly EXT2_BLOCK_SIZE (data). */
|
||||
if (! blockend)
|
||||
|
@ -275,7 +277,7 @@ grub_hfs_read_file (struct grub_hfs_data *data,
|
|||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == pos / data->blksz)
|
||||
if (i == grub_divmod64 (pos, data->blksz, 0))
|
||||
{
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
|
@ -748,10 +750,7 @@ grub_hfs_find_node (struct grub_hfs_data *data, char *key,
|
|||
entry. In case of a non-leaf mode it will be used to lookup
|
||||
the rest of the tree. */
|
||||
if (cmp <= 0)
|
||||
{
|
||||
grub_uint32_t *node = (grub_uint32_t *) rec->data;
|
||||
found = grub_be_to_cpu32 (*node);
|
||||
}
|
||||
found = grub_be_to_cpu32 (grub_get_unaligned32 (rec->data));
|
||||
else /* The key can not be found in the tree. */
|
||||
return 1;
|
||||
|
||||
|
@ -815,7 +814,7 @@ grub_hfs_iterate_dir (struct grub_hfs_data *data, grub_uint32_t root_idx,
|
|||
struct grub_hfs_catalog_key *ckey = rec->key;
|
||||
|
||||
if (grub_hfs_cmp_catkeys (rec->key, (void *) &key) <= 0)
|
||||
found = grub_be_to_cpu32 (*(grub_uint32_t *) rec->data);
|
||||
found = grub_be_to_cpu32 (grub_get_unaligned32 (rec->data));
|
||||
|
||||
if (hnd->type == 0xFF && ckey->strlen > 0)
|
||||
{
|
||||
|
@ -921,7 +920,7 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
|
|||
if (! grub_hfs_find_node (data, (char *) &key, data->cat_root,
|
||||
0, (char *) &fdrec.frec, sizeof (fdrec.frec)))
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", origpath);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,8 @@ enum grub_hfsplus_filetype
|
|||
struct grub_hfsplus_catkey_internal
|
||||
{
|
||||
grub_uint32_t parent;
|
||||
char *name;
|
||||
const grub_uint16_t *name;
|
||||
grub_size_t namelen;
|
||||
};
|
||||
|
||||
/* Internal representation of an extent overflow key. */
|
||||
|
@ -214,7 +215,7 @@ struct grub_fshelp_node
|
|||
struct grub_hfsplus_btree
|
||||
{
|
||||
grub_uint32_t root;
|
||||
int nodesize;
|
||||
grub_size_t nodesize;
|
||||
|
||||
/* Catalog file node. */
|
||||
struct grub_fshelp_node file;
|
||||
|
@ -236,7 +237,7 @@ struct grub_hfsplus_data
|
|||
|
||||
/* This is the offset into the physical disk for an embedded HFS+
|
||||
filesystem (one inside a plain HFS wrapper). */
|
||||
int embedded_offset;
|
||||
grub_disk_addr_t embedded_offset;
|
||||
int case_sensitive;
|
||||
};
|
||||
|
||||
|
@ -245,15 +246,14 @@ static grub_dl_t my_mod;
|
|||
|
||||
/* Return the offset of the record with the index INDEX, in the node
|
||||
NODE which is part of the B+ tree BTREE. */
|
||||
static inline unsigned int
|
||||
static inline grub_off_t
|
||||
grub_hfsplus_btree_recoffset (struct grub_hfsplus_btree *btree,
|
||||
struct grub_hfsplus_btnode *node, int index)
|
||||
{
|
||||
char *cnode = (char *) node;
|
||||
grub_uint16_t *recptr;
|
||||
recptr = (grub_uint16_t *) (&cnode[btree->nodesize
|
||||
- index * sizeof (grub_uint16_t) - 2]);
|
||||
return grub_be_to_cpu16 (*recptr);
|
||||
void *recptr;
|
||||
recptr = (&cnode[btree->nodesize - index * sizeof (grub_uint16_t) - 2]);
|
||||
return grub_be_to_cpu16 (grub_get_unaligned16 (recptr));
|
||||
}
|
||||
|
||||
/* Return a pointer to the record with the index INDEX, in the node
|
||||
|
@ -263,7 +263,7 @@ grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree,
|
|||
struct grub_hfsplus_btnode *node, int index)
|
||||
{
|
||||
char *cnode = (char *) node;
|
||||
unsigned int offset;
|
||||
grub_off_t offset;
|
||||
offset = grub_hfsplus_btree_recoffset (btree, node, index);
|
||||
return (struct grub_hfsplus_key *) &cnode[offset];
|
||||
}
|
||||
|
@ -272,12 +272,12 @@ grub_hfsplus_btree_recptr (struct grub_hfsplus_btree *btree,
|
|||
/* Find the extent that points to FILEBLOCK. If it is not in one of
|
||||
the 8 extents described by EXTENT, return -1. In that case set
|
||||
FILEBLOCK to the next block. */
|
||||
static int
|
||||
static grub_disk_addr_t
|
||||
grub_hfsplus_find_block (struct grub_hfsplus_extent *extent,
|
||||
int *fileblock)
|
||||
grub_disk_addr_t *fileblock)
|
||||
{
|
||||
int i;
|
||||
grub_size_t blksleft = *fileblock;
|
||||
grub_disk_addr_t blksleft = *fileblock;
|
||||
|
||||
/* First lookup the file in the given extents. */
|
||||
for (i = 0; i < 8; i++)
|
||||
|
@ -288,7 +288,7 @@ grub_hfsplus_find_block (struct grub_hfsplus_extent *extent,
|
|||
}
|
||||
|
||||
*fileblock = blksleft;
|
||||
return -1;
|
||||
return 0xffffffffffffffffULL;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
@ -296,7 +296,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
struct grub_hfsplus_key_internal *key,
|
||||
int (*compare_keys) (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb),
|
||||
struct grub_hfsplus_btnode **matchnode, int *keyoffset);
|
||||
struct grub_hfsplus_btnode **matchnode,
|
||||
grub_off_t *keyoffset);
|
||||
|
||||
static int grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb);
|
||||
|
@ -307,15 +308,15 @@ static grub_disk_addr_t
|
|||
grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
||||
{
|
||||
struct grub_hfsplus_btnode *nnode = 0;
|
||||
int blksleft = fileblock;
|
||||
grub_disk_addr_t blksleft = fileblock;
|
||||
struct grub_hfsplus_extent *extents = &node->extents[0];
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct grub_hfsplus_extkey *key;
|
||||
struct grub_hfsplus_extkey_internal extoverflow;
|
||||
int blk;
|
||||
int ptr;
|
||||
struct grub_hfsplus_key_internal extoverflow;
|
||||
grub_disk_addr_t blk;
|
||||
grub_off_t ptr;
|
||||
|
||||
/* Try to find this block in the current set of extents. */
|
||||
blk = grub_hfsplus_find_block (extents, &blksleft);
|
||||
|
@ -325,7 +326,7 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
grub_free (nnode);
|
||||
nnode = 0;
|
||||
|
||||
if (blk != -1)
|
||||
if (blk != 0xffffffffffffffffULL)
|
||||
return (blk
|
||||
+ (node->data->embedded_offset >> (node->data->log2blksize
|
||||
- GRUB_DISK_SECTOR_BITS)));
|
||||
|
@ -341,11 +342,11 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
|
|||
}
|
||||
|
||||
/* Set up the key to look for in the extent overflow file. */
|
||||
extoverflow.fileid = node->fileid;
|
||||
extoverflow.start = fileblock - blksleft;
|
||||
extoverflow.extkey.fileid = node->fileid;
|
||||
extoverflow.extkey.start = fileblock - blksleft;
|
||||
|
||||
if (grub_hfsplus_btree_search (&node->data->extoverflow_tree,
|
||||
(struct grub_hfsplus_key_internal *) &extoverflow,
|
||||
&extoverflow,
|
||||
grub_hfsplus_cmp_extkey, &nnode, &ptr))
|
||||
{
|
||||
grub_error (GRUB_ERR_READ_ERROR,
|
||||
|
@ -376,7 +377,7 @@ static grub_ssize_t
|
|||
grub_hfsplus_read_file (grub_fshelp_node_t node,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
int pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
return grub_fshelp_read_file (node->data->disk, node, read_hook,
|
||||
pos, len, buf, grub_hfsplus_read_block,
|
||||
|
@ -411,9 +412,9 @@ grub_hfsplus_mount (grub_disk_t disk)
|
|||
data->embedded_offset = 0;
|
||||
if (grub_be_to_cpu16 (volheader.hfs.magic) == GRUB_HFS_MAGIC)
|
||||
{
|
||||
int extent_start;
|
||||
int ablk_size;
|
||||
int ablk_start;
|
||||
grub_disk_addr_t extent_start;
|
||||
grub_disk_addr_t ablk_size;
|
||||
grub_disk_addr_t ablk_start;
|
||||
|
||||
/* See if there's an embedded HFS+ filesystem. */
|
||||
if (grub_be_to_cpu16 (volheader.hfs.embed_sig) != GRUB_HFSPLUS_MAGIC)
|
||||
|
@ -518,8 +519,6 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya,
|
|||
{
|
||||
struct grub_hfsplus_catkey *catkey_a = &keya->catkey;
|
||||
struct grub_hfsplus_catkey_internal *catkey_b = &keyb->catkey;
|
||||
char *filename;
|
||||
int i;
|
||||
int diff;
|
||||
|
||||
/* Safe unsigned comparison */
|
||||
|
@ -529,29 +528,35 @@ grub_hfsplus_cmp_catkey (struct grub_hfsplus_key *keya,
|
|||
if (aparent < catkey_b->parent)
|
||||
return -1;
|
||||
|
||||
/* Change the filename in keya so the endianness is correct. */
|
||||
for (i = 0; i < grub_be_to_cpu16 (catkey_a->namelen); i++)
|
||||
catkey_a->name[i] = grub_be_to_cpu16 (catkey_a->name[i]);
|
||||
diff = grub_memcmp (catkey_a->name, catkey_b->name,
|
||||
grub_min (grub_be_to_cpu16 (catkey_a->namelen),
|
||||
catkey_b->namelen)
|
||||
* sizeof (catkey_a->name[0]));
|
||||
if (diff == 0)
|
||||
diff = grub_be_to_cpu16 (catkey_a->namelen) - catkey_b->namelen;
|
||||
|
||||
filename = grub_malloc (grub_be_to_cpu16 (catkey_a->namelen) + 1);
|
||||
|
||||
if (! grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey_a->name,
|
||||
grub_be_to_cpu16 (catkey_a->namelen)))
|
||||
return -1; /* XXX: This error never occurs, but in case it happens
|
||||
just skip this entry. */
|
||||
|
||||
diff = grub_strncmp (filename, catkey_b->name,
|
||||
grub_be_to_cpu16 (catkey_a->namelen));
|
||||
|
||||
grub_free (filename);
|
||||
|
||||
/* The endianness was changed to host format, change it back to
|
||||
whatever it was. */
|
||||
for (i = 0; i < grub_be_to_cpu16 (catkey_a->namelen); i++)
|
||||
catkey_a->name[i] = grub_cpu_to_be16 (catkey_a->name[i]);
|
||||
return diff;
|
||||
}
|
||||
|
||||
/* Compare the on disk catalog key KEYA with the catalog key we are
|
||||
looking for (KEYB). */
|
||||
static int
|
||||
grub_hfsplus_cmp_catkey_id (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb)
|
||||
{
|
||||
struct grub_hfsplus_catkey *catkey_a = &keya->catkey;
|
||||
struct grub_hfsplus_catkey_internal *catkey_b = &keyb->catkey;
|
||||
|
||||
/* Safe unsigned comparison */
|
||||
grub_uint32_t aparent = grub_be_to_cpu32 (catkey_a->parent);
|
||||
if (aparent > catkey_b->parent)
|
||||
return 1;
|
||||
if (aparent < catkey_b->parent)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare the on disk extent overflow key KEYA with the extent
|
||||
overflow key we are looking for (KEYB). */
|
||||
static int
|
||||
|
@ -601,10 +606,10 @@ grub_hfsplus_read_symlink (grub_fshelp_node_t node)
|
|||
static int
|
||||
grub_hfsplus_btree_iterate_node (struct grub_hfsplus_btree *btree,
|
||||
struct grub_hfsplus_btnode *first_node,
|
||||
int first_rec,
|
||||
grub_disk_addr_t first_rec,
|
||||
int (*hook) (void *record))
|
||||
{
|
||||
int rec;
|
||||
grub_disk_addr_t rec;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
@ -642,12 +647,13 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
struct grub_hfsplus_key_internal *key,
|
||||
int (*compare_keys) (struct grub_hfsplus_key *keya,
|
||||
struct grub_hfsplus_key_internal *keyb),
|
||||
struct grub_hfsplus_btnode **matchnode, int *keyoffset)
|
||||
struct grub_hfsplus_btnode **matchnode,
|
||||
grub_off_t *keyoffset)
|
||||
{
|
||||
grub_uint64_t currnode;
|
||||
char *node;
|
||||
struct grub_hfsplus_btnode *nodedesc;
|
||||
int rec;
|
||||
grub_disk_addr_t rec;
|
||||
|
||||
node = grub_malloc (btree->nodesize);
|
||||
if (! node)
|
||||
|
@ -660,7 +666,8 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
|
||||
/* Read a node. */
|
||||
if (grub_hfsplus_read_file (&btree->file, 0,
|
||||
(long)currnode * (long)btree->nodesize,
|
||||
(grub_disk_addr_t) currnode
|
||||
* (grub_disk_addr_t) btree->nodesize,
|
||||
btree->nodesize, (char *) node) <= 0)
|
||||
{
|
||||
grub_free (node);
|
||||
|
@ -689,7 +696,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
}
|
||||
else if (nodedesc->type == GRUB_HFSPLUS_BTNODE_TYPE_INDEX)
|
||||
{
|
||||
grub_uint32_t *pointer;
|
||||
void *pointer;
|
||||
|
||||
/* The place where the key could have been found didn't
|
||||
contain the key. This means that the previous match
|
||||
|
@ -701,10 +708,10 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree,
|
|||
that we are looking for. The last match that is
|
||||
found will be used to locate the child which can
|
||||
contain the record. */
|
||||
pointer = (grub_uint32_t *) ((char *) currkey
|
||||
+ grub_be_to_cpu16 (currkey->keylen)
|
||||
+ 2);
|
||||
currnode = grub_be_to_cpu32 (*pointer);
|
||||
pointer = ((char *) currkey
|
||||
+ grub_be_to_cpu16 (currkey->keylen)
|
||||
+ 2);
|
||||
currnode = grub_be_to_cpu32 (grub_get_unaligned32 (pointer));
|
||||
match = 1;
|
||||
}
|
||||
}
|
||||
|
@ -770,6 +777,11 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (type == GRUB_FSHELP_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
filename = grub_malloc (grub_be_to_cpu16 (catkey->namelen)
|
||||
* GRUB_MAX_UTF8_PER_UTF16 + 1);
|
||||
if (! filename)
|
||||
return 0;
|
||||
|
||||
/* Make sure the byte order of the UTF16 string is correct. */
|
||||
for (i = 0; i < grub_be_to_cpu16 (catkey->namelen); i++)
|
||||
{
|
||||
|
@ -780,18 +792,8 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
return 0;
|
||||
}
|
||||
|
||||
filename = grub_malloc (grub_be_to_cpu16 (catkey->namelen) + 1);
|
||||
if (! filename)
|
||||
return 0;
|
||||
|
||||
if (! grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name,
|
||||
grub_be_to_cpu16 (catkey->namelen)))
|
||||
{
|
||||
grub_free (filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
filename[grub_be_to_cpu16 (catkey->namelen)] = '\0';
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) filename, catkey->name,
|
||||
grub_be_to_cpu16 (catkey->namelen)) = '\0';
|
||||
|
||||
/* Restore the byte order to what it was previously. */
|
||||
for (i = 0; i < grub_be_to_cpu16 (catkey->namelen); i++)
|
||||
|
@ -801,22 +803,18 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (! dir->data->case_sensitive)
|
||||
type |= GRUB_FSHELP_CASE_INSENSITIVE;
|
||||
|
||||
/* Only accept valid nodes. */
|
||||
if (grub_strlen (filename) == grub_be_to_cpu16 (catkey->namelen))
|
||||
{
|
||||
/* A valid node is found; setup the node and call the
|
||||
callback function. */
|
||||
node = grub_malloc (sizeof (*node));
|
||||
node->data = dir->data;
|
||||
/* A valid node is found; setup the node and call the
|
||||
callback function. */
|
||||
node = grub_malloc (sizeof (*node));
|
||||
node->data = dir->data;
|
||||
|
||||
grub_memcpy (node->extents, fileinfo->data.extents,
|
||||
sizeof (node->extents));
|
||||
node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
|
||||
node->size = grub_be_to_cpu64 (fileinfo->data.size);
|
||||
node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
|
||||
grub_memcpy (node->extents, fileinfo->data.extents,
|
||||
sizeof (node->extents));
|
||||
node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
|
||||
node->size = grub_be_to_cpu64 (fileinfo->data.size);
|
||||
node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
|
||||
|
||||
ret = hook (filename, type, node);
|
||||
}
|
||||
ret = hook (filename, type, node);
|
||||
|
||||
grub_free (filename);
|
||||
|
||||
|
@ -825,11 +823,12 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
|
|||
|
||||
struct grub_hfsplus_key_internal intern;
|
||||
struct grub_hfsplus_btnode *node;
|
||||
int ptr;
|
||||
grub_disk_addr_t ptr;
|
||||
|
||||
/* Create a key that points to the first entry in the directory. */
|
||||
intern.catkey.parent = dir->fileid;
|
||||
intern.catkey.name = "";
|
||||
intern.catkey.name = 0;
|
||||
intern.catkey.namelen = 0;
|
||||
|
||||
/* First lookup the first entry. */
|
||||
if (grub_hfsplus_btree_search (&dir->data->catalog_tree, &intern,
|
||||
|
@ -894,7 +893,6 @@ grub_hfsplus_close (grub_file_t file)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/* Read LEN bytes data from FILE into BUF. */
|
||||
static grub_ssize_t
|
||||
grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
|
@ -902,13 +900,10 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
struct grub_hfsplus_data *data =
|
||||
(struct grub_hfsplus_data *) file->data;
|
||||
|
||||
int size = grub_hfsplus_read_file (&data->opened_file, file->read_hook,
|
||||
return grub_hfsplus_read_file (&data->opened_file, file->read_hook,
|
||||
file->offset, len, buf);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static grub_err_t
|
||||
grub_hfsplus_dir (grub_device_t device, const char *path,
|
||||
int (*hook) (const char *filename,
|
||||
|
@ -963,13 +958,59 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
|
|||
|
||||
|
||||
static grub_err_t
|
||||
grub_hfsplus_label (grub_device_t device __attribute__((unused))
|
||||
, char **label __attribute__((unused)))
|
||||
grub_hfsplus_label (grub_device_t device, char **label)
|
||||
{
|
||||
/* XXX: It's not documented how to read a label. */
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"reading the label of a HFS+ "
|
||||
"partition is not implemented");
|
||||
struct grub_hfsplus_data *data;
|
||||
grub_disk_t disk = device->disk;
|
||||
struct grub_hfsplus_catkey *catkey;
|
||||
int i, label_len;
|
||||
struct grub_hfsplus_key_internal intern;
|
||||
struct grub_hfsplus_btnode *node;
|
||||
grub_disk_addr_t ptr;
|
||||
|
||||
*label = 0;
|
||||
|
||||
data = grub_hfsplus_mount (disk);
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
/* Create a key that points to the label. */
|
||||
intern.catkey.parent = 1;
|
||||
intern.catkey.name = 0;
|
||||
intern.catkey.namelen = 0;
|
||||
|
||||
/* First lookup the first entry. */
|
||||
if (grub_hfsplus_btree_search (&data->catalog_tree, &intern,
|
||||
grub_hfsplus_cmp_catkey_id, &node, &ptr))
|
||||
{
|
||||
grub_free (data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
catkey = (struct grub_hfsplus_catkey *)
|
||||
grub_hfsplus_btree_recptr (&data->catalog_tree, node, 0);
|
||||
|
||||
label_len = grub_be_to_cpu16 (catkey->namelen);
|
||||
for (i = 0; i < label_len; i++)
|
||||
{
|
||||
catkey->name[i] = grub_be_to_cpu16 (catkey->name[i]);
|
||||
|
||||
/* If the name is obviously invalid, skip this node. */
|
||||
if (catkey->name[i] == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*label = grub_malloc (label_len * GRUB_MAX_UTF8_PER_UTF16 + 1);
|
||||
if (! *label)
|
||||
return grub_errno;
|
||||
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) (*label), catkey->name,
|
||||
label_len) = '\0';
|
||||
|
||||
grub_free (node);
|
||||
grub_free (data);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Get mtime. */
|
||||
|
|
|
@ -1,653 +0,0 @@
|
|||
/* pxe.c - Driver to provide access to the pxe filesystem */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/bufio.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
#include <grub/machine/pxe.h>
|
||||
#include <grub/machine/int.h>
|
||||
#include <grub/machine/memory.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#define SEGMENT(x) ((x) >> 4)
|
||||
#define OFFSET(x) ((x) & 0xF)
|
||||
#define SEGOFS(x) ((SEGMENT(x) << 16) + OFFSET(x))
|
||||
#define LINEAR(x) (void *) (((x >> 16) <<4) + (x & 0xFFFF))
|
||||
|
||||
struct grub_pxe_disk_data
|
||||
{
|
||||
grub_uint32_t server_ip;
|
||||
grub_uint32_t gateway_ip;
|
||||
};
|
||||
|
||||
struct grub_pxe_bangpxe *grub_pxe_pxenv;
|
||||
static grub_uint32_t grub_pxe_your_ip;
|
||||
static grub_uint32_t grub_pxe_default_server_ip;
|
||||
static grub_uint32_t grub_pxe_default_gateway_ip;
|
||||
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
|
||||
|
||||
static grub_file_t curr_file = 0;
|
||||
|
||||
struct grub_pxe_data
|
||||
{
|
||||
grub_uint32_t packet_number;
|
||||
grub_uint32_t block_size;
|
||||
char filename[0];
|
||||
};
|
||||
|
||||
static grub_uint32_t pxe_rm_entry = 0;
|
||||
|
||||
static struct grub_pxe_bangpxe *
|
||||
grub_pxe_scan (void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
struct grub_pxenv *pxenv;
|
||||
struct grub_pxe_bangpxe *bangpxe;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
|
||||
regs.ebx = 0;
|
||||
regs.ecx = 0;
|
||||
regs.eax = 0x5650;
|
||||
regs.es = 0;
|
||||
|
||||
grub_bios_interrupt (0x1a, ®s);
|
||||
|
||||
if ((regs.eax & 0xffff) != 0x564e)
|
||||
return NULL;
|
||||
|
||||
pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
|
||||
if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
|
||||
sizeof (pxenv->signature))
|
||||
!= 0)
|
||||
return NULL;
|
||||
|
||||
if (pxenv->version < 0x201)
|
||||
return NULL;
|
||||
|
||||
bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
|
||||
+ (pxenv->pxe_ptr & 0xffff));
|
||||
|
||||
if (!bangpxe)
|
||||
return NULL;
|
||||
|
||||
if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
|
||||
sizeof (bangpxe->signature)) != 0)
|
||||
return NULL;
|
||||
|
||||
pxe_rm_entry = bangpxe->rm_entry;
|
||||
|
||||
return bangpxe;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_pxe_iterate (int (*hook) (const char *name))
|
||||
{
|
||||
if (hook ("pxe"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
|
||||
{
|
||||
grub_uint32_t newip = 0;
|
||||
unsigned long t;
|
||||
int i;
|
||||
const char *ptr = val;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
t = grub_strtoul (ptr, (char **) &ptr, 0);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
if (t & ~0xff)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
|
||||
newip >>= 8;
|
||||
newip |= (t << 24);
|
||||
if (i != 3 && *ptr != '.')
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid IP.");
|
||||
ptr++;
|
||||
}
|
||||
*ip = newip;
|
||||
if (rest)
|
||||
*rest = ptr - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxe_open (const char *name, grub_disk_t disk)
|
||||
{
|
||||
struct grub_pxe_disk_data *data;
|
||||
|
||||
if (grub_strcmp (name, "pxe") != 0
|
||||
&& grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a pxe disk");
|
||||
|
||||
data = grub_malloc (sizeof (*data));
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
|
||||
{
|
||||
const char *ptr;
|
||||
grub_err_t err;
|
||||
|
||||
ptr = name + sizeof ("pxe:") - 1;
|
||||
err = parse_ip (ptr, &(data->server_ip), &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
if (*ptr == ':')
|
||||
{
|
||||
err = parse_ip (ptr + 1, &(data->gateway_ip), 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
else
|
||||
data->gateway_ip = grub_pxe_default_gateway_ip;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->server_ip = grub_pxe_default_server_ip;
|
||||
data->gateway_ip = grub_pxe_default_gateway_ip;
|
||||
}
|
||||
|
||||
disk->total_sectors = 0;
|
||||
disk->id = (unsigned long) data;
|
||||
|
||||
disk->data = data;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_pxe_close (grub_disk_t disk)
|
||||
{
|
||||
grub_free (disk->data);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxe_read (grub_disk_t disk __attribute((unused)),
|
||||
grub_disk_addr_t sector __attribute((unused)),
|
||||
grub_size_t size __attribute((unused)),
|
||||
char *buf __attribute((unused)))
|
||||
{
|
||||
return GRUB_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxe_write (grub_disk_t disk __attribute((unused)),
|
||||
grub_disk_addr_t sector __attribute((unused)),
|
||||
grub_size_t size __attribute((unused)),
|
||||
const char *buf __attribute((unused)))
|
||||
{
|
||||
return GRUB_ERR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_pxe_dev =
|
||||
{
|
||||
.name = "pxe",
|
||||
.id = GRUB_DISK_DEVICE_PXE_ID,
|
||||
.iterate = grub_pxe_iterate,
|
||||
.open = grub_pxe_open,
|
||||
.close = grub_pxe_close,
|
||||
.read = grub_pxe_read,
|
||||
.write = grub_pxe_write,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_dir (grub_device_t device,
|
||||
const char *path __attribute__ ((unused)),
|
||||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info)
|
||||
__attribute__ ((unused)))
|
||||
{
|
||||
if (device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "not a pxe disk");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_open (struct grub_file *file, const char *name)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct grub_pxenv_tftp_get_fsize c1;
|
||||
struct grub_pxenv_tftp_open c2;
|
||||
} c;
|
||||
struct grub_pxe_data *data;
|
||||
struct grub_pxe_disk_data *disk_data = file->device->disk->data;
|
||||
grub_file_t file_int, bufio;
|
||||
|
||||
if (file->device->disk->dev->id != GRUB_DISK_DEVICE_PXE_ID)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "not a pxe disk");
|
||||
|
||||
if (curr_file != 0)
|
||||
{
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2, pxe_rm_entry);
|
||||
curr_file = 0;
|
||||
}
|
||||
|
||||
c.c1.server_ip = disk_data->server_ip;
|
||||
c.c1.gateway_ip = disk_data->gateway_ip;
|
||||
grub_strcpy ((char *)&c.c1.filename[0], name);
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry);
|
||||
if (c.c1.status)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
|
||||
file->size = c.c1.file_size;
|
||||
|
||||
c.c2.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
|
||||
c.c2.packet_size = grub_pxe_blksize;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry);
|
||||
if (c.c2.status)
|
||||
return grub_error (GRUB_ERR_BAD_FS, "open fails");
|
||||
|
||||
data = grub_zalloc (sizeof (struct grub_pxe_data) + grub_strlen (name) + 1);
|
||||
if (! data)
|
||||
return grub_errno;
|
||||
|
||||
data->block_size = c.c2.packet_size;
|
||||
grub_strcpy (data->filename, name);
|
||||
|
||||
file_int = grub_malloc (sizeof (*file_int));
|
||||
if (! file_int)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
file->data = data;
|
||||
file->not_easily_seekable = 1;
|
||||
grub_memcpy (file_int, file, sizeof (struct grub_file));
|
||||
curr_file = file_int;
|
||||
|
||||
bufio = grub_bufio_open (file_int, data->block_size);
|
||||
if (! bufio)
|
||||
{
|
||||
grub_free (file_int);
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_memcpy (file, bufio, sizeof (struct grub_file));
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_pxenv_tftp_read c;
|
||||
struct grub_pxe_data *data;
|
||||
struct grub_pxe_disk_data *disk_data = file->device->disk->data;
|
||||
grub_uint32_t pn;
|
||||
grub_uint64_t r;
|
||||
|
||||
data = file->data;
|
||||
|
||||
pn = grub_divmod64 (file->offset, data->block_size, &r);
|
||||
if (r)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS,
|
||||
"read access must be aligned to packet size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((curr_file != file) || (data->packet_number > pn))
|
||||
{
|
||||
struct grub_pxenv_tftp_open o;
|
||||
|
||||
if (curr_file != 0)
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry);
|
||||
|
||||
o.server_ip = disk_data->server_ip;
|
||||
o.gateway_ip = disk_data->gateway_ip;
|
||||
grub_strcpy ((char *)&o.filename[0], data->filename);
|
||||
o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
|
||||
o.packet_size = data->block_size;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry);
|
||||
if (o.status)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "open fails");
|
||||
return -1;
|
||||
}
|
||||
data->block_size = o.packet_size;
|
||||
data->packet_number = 0;
|
||||
curr_file = file;
|
||||
}
|
||||
|
||||
c.buffer = SEGOFS (GRUB_MEMORY_MACHINE_SCRATCH_ADDR);
|
||||
while (pn >= data->packet_number)
|
||||
{
|
||||
c.buffer_size = data->block_size;
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_READ, &c, pxe_rm_entry);
|
||||
if (c.status)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "read fails");
|
||||
return -1;
|
||||
}
|
||||
data->packet_number++;
|
||||
}
|
||||
|
||||
grub_memcpy (buf, (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_close (grub_file_t file)
|
||||
{
|
||||
struct grub_pxenv_tftp_close c;
|
||||
|
||||
if (curr_file == file)
|
||||
{
|
||||
grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c, pxe_rm_entry);
|
||||
curr_file = 0;
|
||||
}
|
||||
|
||||
grub_free (file->data);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_pxefs_label (grub_device_t device __attribute ((unused)),
|
||||
char **label __attribute ((unused)))
|
||||
{
|
||||
*label = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_fs grub_pxefs_fs =
|
||||
{
|
||||
.name = "pxefs",
|
||||
.dir = grub_pxefs_dir,
|
||||
.open = grub_pxefs_open,
|
||||
.read = grub_pxefs_read,
|
||||
.close = grub_pxefs_close,
|
||||
.label = grub_pxefs_label,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
static char *
|
||||
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val __attribute__ ((unused)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_mac_env (grub_uint8_t *mac_addr, grub_size_t mac_len)
|
||||
{
|
||||
char buf[(sizeof ("XX:") - 1) * mac_len + 1];
|
||||
char *ptr = buf;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < mac_len; i++)
|
||||
{
|
||||
grub_snprintf (ptr, sizeof (buf) - (ptr - buf),
|
||||
"%02x:", mac_addr[i] & 0xff);
|
||||
ptr += (sizeof ("XX:") - 1);
|
||||
}
|
||||
if (mac_len)
|
||||
*(ptr - 1) = 0;
|
||||
else
|
||||
buf[0] = 0;
|
||||
|
||||
grub_env_set ("net_pxe_mac", buf);
|
||||
/* XXX: Is it possible to change MAC in PXE? */
|
||||
grub_register_variable_hook ("net_pxe_mac", 0, grub_env_write_readonly);
|
||||
grub_env_export ("net_pxe_mac");
|
||||
}
|
||||
|
||||
static void
|
||||
set_env_limn_ro (const char *varname, char *value, grub_size_t len)
|
||||
{
|
||||
char c;
|
||||
c = value[len];
|
||||
value[len] = 0;
|
||||
grub_env_set (varname, value);
|
||||
value[len] = c;
|
||||
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
|
||||
grub_env_export (varname);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_dhcp_vendor (void *vend, int limit)
|
||||
{
|
||||
grub_uint8_t *ptr, *ptr0;
|
||||
|
||||
ptr = ptr0 = vend;
|
||||
|
||||
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363)
|
||||
return;
|
||||
ptr = ptr + sizeof (grub_uint32_t);
|
||||
while (ptr - ptr0 < limit)
|
||||
{
|
||||
grub_uint8_t tagtype;
|
||||
grub_uint8_t taglength;
|
||||
|
||||
tagtype = *ptr++;
|
||||
|
||||
/* Pad tag. */
|
||||
if (tagtype == 0)
|
||||
continue;
|
||||
|
||||
/* End tag. */
|
||||
if (tagtype == 0xff)
|
||||
return;
|
||||
|
||||
taglength = *ptr++;
|
||||
|
||||
switch (tagtype)
|
||||
{
|
||||
case 12:
|
||||
set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 17:
|
||||
set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
/* If you need any other options please contact GRUB
|
||||
development team. */
|
||||
}
|
||||
|
||||
ptr += taglength;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grub_pxe_detect (void)
|
||||
{
|
||||
struct grub_pxe_bangpxe *pxenv;
|
||||
struct grub_pxenv_get_cached_info ci;
|
||||
struct grub_pxenv_boot_player *bp;
|
||||
|
||||
pxenv = grub_pxe_scan ();
|
||||
if (! pxenv)
|
||||
return;
|
||||
|
||||
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
|
||||
ci.buffer = 0;
|
||||
ci.buffer_size = 0;
|
||||
grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
|
||||
if (ci.status)
|
||||
return;
|
||||
|
||||
bp = LINEAR (ci.buffer);
|
||||
|
||||
grub_pxe_your_ip = bp->your_ip;
|
||||
grub_pxe_default_server_ip = bp->server_ip;
|
||||
grub_pxe_default_gateway_ip = bp->gateway_ip;
|
||||
set_mac_env (bp->mac_addr, bp->hw_len < sizeof (bp->mac_addr) ? bp->hw_len
|
||||
: sizeof (bp->mac_addr));
|
||||
set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file,
|
||||
sizeof (bp->boot_file));
|
||||
set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name,
|
||||
sizeof (bp->server_name));
|
||||
parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor));
|
||||
grub_pxe_pxenv = pxenv;
|
||||
}
|
||||
|
||||
void
|
||||
grub_pxe_unload (void)
|
||||
{
|
||||
if (grub_pxe_pxenv)
|
||||
{
|
||||
grub_fs_unregister (&grub_pxefs_fs);
|
||||
grub_disk_dev_unregister (&grub_pxe_dev);
|
||||
|
||||
grub_pxe_pxenv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_ip_env (char *varname, grub_uint32_t ip)
|
||||
{
|
||||
char buf[sizeof ("XXX.XXX.XXX.XXX")];
|
||||
|
||||
grub_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff),
|
||||
(ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
|
||||
grub_env_set (varname, buf);
|
||||
}
|
||||
|
||||
static char *
|
||||
write_ip_env (grub_uint32_t *ip, const char *val)
|
||||
{
|
||||
char *buf;
|
||||
grub_err_t err;
|
||||
grub_uint32_t newip;
|
||||
|
||||
err = parse_ip (val, &newip, 0);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
/* Normalize the IP. */
|
||||
buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff,
|
||||
(newip >> 16) & 0xff, (newip >> 24) & 0xff);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
*ip = newip;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_env_write_pxe_default_server (struct grub_env_var *var
|
||||
__attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
return write_ip_env (&grub_pxe_default_server_ip, val);
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_env_write_pxe_default_gateway (struct grub_env_var *var
|
||||
__attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
return write_ip_env (&grub_pxe_default_gateway_ip, val);
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
unsigned size;
|
||||
char *buf;
|
||||
|
||||
size = grub_strtoul (val, 0, 0);
|
||||
if (grub_errno)
|
||||
return 0;
|
||||
|
||||
if (size < GRUB_PXE_MIN_BLKSIZE)
|
||||
size = GRUB_PXE_MIN_BLKSIZE;
|
||||
else if (size > GRUB_PXE_MAX_BLKSIZE)
|
||||
size = GRUB_PXE_MAX_BLKSIZE;
|
||||
|
||||
buf = grub_xasprintf ("%d", size);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
grub_pxe_blksize = size;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
GRUB_MOD_INIT(pxe)
|
||||
{
|
||||
grub_pxe_detect ();
|
||||
if (grub_pxe_pxenv)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = grub_xasprintf ("%d", grub_pxe_blksize);
|
||||
if (buf)
|
||||
grub_env_set ("pxe_blksize", buf);
|
||||
grub_free (buf);
|
||||
|
||||
set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
|
||||
set_ip_env ("pxe_default_gateway", grub_pxe_default_gateway_ip);
|
||||
set_ip_env ("net_pxe_ip", grub_pxe_your_ip);
|
||||
grub_register_variable_hook ("pxe_default_server", 0,
|
||||
grub_env_write_pxe_default_server);
|
||||
grub_register_variable_hook ("pxe_default_gateway", 0,
|
||||
grub_env_write_pxe_default_gateway);
|
||||
|
||||
|
||||
/* XXX: Is it possible to change IP in PXE? */
|
||||
grub_register_variable_hook ("net_pxe_ip", 0,
|
||||
grub_env_write_readonly);
|
||||
grub_register_variable_hook ("pxe_blksize", 0,
|
||||
grub_env_write_pxe_blocksize);
|
||||
|
||||
grub_env_export ("pxe_default_server");
|
||||
grub_env_export ("pxe_default_gateway");
|
||||
grub_env_export ("net_pxe_ip");
|
||||
grub_env_export ("pxe_blksize");
|
||||
|
||||
grub_disk_dev_register (&grub_pxe_dev);
|
||||
grub_fs_register (&grub_pxefs_fs);
|
||||
}
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(pxe)
|
||||
{
|
||||
grub_pxe_unload ();
|
||||
}
|
|
@ -149,22 +149,29 @@ struct grub_iso9660_data
|
|||
{
|
||||
struct grub_iso9660_primary_voldesc voldesc;
|
||||
grub_disk_t disk;
|
||||
unsigned int first_sector;
|
||||
int rockridge;
|
||||
int susp_skip;
|
||||
int joliet;
|
||||
struct grub_fshelp_node *node;
|
||||
};
|
||||
|
||||
struct grub_fshelp_node
|
||||
{
|
||||
struct grub_iso9660_data *data;
|
||||
struct grub_iso9660_dir dirent;
|
||||
unsigned int size;
|
||||
unsigned int blk;
|
||||
unsigned int dir_blk;
|
||||
unsigned int dir_off;
|
||||
grub_size_t have_dirents, alloc_dirents;
|
||||
int have_symlink;
|
||||
struct grub_iso9660_dir dirents[8];
|
||||
char symlink[0];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_TYPE_PLAIN = 0,
|
||||
FLAG_TYPE_DIR = 2,
|
||||
FLAG_TYPE = 3,
|
||||
FLAG_MORE_EXTENTS = 0x80
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
|
||||
|
@ -214,35 +221,77 @@ iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf)
|
||||
{
|
||||
grub_size_t i = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
grub_size_t toread;
|
||||
grub_err_t err;
|
||||
while (i < node->have_dirents
|
||||
&& off >= grub_le_to_cpu32 (node->dirents[i].size))
|
||||
{
|
||||
off -= grub_le_to_cpu32 (node->dirents[i].size);
|
||||
i++;
|
||||
}
|
||||
if (i == node->have_dirents)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range");
|
||||
toread = grub_le_to_cpu32 (node->dirents[i].size);
|
||||
if (toread > len)
|
||||
toread = len;
|
||||
err = grub_disk_read (node->data->disk,
|
||||
((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ,
|
||||
off, toread, buf);
|
||||
if (err)
|
||||
return err;
|
||||
len -= toread;
|
||||
off += toread;
|
||||
buf += toread;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Iterate over the susp entries, starting with block SUA_BLOCK on the
|
||||
offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for
|
||||
every entry. */
|
||||
static grub_err_t
|
||||
grub_iso9660_susp_iterate (struct grub_iso9660_data *data,
|
||||
int sua_block, int sua_pos, int sua_size,
|
||||
grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off,
|
||||
grub_ssize_t sua_size,
|
||||
grub_err_t (*hook)
|
||||
(struct grub_iso9660_susp_entry *entry))
|
||||
{
|
||||
char *sua;
|
||||
struct grub_iso9660_susp_entry *entry;
|
||||
grub_disk_addr_t ce_block;
|
||||
int is_ce = 0;
|
||||
|
||||
auto grub_err_t load_sua (void);
|
||||
|
||||
/* Load a part of the System Usage Area. */
|
||||
grub_err_t load_sua (void)
|
||||
{
|
||||
grub_err_t err;
|
||||
sua = grub_malloc (sua_size);
|
||||
if (!sua)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_disk_read (data->disk, sua_block, sua_pos,
|
||||
sua_size, sua))
|
||||
return grub_errno;
|
||||
if (is_ce)
|
||||
err = grub_disk_read (node->data->disk, ce_block, off,
|
||||
sua_size, sua);
|
||||
else
|
||||
err = read_node (node, off, sua_size, sua);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
entry = (struct grub_iso9660_susp_entry *) sua;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sua_size <= 0)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
if (load_sua ())
|
||||
return grub_errno;
|
||||
|
||||
|
@ -259,10 +308,11 @@ grub_iso9660_susp_iterate (struct grub_iso9660_data *data,
|
|||
{
|
||||
struct grub_iso9660_susp_ce *ce;
|
||||
|
||||
is_ce = 1;
|
||||
ce = (struct grub_iso9660_susp_ce *) entry;
|
||||
sua_size = grub_le_to_cpu32 (ce->len);
|
||||
sua_pos = grub_le_to_cpu32 (ce->off);
|
||||
sua_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
|
||||
off = grub_le_to_cpu32 (ce->off);
|
||||
ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ;
|
||||
|
||||
grub_free (sua);
|
||||
if (load_sua ())
|
||||
|
@ -281,34 +331,32 @@ grub_iso9660_susp_iterate (struct grub_iso9660_data *data,
|
|||
}
|
||||
|
||||
static char *
|
||||
grub_iso9660_convert_string (grub_uint16_t *us, int len)
|
||||
grub_iso9660_convert_string (grub_uint8_t *us, int len)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
grub_uint16_t t[len];
|
||||
|
||||
p = grub_malloc (len * 4 + 1);
|
||||
p = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1);
|
||||
if (! p)
|
||||
return p;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
us[i] = grub_be_to_cpu16 (us[i]);
|
||||
t[i] = grub_be_to_cpu16 (grub_get_unaligned16 (us + 2 * i));
|
||||
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) p, us, len) = '\0';
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) p, t, len) = '\0';
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct grub_iso9660_data *
|
||||
grub_iso9660_mount (grub_disk_t disk)
|
||||
static grub_err_t
|
||||
set_rockridge (struct grub_iso9660_data *data)
|
||||
{
|
||||
struct grub_iso9660_data *data = 0;
|
||||
struct grub_iso9660_dir rootdir;
|
||||
int sua_pos;
|
||||
int sua_size;
|
||||
char *sua;
|
||||
struct grub_iso9660_dir rootdir;
|
||||
struct grub_iso9660_susp_entry *entry;
|
||||
struct grub_iso9660_primary_voldesc voldesc;
|
||||
int block;
|
||||
|
||||
auto grub_err_t susp_iterate (struct grub_iso9660_susp_entry *);
|
||||
|
||||
|
@ -324,6 +372,74 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
data->rockridge = 0;
|
||||
|
||||
/* Read the system use area and test it to see if SUSP is
|
||||
supported. */
|
||||
if (grub_disk_read (data->disk,
|
||||
(grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
|
||||
<< GRUB_ISO9660_LOG2_BLKSZ), 0,
|
||||
sizeof (rootdir), (char *) &rootdir))
|
||||
return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
|
||||
|
||||
sua_pos = (sizeof (rootdir) + rootdir.namelen
|
||||
+ (rootdir.namelen % 2) - 1);
|
||||
sua_size = rootdir.len - sua_pos;
|
||||
|
||||
if (!sua_size)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
sua = grub_malloc (sua_size);
|
||||
if (! sua)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_disk_read (data->disk,
|
||||
(grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
|
||||
<< GRUB_ISO9660_LOG2_BLKSZ), sua_pos,
|
||||
sua_size, sua))
|
||||
{
|
||||
grub_free (sua);
|
||||
return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
|
||||
}
|
||||
|
||||
entry = (struct grub_iso9660_susp_entry *) sua;
|
||||
|
||||
/* Test if the SUSP protocol is used on this filesystem. */
|
||||
if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
|
||||
{
|
||||
struct grub_fshelp_node rootnode;
|
||||
|
||||
rootnode.data = data;
|
||||
rootnode.alloc_dirents = ARRAY_SIZE (rootnode.dirents);
|
||||
rootnode.have_dirents = 1;
|
||||
rootnode.have_symlink = 0;
|
||||
rootnode.dirents[0] = data->voldesc.rootdir;
|
||||
|
||||
/* The 2nd data byte stored how many bytes are skipped every time
|
||||
to get to the SUA (System Usage Area). */
|
||||
data->susp_skip = entry->data[2];
|
||||
entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
|
||||
|
||||
/* Iterate over the entries in the SUA area to detect
|
||||
extensions. */
|
||||
if (grub_iso9660_susp_iterate (&rootnode,
|
||||
sua_pos, sua_size, susp_iterate))
|
||||
{
|
||||
grub_free (sua);
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
grub_free (sua);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_iso9660_data *
|
||||
grub_iso9660_mount (grub_disk_t disk)
|
||||
{
|
||||
struct grub_iso9660_data *data = 0;
|
||||
struct grub_iso9660_primary_voldesc voldesc;
|
||||
int block;
|
||||
|
||||
data = grub_zalloc (sizeof (struct grub_iso9660_data));
|
||||
if (! data)
|
||||
return 0;
|
||||
|
@ -351,9 +467,11 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
}
|
||||
|
||||
if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY)
|
||||
copy_voldesc = 1;
|
||||
else if ((voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP) &&
|
||||
(voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f) &&
|
||||
copy_voldesc = 1;
|
||||
else if (!data->rockridge
|
||||
&& (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP)
|
||||
&& (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f)
|
||||
&&
|
||||
((voldesc.escape[2] == 0x40) || /* UCS-2 Level 1. */
|
||||
(voldesc.escape[2] == 0x43) || /* UCS-2 Level 2. */
|
||||
(voldesc.escape[2] == 0x45))) /* UCS-2 Level 3. */
|
||||
|
@ -363,57 +481,16 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
}
|
||||
|
||||
if (copy_voldesc)
|
||||
grub_memcpy((char *) &data->voldesc, (char *) &voldesc,
|
||||
sizeof (struct grub_iso9660_primary_voldesc));
|
||||
{
|
||||
grub_memcpy((char *) &data->voldesc, (char *) &voldesc,
|
||||
sizeof (struct grub_iso9660_primary_voldesc));
|
||||
if (set_rockridge (data))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
block++;
|
||||
} while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END);
|
||||
|
||||
/* Read the system use area and test it to see if SUSP is
|
||||
supported. */
|
||||
if (grub_disk_read (disk, (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
|
||||
<< GRUB_ISO9660_LOG2_BLKSZ), 0,
|
||||
sizeof (rootdir), (char *) &rootdir))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sua_pos = (sizeof (rootdir) + rootdir.namelen
|
||||
+ (rootdir.namelen % 2) - 1);
|
||||
sua_size = rootdir.len - sua_pos;
|
||||
|
||||
sua = grub_malloc (sua_size);
|
||||
if (! sua)
|
||||
goto fail;
|
||||
|
||||
if (grub_disk_read (disk, (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
|
||||
<< GRUB_ISO9660_LOG2_BLKSZ), sua_pos,
|
||||
sua_size, sua))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
entry = (struct grub_iso9660_susp_entry *) sua;
|
||||
|
||||
/* Test if the SUSP protocol is used on this filesystem. */
|
||||
if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0)
|
||||
{
|
||||
/* The 2nd data byte stored how many bytes are skipped every time
|
||||
to get to the SUA (System Usage Area). */
|
||||
data->susp_skip = entry->data[2];
|
||||
entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len);
|
||||
|
||||
/* Iterate over the entries in the SUA area to detect
|
||||
extensions. */
|
||||
if (grub_iso9660_susp_iterate (data,
|
||||
(grub_le_to_cpu32 (data->voldesc.rootdir.first_sector)
|
||||
<< GRUB_ISO9660_LOG2_BLKSZ),
|
||||
sua_pos, sua_size, susp_iterate))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
|
@ -425,42 +502,125 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
static char *
|
||||
grub_iso9660_read_symlink (grub_fshelp_node_t node)
|
||||
{
|
||||
int sua_off;
|
||||
int sua_size;
|
||||
char *symlink = 0;
|
||||
int addslash = 0;
|
||||
return node->have_symlink
|
||||
? grub_strdup (node->symlink
|
||||
+ (node->have_dirents) * sizeof (node->dirents[0])
|
||||
- sizeof (node->dirents)) : grub_strdup ("");
|
||||
}
|
||||
|
||||
auto void add_part (const char *part, int len);
|
||||
auto grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *);
|
||||
static grub_off_t
|
||||
get_node_size (grub_fshelp_node_t node)
|
||||
{
|
||||
grub_off_t ret = 0;
|
||||
grub_size_t i;
|
||||
|
||||
for (i = 0; i < node->have_dirents; i++)
|
||||
ret += grub_le_to_cpu32 (node->dirents[i].size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
{
|
||||
struct grub_iso9660_dir dirent;
|
||||
grub_off_t offset = 0;
|
||||
char *filename = 0;
|
||||
int filename_alloc = 0;
|
||||
enum grub_fshelp_filetype type;
|
||||
grub_off_t len;
|
||||
char *symlink = 0;
|
||||
|
||||
/* Extend the symlink. */
|
||||
void add_part (const char *part, int len)
|
||||
{
|
||||
int size = grub_strlen (symlink);
|
||||
auto inline void __attribute__ ((always_inline)) add_part (const char *part,
|
||||
int len2);
|
||||
|
||||
symlink = grub_realloc (symlink, size + len + 1);
|
||||
auto inline void __attribute__ ((always_inline)) add_part (const char *part,
|
||||
int len2)
|
||||
{
|
||||
int size = symlink ? grub_strlen (symlink) : 0;
|
||||
|
||||
symlink = grub_realloc (symlink, size + len2 + 1);
|
||||
if (! symlink)
|
||||
return;
|
||||
|
||||
grub_strncat (symlink, part, len);
|
||||
symlink[size] = 0;
|
||||
grub_strncat (symlink, part, len2);
|
||||
}
|
||||
|
||||
/* Read in a symlink. */
|
||||
grub_err_t susp_iterate_sl (struct grub_iso9660_susp_entry *entry)
|
||||
auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *);
|
||||
|
||||
grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *entry)
|
||||
{
|
||||
if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
|
||||
/* The filename in the rock ridge entry. */
|
||||
if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0)
|
||||
{
|
||||
/* The flags are stored at the data position 0, here the
|
||||
filename type is stored. */
|
||||
if (entry->data[0] & GRUB_ISO9660_RR_DOT)
|
||||
filename = ".";
|
||||
else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT)
|
||||
filename = "..";
|
||||
else if (entry->len >= 5)
|
||||
{
|
||||
grub_size_t size = 1, csize = 1;
|
||||
char *old;
|
||||
csize = size = entry->len - 5;
|
||||
old = filename;
|
||||
if (filename_alloc)
|
||||
{
|
||||
size += grub_strlen (filename);
|
||||
filename = grub_realloc (filename, size + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename_alloc = 1;
|
||||
filename = grub_zalloc (size + 1);
|
||||
filename[0] = 0;
|
||||
}
|
||||
if (!filename)
|
||||
{
|
||||
filename = old;
|
||||
return grub_errno;
|
||||
}
|
||||
filename_alloc = 1;
|
||||
grub_strncat (filename, (char *) &entry->data[1], csize);
|
||||
filename[size] = '\0';
|
||||
}
|
||||
}
|
||||
/* The mode information (st_mode). */
|
||||
else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0)
|
||||
{
|
||||
/* At position 0 of the PX record the st_mode information is
|
||||
stored (little-endian). */
|
||||
grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8))
|
||||
& GRUB_ISO9660_FSTYPE_MASK);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GRUB_ISO9660_FSTYPE_DIR:
|
||||
type = GRUB_FSHELP_DIR;
|
||||
break;
|
||||
case GRUB_ISO9660_FSTYPE_REG:
|
||||
type = GRUB_FSHELP_REG;
|
||||
break;
|
||||
case GRUB_ISO9660_FSTYPE_SYMLINK:
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
break;
|
||||
default:
|
||||
type = GRUB_FSHELP_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0)
|
||||
{
|
||||
unsigned int pos = 1;
|
||||
|
||||
/* The symlink is not stored as a POSIX symlink, translate it. */
|
||||
while (pos < grub_le_to_cpu32 (entry->len))
|
||||
while (pos + sizeof (*entry) < grub_le_to_cpu32 (entry->len))
|
||||
{
|
||||
if (addslash)
|
||||
{
|
||||
add_part ("/", 1);
|
||||
addslash = 0;
|
||||
}
|
||||
|
||||
/* The current position is the `Component Flag'. */
|
||||
switch (entry->data[pos] & 30)
|
||||
{
|
||||
|
@ -469,10 +629,10 @@ grub_iso9660_read_symlink (grub_fshelp_node_t node)
|
|||
/* The data on pos + 2 is the actual data, pos + 1
|
||||
is the length. Both are part of the `Component
|
||||
Record'. */
|
||||
if (symlink && (entry->data[pos] & 1))
|
||||
add_part ("/", 1);
|
||||
add_part ((char *) &entry->data[pos + 2],
|
||||
entry->data[pos + 1]);
|
||||
if ((entry->data[pos] & 1))
|
||||
addslash = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -502,109 +662,13 @@ grub_iso9660_read_symlink (grub_fshelp_node_t node)
|
|||
return 0;
|
||||
}
|
||||
|
||||
sua_off = (sizeof (node->dirent) + node->dirent.namelen + 1
|
||||
- (node->dirent.namelen % 2)
|
||||
+ node->data->susp_skip);
|
||||
sua_size = node->dirent.len - sua_off;
|
||||
len = get_node_size (dir);
|
||||
|
||||
symlink = grub_malloc (1);
|
||||
if (!symlink)
|
||||
return 0;
|
||||
|
||||
*symlink = '\0';
|
||||
|
||||
if (grub_iso9660_susp_iterate (node->data, node->dir_blk,
|
||||
node->dir_off + sua_off,
|
||||
sua_size, susp_iterate_sl))
|
||||
for (; offset < len; offset += dirent.len)
|
||||
{
|
||||
grub_free (symlink);
|
||||
return 0;
|
||||
}
|
||||
symlink = 0;
|
||||
|
||||
return symlink;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
||||
int NESTED_FUNC_ATTR
|
||||
(*hook) (const char *filename,
|
||||
enum grub_fshelp_filetype filetype,
|
||||
grub_fshelp_node_t node))
|
||||
{
|
||||
struct grub_iso9660_dir dirent;
|
||||
unsigned int offset = 0;
|
||||
char *filename;
|
||||
int filename_alloc = 0;
|
||||
enum grub_fshelp_filetype type;
|
||||
|
||||
auto grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *);
|
||||
|
||||
grub_err_t susp_iterate_dir (struct grub_iso9660_susp_entry *entry)
|
||||
{
|
||||
/* The filename in the rock ridge entry. */
|
||||
if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0)
|
||||
{
|
||||
/* The flags are stored at the data position 0, here the
|
||||
filename type is stored. */
|
||||
if (entry->data[0] & GRUB_ISO9660_RR_DOT)
|
||||
filename = ".";
|
||||
else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT)
|
||||
filename = "..";
|
||||
else
|
||||
{
|
||||
int size = 1;
|
||||
if (filename)
|
||||
{
|
||||
size += grub_strlen (filename);
|
||||
grub_realloc (filename,
|
||||
grub_strlen (filename)
|
||||
+ entry->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = entry->len - 5;
|
||||
filename = grub_zalloc (size + 1);
|
||||
}
|
||||
filename_alloc = 1;
|
||||
grub_strncpy (filename, (char *) &entry->data[1], size);
|
||||
filename[size] = '\0';
|
||||
}
|
||||
}
|
||||
/* The mode information (st_mode). */
|
||||
else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0)
|
||||
{
|
||||
/* At position 0 of the PX record the st_mode information is
|
||||
stored (little-endian). */
|
||||
grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8))
|
||||
& GRUB_ISO9660_FSTYPE_MASK);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case GRUB_ISO9660_FSTYPE_DIR:
|
||||
type = GRUB_FSHELP_DIR;
|
||||
break;
|
||||
case GRUB_ISO9660_FSTYPE_REG:
|
||||
type = GRUB_FSHELP_REG;
|
||||
break;
|
||||
case GRUB_ISO9660_FSTYPE_SYMLINK:
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
break;
|
||||
default:
|
||||
type = GRUB_FSHELP_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (offset < dir->size)
|
||||
{
|
||||
if (grub_disk_read (dir->data->disk,
|
||||
(dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ offset / GRUB_DISK_SECTOR_SIZE,
|
||||
offset % GRUB_DISK_SECTOR_SIZE,
|
||||
sizeof (dirent), (char *) &dirent))
|
||||
if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
|
||||
return 0;
|
||||
|
||||
/* The end of the block, skip to the next one. */
|
||||
|
@ -629,39 +693,30 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
type = GRUB_FSHELP_UNKNOWN;
|
||||
|
||||
if (dir->data->rockridge
|
||||
&& grub_iso9660_susp_iterate (dir->data,
|
||||
(dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ (sua_off
|
||||
/ GRUB_DISK_SECTOR_SIZE),
|
||||
sua_off % GRUB_DISK_SECTOR_SIZE,
|
||||
sua_size, susp_iterate_dir))
|
||||
&& grub_iso9660_susp_iterate (dir, sua_off, sua_size,
|
||||
susp_iterate_dir))
|
||||
return 0;
|
||||
|
||||
/* Read the name. */
|
||||
if (grub_disk_read (dir->data->disk,
|
||||
(dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ nameoffset / GRUB_DISK_SECTOR_SIZE,
|
||||
nameoffset % GRUB_DISK_SECTOR_SIZE,
|
||||
dirent.namelen, (char *) name))
|
||||
if (read_node (dir, nameoffset, dirent.namelen, (char *) name))
|
||||
return 0;
|
||||
|
||||
node = grub_malloc (sizeof (struct grub_fshelp_node));
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
node->alloc_dirents = ARRAY_SIZE (node->dirents);
|
||||
node->have_dirents = 1;
|
||||
|
||||
/* Setup a new node. */
|
||||
node->data = dir->data;
|
||||
node->size = grub_le_to_cpu32 (dirent.size);
|
||||
node->blk = grub_le_to_cpu32 (dirent.first_sector);
|
||||
node->dir_blk = ((dir->blk << GRUB_ISO9660_LOG2_BLKSZ)
|
||||
+ offset / GRUB_DISK_SECTOR_SIZE);
|
||||
node->dir_off = offset % GRUB_DISK_SECTOR_SIZE;
|
||||
node->have_symlink = 0;
|
||||
|
||||
/* If the filetype was not stored using rockridge, use
|
||||
whatever is stored in the iso9660 filesystem. */
|
||||
if (type == GRUB_FSHELP_UNKNOWN)
|
||||
{
|
||||
if ((dirent.flags & 3) == 2)
|
||||
if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
|
||||
type = GRUB_FSHELP_DIR;
|
||||
else
|
||||
type = GRUB_FSHELP_REG;
|
||||
|
@ -676,10 +731,12 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (filename)
|
||||
*filename = '\0';
|
||||
|
||||
if (dirent.namelen == 1 && name[0] == 0)
|
||||
filename = ".";
|
||||
else if (dirent.namelen == 1 && name[0] == 1)
|
||||
filename = "..";
|
||||
/* . and .. */
|
||||
if (dirent.namelen == 1 && (name[0] == 0 || name[0] == 1))
|
||||
{
|
||||
grub_free (node);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
filename = name;
|
||||
}
|
||||
|
@ -690,7 +747,7 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
|
||||
oldname = filename;
|
||||
filename = grub_iso9660_convert_string
|
||||
((grub_uint16_t *) oldname, dirent.namelen >> 1);
|
||||
((grub_uint8_t *) oldname, dirent.namelen >> 1);
|
||||
|
||||
semicolon = grub_strrchr (filename, ';');
|
||||
if (semicolon)
|
||||
|
@ -702,7 +759,64 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
filename_alloc = 1;
|
||||
}
|
||||
|
||||
node->dirent = dirent;
|
||||
node->dirents[0] = dirent;
|
||||
while (dirent.flags & FLAG_MORE_EXTENTS)
|
||||
{
|
||||
offset += dirent.len;
|
||||
if (read_node (dir, offset, sizeof (dirent), (char *) &dirent))
|
||||
{
|
||||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
grub_free (node);
|
||||
return 0;
|
||||
}
|
||||
if (node->have_dirents >= node->alloc_dirents)
|
||||
{
|
||||
struct grub_fshelp_node *new_node;
|
||||
node->alloc_dirents *= 2;
|
||||
new_node = grub_realloc (node,
|
||||
sizeof (struct grub_fshelp_node)
|
||||
+ ((node->alloc_dirents
|
||||
- ARRAY_SIZE (node->dirents))
|
||||
* sizeof (node->dirents[0])));
|
||||
if (!new_node)
|
||||
{
|
||||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
grub_free (node);
|
||||
return 0;
|
||||
}
|
||||
node = new_node;
|
||||
}
|
||||
node->dirents[node->have_dirents++] = dirent;
|
||||
}
|
||||
if (symlink)
|
||||
{
|
||||
if ((node->alloc_dirents - node->have_dirents)
|
||||
* sizeof (node->dirents[0]) < grub_strlen (symlink) + 1)
|
||||
{
|
||||
struct grub_fshelp_node *new_node;
|
||||
new_node = grub_realloc (node,
|
||||
sizeof (struct grub_fshelp_node)
|
||||
+ ((node->alloc_dirents
|
||||
- ARRAY_SIZE (node->dirents))
|
||||
* sizeof (node->dirents[0]))
|
||||
+ grub_strlen (symlink) + 1);
|
||||
if (!new_node)
|
||||
{
|
||||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
grub_free (node);
|
||||
return 0;
|
||||
}
|
||||
node = new_node;
|
||||
}
|
||||
node->have_symlink = 1;
|
||||
grub_strcpy (node->symlink
|
||||
+ node->have_dirents * sizeof (node->dirents[0])
|
||||
- sizeof (node->dirents), symlink);
|
||||
grub_free (symlink);
|
||||
}
|
||||
if (hook (filename, type, node))
|
||||
{
|
||||
if (filename_alloc)
|
||||
|
@ -712,8 +826,6 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (filename_alloc)
|
||||
grub_free (filename);
|
||||
}
|
||||
|
||||
offset += dirent.len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -741,7 +853,7 @@ grub_iso9660_dir (grub_device_t device, const char *path,
|
|||
struct grub_dirhook_info info;
|
||||
grub_memset (&info, 0, sizeof (info));
|
||||
info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
|
||||
info.mtimeset = !!iso9660_to_unixtime2 (&node->dirent.mtime, &info.mtime);
|
||||
info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime);
|
||||
|
||||
grub_free (node);
|
||||
return hook (filename, &info);
|
||||
|
@ -754,8 +866,10 @@ grub_iso9660_dir (grub_device_t device, const char *path,
|
|||
goto fail;
|
||||
|
||||
rootnode.data = data;
|
||||
rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector);
|
||||
rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size);
|
||||
rootnode.alloc_dirents = 0;
|
||||
rootnode.have_dirents = 1;
|
||||
rootnode.have_symlink = 0;
|
||||
rootnode.dirents[0] = data->voldesc.rootdir;
|
||||
|
||||
/* Use the fshelp function to traverse the path. */
|
||||
if (grub_fshelp_find_file (path, &rootnode,
|
||||
|
@ -795,8 +909,10 @@ grub_iso9660_open (struct grub_file *file, const char *name)
|
|||
goto fail;
|
||||
|
||||
rootnode.data = data;
|
||||
rootnode.blk = grub_le_to_cpu32 (data->voldesc.rootdir.first_sector);
|
||||
rootnode.size = grub_le_to_cpu32 (data->voldesc.rootdir.size);
|
||||
rootnode.alloc_dirents = 0;
|
||||
rootnode.have_dirents = 1;
|
||||
rootnode.have_symlink = 0;
|
||||
rootnode.dirents[0] = data->voldesc.rootdir;
|
||||
|
||||
/* Use the fshelp function to traverse the path. */
|
||||
if (grub_fshelp_find_file (name, &rootnode,
|
||||
|
@ -806,10 +922,9 @@ grub_iso9660_open (struct grub_file *file, const char *name)
|
|||
GRUB_FSHELP_REG))
|
||||
goto fail;
|
||||
|
||||
data->first_sector = foundnode->blk;
|
||||
|
||||
data->node = foundnode;
|
||||
file->data = data;
|
||||
file->size = foundnode->size;
|
||||
file->size = get_node_size (foundnode);
|
||||
file->offset = 0;
|
||||
|
||||
return 0;
|
||||
|
@ -831,10 +946,7 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
|
||||
/* XXX: The file is stored in as a single extent. */
|
||||
data->disk->read_hook = file->read_hook;
|
||||
grub_disk_read (data->disk,
|
||||
data->first_sector << GRUB_ISO9660_LOG2_BLKSZ,
|
||||
file->offset,
|
||||
len, buf);
|
||||
read_node (data->node, file->offset, len, buf);
|
||||
data->disk->read_hook = NULL;
|
||||
|
||||
if (grub_errno)
|
||||
|
@ -847,7 +959,10 @@ grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
static grub_err_t
|
||||
grub_iso9660_close (grub_file_t file)
|
||||
{
|
||||
grub_free (file->data);
|
||||
struct grub_iso9660_data *data =
|
||||
(struct grub_iso9660_data *) file->data;
|
||||
grub_free (data->node);
|
||||
grub_free (data);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
|
@ -864,8 +979,7 @@ grub_iso9660_label (grub_device_t device, char **label)
|
|||
if (data)
|
||||
{
|
||||
if (data->joliet)
|
||||
*label = grub_iso9660_convert_string
|
||||
((grub_uint16_t *) &data->voldesc.volname, 16);
|
||||
*label = grub_iso9660_convert_string (data->voldesc.volname, 16);
|
||||
else
|
||||
*label = grub_strndup ((char *) data->voldesc.volname, 32);
|
||||
if (*label)
|
||||
|
|
|
@ -52,9 +52,9 @@ struct grub_jfs_sblock
|
|||
grub_uint32_t blksz;
|
||||
grub_uint16_t log2_blksz;
|
||||
|
||||
grub_uint8_t unused[71];
|
||||
grub_uint8_t unused[79];
|
||||
grub_uint8_t volname[11];
|
||||
grub_uint8_t unused2[32];
|
||||
grub_uint8_t unused2[24];
|
||||
grub_uint8_t uuid[16];
|
||||
};
|
||||
|
||||
|
@ -205,7 +205,7 @@ struct grub_jfs_inode
|
|||
struct
|
||||
{
|
||||
grub_uint8_t unused[32];
|
||||
grub_uint8_t path[128];
|
||||
grub_uint8_t path[256];
|
||||
} symlink;
|
||||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
@ -238,7 +238,10 @@ struct grub_jfs_diropen
|
|||
struct grub_jfs_leaf_next_dirent *next_leaf;
|
||||
|
||||
/* The filename and inode of the last read dirent. */
|
||||
char name[255];
|
||||
/* On-disk name is at most 255 UTF-16 codepoints.
|
||||
Every UTF-16 codepoint is at most 4 UTF-8 bytes.
|
||||
*/
|
||||
char name[256 * GRUB_MAX_UTF8_PER_UTF16 + 1];
|
||||
grub_uint32_t ino;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
@ -253,11 +256,11 @@ static grub_int64_t
|
|||
grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
||||
grub_uint64_t blk)
|
||||
{
|
||||
auto int getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents);
|
||||
auto grub_int64_t getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents);
|
||||
|
||||
int getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents)
|
||||
grub_int64_t getblk (struct grub_jfs_treehead *treehead,
|
||||
struct grub_jfs_tree_extent *extents)
|
||||
{
|
||||
int found = -1;
|
||||
int i;
|
||||
|
@ -269,7 +272,7 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
|||
/* Read the leafnode. */
|
||||
if (grub_le_to_cpu32 (extents[i].offset2) <= blk
|
||||
&& ((grub_le_to_cpu16 (extents[i].extent.length))
|
||||
+ (extents[i].extent.length2 << 8)
|
||||
+ (extents[i].extent.length2 << 16)
|
||||
+ grub_le_to_cpu32 (extents[i].offset2)) > blk)
|
||||
return (blk - grub_le_to_cpu32 (extents[i].offset2)
|
||||
+ grub_le_to_cpu32 (extents[i].extent.blk2));
|
||||
|
@ -288,7 +291,7 @@ grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode,
|
|||
} tree;
|
||||
|
||||
if (grub_disk_read (data->disk,
|
||||
grub_le_to_cpu32 (extents[found].extent.blk2)
|
||||
((grub_disk_addr_t) grub_le_to_cpu32 (extents[found].extent.blk2))
|
||||
<< (grub_le_to_cpu16 (data->sblock.log2_blksz)
|
||||
- GRUB_DISK_SECTOR_BITS), 0,
|
||||
sizeof (tree), (char *) &tree))
|
||||
|
@ -479,7 +482,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro)
|
|||
struct grub_jfs_leaf_next_dirent *next_leaf;
|
||||
int len;
|
||||
int nextent;
|
||||
grub_uint16_t filename[255];
|
||||
grub_uint16_t filename[256];
|
||||
|
||||
auto void addstr (grub_uint16_t *uname, int ulen);
|
||||
|
||||
|
@ -487,7 +490,7 @@ grub_jfs_getent (struct grub_jfs_diropen *diro)
|
|||
void addstr (grub_uint16_t *name, int ulen)
|
||||
{
|
||||
while (ulen--)
|
||||
filename[strpos++] = *(name++);
|
||||
filename[strpos++] = grub_le_to_cpu16 (*(name++));
|
||||
}
|
||||
|
||||
/* The last node, read in more. */
|
||||
|
@ -558,10 +561,10 @@ static grub_ssize_t
|
|||
grub_jfs_read_file (struct grub_jfs_data *data,
|
||||
void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length),
|
||||
grub_uint64_t pos, grub_size_t len, char *buf)
|
||||
grub_off_t pos, grub_size_t len, char *buf)
|
||||
{
|
||||
grub_uint64_t i;
|
||||
grub_uint64_t blockcnt;
|
||||
grub_off_t i;
|
||||
grub_off_t blockcnt;
|
||||
|
||||
blockcnt = (len + pos + grub_le_to_cpu32 (data->sblock.blksz) - 1)
|
||||
>> grub_le_to_cpu16 (data->sblock.log2_blksz);
|
||||
|
@ -614,7 +617,8 @@ grub_jfs_read_file (struct grub_jfs_data *data,
|
|||
/* Find the file with the pathname PATH on the filesystem described by
|
||||
DATA. */
|
||||
static grub_err_t
|
||||
grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
||||
grub_jfs_find_file (struct grub_jfs_data *data, const char *path,
|
||||
grub_uint32_t start_ino)
|
||||
{
|
||||
char fpath[grub_strlen (path)];
|
||||
char *name = fpath;
|
||||
|
@ -623,7 +627,7 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
|||
|
||||
grub_strncpy (fpath, path, grub_strlen (path) + 1);
|
||||
|
||||
if (grub_jfs_read_inode (data, GRUB_JFS_AGGR_INODE, &data->currinode))
|
||||
if (grub_jfs_read_inode (data, start_ino, &data->currinode))
|
||||
return grub_errno;
|
||||
|
||||
/* Skip the first slashes. */
|
||||
|
@ -699,7 +703,7 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
|||
}
|
||||
|
||||
grub_jfs_closedir (diro);
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
@ -707,14 +711,14 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path)
|
|||
static grub_err_t
|
||||
grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino)
|
||||
{
|
||||
grub_uint64_t size = grub_le_to_cpu64 (data->currinode.size);
|
||||
grub_size_t size = grub_le_to_cpu64 (data->currinode.size);
|
||||
char symlink[size + 1];
|
||||
|
||||
if (++data->linknest > GRUB_JFS_MAX_SYMLNK_CNT)
|
||||
return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
|
||||
|
||||
if (size <= 128)
|
||||
grub_strncpy (symlink, (char *) (data->currinode.symlink.path), 128);
|
||||
if (size <= sizeof (data->currinode.symlink.path))
|
||||
grub_strncpy (symlink, (char *) (data->currinode.symlink.path), size);
|
||||
else if (grub_jfs_read_file (data, 0, 0, size, symlink) < 0)
|
||||
return grub_errno;
|
||||
|
||||
|
@ -724,11 +728,7 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino)
|
|||
if (symlink[0] == '/')
|
||||
ino = 2;
|
||||
|
||||
/* Now load in the old inode. */
|
||||
if (grub_jfs_read_inode (data, ino, &data->currinode))
|
||||
return grub_errno;
|
||||
|
||||
grub_jfs_find_file (data, symlink);
|
||||
grub_jfs_find_file (data, symlink, ino);
|
||||
if (grub_errno)
|
||||
grub_error (grub_errno, "cannot follow symlink `%s'", symlink);
|
||||
|
||||
|
@ -750,7 +750,7 @@ grub_jfs_dir (grub_device_t device, const char *path,
|
|||
if (!data)
|
||||
goto fail;
|
||||
|
||||
if (grub_jfs_find_file (data, path))
|
||||
if (grub_jfs_find_file (data, path, GRUB_JFS_AGGR_INODE))
|
||||
goto fail;
|
||||
|
||||
diro = grub_jfs_opendir (data, &data->currinode);
|
||||
|
@ -801,7 +801,7 @@ grub_jfs_open (struct grub_file *file, const char *name)
|
|||
if (!data)
|
||||
goto fail;
|
||||
|
||||
grub_jfs_find_file (data, name);
|
||||
grub_jfs_find_file (data, name, GRUB_JFS_AGGR_INODE);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
|
@ -891,6 +891,8 @@ grub_jfs_label (grub_device_t device, char **label)
|
|||
else
|
||||
*label = 0;
|
||||
|
||||
grub_free (data);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ typedef grub_uint16_t grub_minix_ino_t;
|
|||
#define grub_minix_le_to_cpu_ino grub_le_to_cpu16
|
||||
#endif
|
||||
|
||||
#define GRUB_MINIX_INODE_SIZE(data) (grub_minix_le_to_cpu_n (data->inode.size))
|
||||
#define GRUB_MINIX_INODE_SIZE(data) (grub_le_to_cpu32 (data->inode.size))
|
||||
#define GRUB_MINIX_INODE_MODE(data) (grub_le_to_cpu16 (data->inode.mode))
|
||||
#define GRUB_MINIX_INODE_DIR_ZONES(data,blk) (grub_minix_le_to_cpu_n \
|
||||
(data->inode.dir_zones[blk]))
|
||||
|
@ -76,11 +76,11 @@ typedef grub_uint16_t grub_minix_ino_t;
|
|||
#define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \
|
||||
+ grub_le_to_cpu16 (data->sblock.log2_zone_size))
|
||||
#endif
|
||||
#define GRUB_MINIX_ZONESZ (data->block_size \
|
||||
<< grub_le_to_cpu16 (data->sblock.log2_zone_size))
|
||||
#define GRUB_MINIX_ZONESZ (1 << (data->log_block_size \
|
||||
+ grub_le_to_cpu16 (data->sblock.log2_zone_size)))
|
||||
|
||||
#ifdef MODE_MINIX3
|
||||
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) * (data->block_size / GRUB_DISK_SECTOR_SIZE))
|
||||
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << (data->log_block_size - GRUB_DISK_SECTOR_BITS))
|
||||
#else
|
||||
#define GRUB_MINIX_ZONE2SECT(zone) ((zone) << GRUB_MINIX_LOG2_ZONESZ)
|
||||
#endif
|
||||
|
@ -132,16 +132,15 @@ struct grub_minix_inode
|
|||
grub_uint32_t dir_zones[7];
|
||||
grub_uint32_t indir_zone;
|
||||
grub_uint32_t double_indir_zone;
|
||||
grub_uint32_t unused;
|
||||
|
||||
grub_uint32_t triple_indir_zone;
|
||||
};
|
||||
#else
|
||||
struct grub_minix_inode
|
||||
{
|
||||
grub_uint16_t mode;
|
||||
grub_uint16_t uid;
|
||||
grub_uint16_t size;
|
||||
grub_uint32_t ctime;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t mtime;
|
||||
grub_uint8_t gid;
|
||||
grub_uint8_t nlinks;
|
||||
grub_uint16_t dir_zones[7];
|
||||
|
@ -160,7 +159,7 @@ struct grub_minix_data
|
|||
int linknest;
|
||||
grub_disk_t disk;
|
||||
int filename_size;
|
||||
grub_size_t block_size;
|
||||
grub_size_t log_block_size;
|
||||
};
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
@ -168,15 +167,19 @@ static grub_dl_t my_mod;
|
|||
static grub_err_t grub_minix_find_file (struct grub_minix_data *data,
|
||||
const char *path);
|
||||
|
||||
static int
|
||||
static grub_minix_uintn_t
|
||||
grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
|
||||
{
|
||||
int indir;
|
||||
grub_minix_uintn_t indir;
|
||||
const grub_uint32_t block_per_zone = (GRUB_MINIX_ZONESZ
|
||||
/ GRUB_MINIX_INODE_BLKSZ (data));
|
||||
|
||||
auto int grub_get_indir (int, int);
|
||||
auto grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t,
|
||||
grub_minix_uintn_t);
|
||||
|
||||
/* Read the block pointer in ZONE, on the offset NUM. */
|
||||
int grub_get_indir (int zone, int num)
|
||||
grub_minix_uintn_t grub_get_indir (grub_minix_uintn_t zone,
|
||||
grub_minix_uintn_t num)
|
||||
{
|
||||
grub_minix_uintn_t indirn;
|
||||
grub_disk_read (data->disk,
|
||||
|
@ -192,25 +195,38 @@ grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
|
|||
|
||||
/* Indirect block. */
|
||||
blk -= GRUB_MINIX_INODE_DIR_BLOCKS;
|
||||
if (blk < GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data))
|
||||
if (blk < block_per_zone)
|
||||
{
|
||||
indir = grub_get_indir (GRUB_MINIX_INODE_INDIR_ZONE (data), blk);
|
||||
return indir;
|
||||
}
|
||||
|
||||
/* Double indirect block. */
|
||||
blk -= GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data);
|
||||
if (blk < (GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data))
|
||||
* (GRUB_MINIX_ZONESZ / GRUB_MINIX_INODE_BLKSZ (data)))
|
||||
blk -= block_per_zone;
|
||||
if (blk < block_per_zone * block_per_zone)
|
||||
{
|
||||
indir = grub_get_indir (GRUB_MINIX_INODE_DINDIR_ZONE (data),
|
||||
blk / GRUB_MINIX_ZONESZ);
|
||||
blk / block_per_zone);
|
||||
|
||||
indir = grub_get_indir (indir, blk % GRUB_MINIX_ZONESZ);
|
||||
indir = grub_get_indir (indir, blk % block_per_zone);
|
||||
|
||||
return indir;
|
||||
}
|
||||
|
||||
#if defined (MODE_MINIX3) || defined (MODE_MINIX2)
|
||||
blk -= block_per_zone * block_per_zone;
|
||||
if (blk < ((grub_uint64_t) block_per_zone * (grub_uint64_t) block_per_zone
|
||||
* (grub_uint64_t) block_per_zone))
|
||||
{
|
||||
indir = grub_get_indir (grub_minix_le_to_cpu_n (data->inode.triple_indir_zone),
|
||||
(blk / block_per_zone) / block_per_zone);
|
||||
indir = grub_get_indir (indir, (blk / block_per_zone) % block_per_zone);
|
||||
indir = grub_get_indir (indir, blk % block_per_zone);
|
||||
|
||||
return indir;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This should never happen. */
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, "file bigger than maximum size");
|
||||
|
||||
|
@ -235,14 +251,15 @@ grub_minix_read_file (struct grub_minix_data *data,
|
|||
if (len + pos > GRUB_MINIX_INODE_SIZE (data))
|
||||
len = GRUB_MINIX_INODE_SIZE (data) - pos;
|
||||
|
||||
blockcnt = grub_divmod64 ((len + pos + data->block_size - 1),
|
||||
data->block_size, 0);
|
||||
posblock = grub_divmod64 (pos, data->block_size, &blockoff);
|
||||
blockcnt = ((len + pos + (1 << data->log_block_size) - 1)
|
||||
>> data->log_block_size);
|
||||
posblock = pos >> data->log_block_size;
|
||||
blockoff = pos & ((1 << data->log_block_size) - 1);
|
||||
|
||||
for (i = posblock; i < blockcnt; i++)
|
||||
{
|
||||
grub_disk_addr_t blknr;
|
||||
grub_uint64_t blockend = data->block_size;
|
||||
grub_uint64_t blockend = 1 << data->log_block_size;
|
||||
grub_off_t skipfirst = 0;
|
||||
|
||||
blknr = grub_minix_get_file_block (data, i);
|
||||
|
@ -252,10 +269,10 @@ grub_minix_read_file (struct grub_minix_data *data,
|
|||
/* Last block. */
|
||||
if (i == blockcnt - 1)
|
||||
{
|
||||
grub_divmod64 (len + pos, data->block_size, &blockend);
|
||||
blockend = (len + pos) & ((1 << data->log_block_size) - 1);
|
||||
|
||||
if (!blockend)
|
||||
blockend = data->block_size;
|
||||
blockend = 1 << data->log_block_size;
|
||||
}
|
||||
|
||||
/* First block. */
|
||||
|
@ -273,7 +290,7 @@ grub_minix_read_file (struct grub_minix_data *data,
|
|||
if (grub_errno)
|
||||
return -1;
|
||||
|
||||
buf += data->block_size - skipfirst;
|
||||
buf += (1 << data->log_block_size) - skipfirst;
|
||||
}
|
||||
|
||||
return len;
|
||||
|
@ -424,7 +441,7 @@ grub_minix_find_file (struct grub_minix_data *data, const char *path)
|
|||
pos += sizeof (ino) + data->filename_size;
|
||||
} while (pos < GRUB_MINIX_INODE_SIZE (data));
|
||||
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
|
||||
grub_error (GRUB_ERR_FILE_NOT_FOUND, "file `%s' not found", path);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
|
@ -463,9 +480,14 @@ grub_minix_mount (grub_disk_t disk)
|
|||
data->disk = disk;
|
||||
data->linknest = 0;
|
||||
#ifdef MODE_MINIX3
|
||||
data->block_size = grub_le_to_cpu16 (data->sblock.block_size);
|
||||
if ((grub_le_to_cpu16 (data->sblock.block_size)
|
||||
& (grub_le_to_cpu16 (data->sblock.block_size) - 1))
|
||||
|| grub_le_to_cpu16 (data->sblock.block_size) == 0)
|
||||
goto fail;
|
||||
for (data->log_block_size = 0; (1 << data->log_block_size)
|
||||
< grub_le_to_cpu16 (data->sblock.block_size); data->log_block_size++);
|
||||
#else
|
||||
data->block_size = 1024U;
|
||||
data->log_block_size = 10;
|
||||
#endif
|
||||
|
||||
return data;
|
||||
|
@ -536,11 +558,7 @@ grub_minix_dir (grub_device_t device, const char *path,
|
|||
info.dir = ((GRUB_MINIX_INODE_MODE (data)
|
||||
& GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
|
||||
info.mtimeset = 1;
|
||||
#ifndef MODE_MINIX2
|
||||
info.mtime = grub_le_to_cpu32 (data->inode.ctime);
|
||||
#else
|
||||
info.mtime = grub_le_to_cpu32 (data->inode.mtime);
|
||||
#endif
|
||||
|
||||
if (hook (filename, &info) ? 1 : 0)
|
||||
break;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue