merge mainline into net
This commit is contained in:
		
						commit
						975cffff74
					
				
					 840 changed files with 95368 additions and 37287 deletions
				
			
		
							
								
								
									
										304
									
								
								grub-core/Makefile.am
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								grub-core/Makefile.am
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,304 @@ | |||
| AUTOMAKE_OPTIONS = subdir-objects | ||||
| 
 | ||||
| DEPDIR=.deps-core | ||||
| 
 | ||||
| include $(top_srcdir)/conf/Makefile.common | ||||
| 
 | ||||
| CC=$(TARGET_CC) | ||||
| CPP=$(TARGET_CC) | ||||
| CCAS=$(TARGET_CC) | ||||
| 
 | ||||
| if COND_GRUB_MKFONT | ||||
| if COND_HAVE_FONT_SOURCE | ||||
| TARGET_CFLAGS += -DUSE_ASCII_FAILBACK=1 -DHAVE_UNIFONT_WIDTHSPEC=1 | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| AM_CFLAGS = $(TARGET_CFLAGS) | ||||
| AM_LDFLAGS = $(TARGET_LDFLAGS) | ||||
| AM_CPPFLAGS = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) | ||||
| AM_CCASFLAGS = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) | ||||
| 
 | ||||
| CFLAGS_PROGRAM += $(CFLAGS_PLATFORM) | ||||
| LDFLAGS_PROGRAM += $(LDFLAGS_PLATFORM) | ||||
| CPPFLAGS_PROGRAM += $(CPPFLAGS_PLATFORM) | ||||
| CCASFLAGS_PROGRAM += $(CCASFLAGS_PLATFORM) | ||||
| 
 | ||||
| CFLAGS_LIBRARY += $(CFLAGS_PLATFORM) -fno-builtin | ||||
| CPPFLAGS_LIBRARY += $(CPPFLAGS_PLATFORM) | ||||
| CCASFLAGS_LIBRARY += $(CCASFLAGS_PLATFORM) | ||||
| 
 | ||||
| # gentrigtables | ||||
| gentrigtables: gentrigtables.c | ||||
| 	$(BUILD_CC) -o $@ -I$(top_srcdir)/include $(CPPFLAGS) -lm $< | ||||
| CLEANFILES += gentrigtables | ||||
| 
 | ||||
| # trigtables.c | ||||
| trigtables.c: gentrigtables gentrigtables.c $(top_srcdir)/configure.ac | ||||
| 	$(builddir)/gentrigtables > $@ | ||||
| CLEANFILES += trigtables.c | ||||
| 
 | ||||
| # XXX Use Automake's LEX & YACC support | ||||
| grub_script.tab.h: script/parser.y | ||||
| 	$(YACC) -d -p grub_script_yy -b grub_script $< | ||||
| grub_script.tab.c: grub_script.tab.h | ||||
| CLEANFILES += grub_script.tab.c grub_script.tab.h | ||||
| 
 | ||||
| # For the lexer. | ||||
| grub_script.yy.h: script/yylex.l | ||||
| 	$(LEX) -o grub_script.yy.c --header-file=grub_script.yy.h $< | ||||
| grub_script.yy.c: grub_script.yy.h | ||||
| CLEANFILES += grub_script.yy.c grub_script.yy.h | ||||
| 
 | ||||
| include $(srcdir)/Makefile.core.am | ||||
| include $(srcdir)/Makefile.gcry.am | ||||
| 
 | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/disk.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dl.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h | ||||
| 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 | ||||
| 
 | ||||
| if COND_i386_pc | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_i386_efi | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/time.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_i386_coreboot | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_i386_multiboot | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_i386_qemu | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_i386_ieee1275 | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_x86_64_efi | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/time.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h | ||||
| endif | ||||
| 
 | ||||
| if COND_mips_yeeloong | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h | ||||
| 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/pci.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cs5536.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pci.h | ||||
| KERNEL_HEADER_FILES += $(top_builddir)/include/grub/serial.h | ||||
| endif | ||||
| 
 | ||||
| if COND_powerpc_ieee1275 | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h | ||||
| endif | ||||
| 
 | ||||
| if COND_sparc64_ieee1275 | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sparc64/ieee1275/ieee1275.h | ||||
| endif | ||||
| 
 | ||||
| if COND_emu | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h | ||||
| if COND_GRUB_EMU_SDL | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h | ||||
| endif | ||||
| if COND_GRUB_EMU_USB | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libusb.h | ||||
| endif | ||||
| if COND_GRUB_EMU_PCI | ||||
| KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libpciaccess.h | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| symlist.h: $(top_builddir)/config.h $(KERNEL_HEADER_FILES) | ||||
| 	@list='$^'; \ | ||||
| 	for p in $$list; do \ | ||||
| 	  echo "#include <$$p>" >> $@ || (rm -f $@; exit 1); \ | ||||
| 	done | ||||
| CLEANFILES += symlist.h | ||||
| BUILT_SOURCES += symlist.h | ||||
| 
 | ||||
| symlist.c: symlist.h gensymlist.sh | ||||
| 	$(TARGET_CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) $(CPPFLAGS) -DGRUB_SYMBOL_GENERATOR=1 symlist.h > symlist.p || (rm -f symlist.p; exit 1) | ||||
| 	cat symlist.p | /bin/sh $(srcdir)/gensymlist.sh $(top_builddir)/config.h $(KERNEL_HEADER_FILES) >$@ || (rm -f $@; exit 1) | ||||
| 	rm -f symlist.p | ||||
| CLEANFILES += symlist.c | ||||
| BUILT_SOURCES += symlist.c | ||||
| 
 | ||||
| noinst_DATA += kernel_syms.lst | ||||
| kernel_syms.lst: $(KERNEL_HEADER_FILES) $(top_builddir)/config.h | ||||
| 	$(TARGET_CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) $(CPPFLAGS) $(CFLAGS) -DGRUB_SYMBOL_GENERATOR=1 $^ >kernel_syms.input | ||||
| 	if grep "^#define HAVE_ASM_USCORE" $(top_builddir)/config.h; then u="_"; else u=""; fi; \ | ||||
| 	cat kernel_syms.input | grep -v '^#' | sed -n \ | ||||
| 	  -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/'"$$u"'\1 kernel/;p;}' \ | ||||
| 	  -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/'"$$u"'\1 kernel/;p;}' \ | ||||
| 	  | sort -u >$@ | ||||
| 	rm -f kernel_syms.input | ||||
| CLEANFILES += kernel_syms.lst | ||||
| 
 | ||||
| if COND_emu | ||||
| kern/emu/grub_emu-main.$(OBJEXT):grub_emu_init.h | ||||
| grub_emu-grub_emu_init.$(OBJEXT):grub_emu_init.h | ||||
| kern/emu/grub_emu_dyn-main.$(OBJEXT):grub_emu_init.h | ||||
| grub_emu_dyn-grub_emu_init.$(OBJEXT):grub_emu_init.h | ||||
| 
 | ||||
| grub_emu_init.h: genemuinitheader.sh $(MOD_FILES) | ||||
| 	rm -f $@; echo $(MOD_FILES) | sh $(srcdir)/genemuinitheader.sh $(NM) > $@ | ||||
| CLEANFILES += grub_emu_init.h | ||||
| 
 | ||||
| grub_emu_init.c: grub_emu_init.h genemuinit.sh $(MOD_FILES) | ||||
| 	rm -f $@; echo $(MOD_FILES) | sh $(srcdir)/genemuinit.sh $(NM) > $@ | ||||
| CLEANFILES += grub_emu_init.c | ||||
| endif | ||||
| 
 | ||||
| # .lst files | ||||
| platform_DATA += moddep.lst | ||||
| platform_DATA += fs.lst | ||||
| platform_DATA += command.lst | ||||
| platform_DATA += partmap.lst | ||||
| platform_DATA += handler.lst | ||||
| platform_DATA += terminal.lst | ||||
| platform_DATA += parttool.lst | ||||
| platform_DATA += video.lst | ||||
| platform_DATA += crypto.lst | ||||
| CLEANFILES += moddep.lst | ||||
| CLEANFILES += handler.lst | ||||
| CLEANFILES += terminal.lst | ||||
| CLEANFILES += parttool.lst | ||||
| CLEANFILES += video.lst | ||||
| CLEANFILES += crypto.lst | ||||
| 
 | ||||
| fs.lst: $(FS_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += fs.lst | ||||
| 
 | ||||
| command.lst: $(COMMAND_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += command.lst | ||||
| 
 | ||||
| partmap.lst: $(PARTMAP_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += partmap.lst | ||||
| 
 | ||||
| handler.lst: $(HANDLER_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += handler.lst | ||||
| 
 | ||||
| terminal.lst: $(TERMINAL_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += terminal.lst | ||||
| 
 | ||||
| parttool.lst: $(PARTTOOL_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += parttool.lst | ||||
| 
 | ||||
| video.lst: $(VIDEO_FILES) | ||||
| 	cat $^ /dev/null | sort | uniq > $@ | ||||
| CLEANFILES += video.lst | ||||
| 
 | ||||
| # but, crypto.lst is simply copied | ||||
| crypto.lst: $(srcdir)/lib/libgcrypt-grub/cipher/crypto.lst | ||||
| 	cp $^ $@ | ||||
| CLEANFILES += crypto.lst | ||||
| 
 | ||||
| # generate global module dependencies list | ||||
| moddep.lst: kernel_syms.lst genmoddep.awk $(DEF_FILES) $(UND_FILES) | ||||
| 	cat $(DEF_FILES) kernel_syms.lst /dev/null \ | ||||
| 	  | $(AWK) -f $(srcdir)/genmoddep.awk $(UND_FILES) > $@ \ | ||||
| 	  || (rm -f $@; exit 1) | ||||
| 
 | ||||
| if COND_ENABLE_EFIEMU | ||||
| efiemu32.o: efiemu/runtime/efiemu.c $(TARGET_OBJ2ELF) | ||||
| 	-rm -f $@; \ | ||||
| 	if test "x$(TARGET_APPLE_CC)" = x1; then \ | ||||
| 	  $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -DELF32 -DAPPLE_CC -m32 -Wall -Werror -nostdlib -O2 -c -o $@.bin $< || exit 1; \ | ||||
| 	  $(OBJCONV) -felf32 -nu -nd $@.bin $@ || exit 1; \ | ||||
| 	  rm -f $@.bin; \ | ||||
| 	else \ | ||||
| 	  $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -DELF32 -m32 -Wall -Werror -nostdlib -O2 -c -o $@ $< || exit 1; \ | ||||
| 	  if test ! -z "$(TARGET_OBJ2ELF)"; then $(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi; \ | ||||
| 	fi | ||||
| 
 | ||||
| efiemu64_c.o: efiemu/runtime/efiemu.c | ||||
| 	if test "x$(TARGET_APPLE_CC)" = x1; then \ | ||||
| 	  $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -DELF64 -DAPPLE_CC=1 -m64 -nostdlib -Wall -Werror -mno-red-zone -c -o $@ $< || exit 1; \ | ||||
| 	else \ | ||||
| 	  $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -DELF64 -m64 -nostdlib -Wall -Werror -O2 -mcmodel=large -mno-red-zone -c -o $@ $< || exit 1; \ | ||||
| 	fi | ||||
| 
 | ||||
| efiemu64_s.o: efiemu/runtime/efiemu.S | ||||
| 	-rm -f $@ | ||||
| 	if test "x$(TARGET_APPLE_CC)" = x1; then \ | ||||
| 	  $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -DELF64 -DAPPLE_CC=1 -m64 -Wall -Werror -nostdlib -O2 -mno-red-zone -c -o $@ $< || exit 1; \ | ||||
| 	else \ | ||||
| 	  $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -DELF64 -m64 -Wall -Werror -nostdlib -O2 -mcmodel=large -mno-red-zone -c -o $@ $< || exit 1; \ | ||||
| 	fi | ||||
| 
 | ||||
| efiemu64.o: efiemu64_c.o efiemu64_s.o $(TARGET_OBJ2ELEF) | ||||
| 	-rm -f $@; \ | ||||
| 	if test "x$(TARGET_APPLE_CC)" = x1; then \ | ||||
| 	  rm -f $@.bin; \ | ||||
| 	  $(TARGET_CC) -m64 -Wl,-r -nostdlib -o $@.bin $^ || exit 1; \ | ||||
| 	  $(OBJCONV) -felf64 -nu -nd $@.bin $@ || exit 1; \ | ||||
| 	  rm -f $@.bin; \ | ||||
| 	else \ | ||||
| 	  $(TARGET_CC) -m64 -nostdlib -Wl,-r -o $@ $^ || exit 1; \ | ||||
| 	  if test ! -z "$(TARGET_OBJ2ELF)"; then $(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi; \ | ||||
| 	fi | ||||
| 
 | ||||
| platform_DATA += efiemu32.o efiemu64.o | ||||
| CLEANFILES += efiemu32.o efiemu64.o efiemu64_c.o efiemu64_s.o | ||||
| endif | ||||
							
								
								
									
										1383
									
								
								grub-core/Makefile.core.def
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1383
									
								
								grub-core/Makefile.core.def
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										475
									
								
								grub-core/boot/i386/pc/boot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								grub-core/boot/i386/pc/boot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,475 @@ | |||
| /* -*-Asm-*- */ | ||||
| /* | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 1999,2000,2001,2002,2005,2006,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/symbol.h> | ||||
| #include <grub/boot.h> | ||||
| #include <grub/machine/boot.h> | ||||
| 
 | ||||
| /* | ||||
|  *  defines for the code go here | ||||
|  */ | ||||
| 
 | ||||
| 	/* Print message string */ | ||||
| #define MSG(x)	movw $x, %si; call LOCAL(message)
 | ||||
| #define ERR(x)	movw $x, %si; jmp LOCAL(error_message)
 | ||||
| 
 | ||||
| 	.file	"boot.S" | ||||
| 
 | ||||
| 	.text | ||||
| 
 | ||||
| 	/* Tell GAS to generate 16-bit instructions so that this code works | ||||
| 	   in real mode. */ | ||||
| 	.code16 | ||||
| 
 | ||||
| .globl _start, start;
 | ||||
| _start: | ||||
| start: | ||||
| 	/* | ||||
| 	 * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00 | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Beginning of the sector is compatible with the FAT/HPFS BIOS | ||||
| 	 * parameter block. | ||||
| 	 */ | ||||
| 
 | ||||
| 	jmp	LOCAL(after_BPB) | ||||
| 	nop	/* do I care about this ??? */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 * This space is for the BIOS parameter block!!!!  Don't change | ||||
| 	 * the first jump, nor start the code anywhere but right after | ||||
| 	 * this area. | ||||
| 	 */ | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_BPB_START | ||||
| 	. = _start + 4 | ||||
| 
 | ||||
| 	/* scratch space */ | ||||
| mode: | ||||
| 	.byte	0
 | ||||
| disk_address_packet: | ||||
| sectors: | ||||
| 	.long	0
 | ||||
| heads: | ||||
| 	.long	0
 | ||||
| cylinders: | ||||
| 	.word	0
 | ||||
| sector_start: | ||||
| 	.byte	0
 | ||||
| head_start: | ||||
| 	.byte	0
 | ||||
| cylinder_start: | ||||
| 	.word	0
 | ||||
| 	/* more space... */ | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_BPB_END | ||||
| 
 | ||||
| 	/* | ||||
| 	 * End of BIOS parameter block. | ||||
| 	 */ | ||||
| 
 | ||||
| kernel_address: | ||||
| 	.word	GRUB_BOOT_MACHINE_KERNEL_ADDR
 | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_KERNEL_SECTOR | ||||
| kernel_sector: | ||||
| 	.long	1, 0 | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_BOOT_DRIVE | ||||
| boot_drive: | ||||
| 	.byte 0xff	/* the disk to load kernel from */ | ||||
| 			/* 0xff means use the boot drive */ | ||||
| 
 | ||||
| LOCAL(after_BPB): | ||||
| 
 | ||||
| /* general setup */ | ||||
| 	cli		/* we're not safe here! */ | ||||
| 
 | ||||
|         /* | ||||
|          * This is a workaround for buggy BIOSes which don't pass boot | ||||
|          * drive correctly. If GRUB is installed into a HDD, check if | ||||
|          * DL is masked correctly. If not, assume that the BIOS passed | ||||
|          * a bogus value and set DL to 0x80, since this is the only | ||||
|          * possible boot drive. If GRUB is installed into a floppy, | ||||
|          * this does nothing (only jump). | ||||
|          */ | ||||
| 	. = _start + GRUB_BOOT_MACHINE_DRIVE_CHECK | ||||
| boot_drive_check: | ||||
|         jmp     1f	/* grub-setup may overwrite this jump */ | ||||
|         testb   $0x80, %dl | ||||
|         jnz     1f | ||||
|         movb    $0x80, %dl | ||||
| 1: | ||||
| 
 | ||||
| 	/* | ||||
| 	 * ljmp to the next instruction because some bogus BIOSes | ||||
| 	 * jump to 07C0:0000 instead of 0000:7C00. | ||||
| 	 */ | ||||
| 	ljmp	$0, $real_start | ||||
| 
 | ||||
| real_start: | ||||
| 
 | ||||
| 	/* set up %ds and %ss as offset from 0 */ | ||||
| 	xorw	%ax, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	%ax, %ss | ||||
| 
 | ||||
| 	/* set up the REAL stack */ | ||||
| 	movw	$GRUB_BOOT_MACHINE_STACK_SEG, %sp | ||||
| 
 | ||||
| 	sti		/* we're safe again */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 *  Check if we have a forced disk reference here | ||||
| 	 */ | ||||
| 	movb   boot_drive, %al | ||||
| 	cmpb	$0xff, %al | ||||
| 	je	1f | ||||
| 	movb	%al, %dl | ||||
| 1: | ||||
| 	/* save drive reference first thing! */ | ||||
| 	pushw	%dx | ||||
| 
 | ||||
| 	/* print a notification message on the screen */ | ||||
| 	MSG(notification_string) | ||||
| 
 | ||||
| 	/* set %si to the disk address packet */ | ||||
| 	movw	$disk_address_packet, %si | ||||
| 
 | ||||
| 	/* check if LBA is supported */ | ||||
| 	movb	$0x41, %ah | ||||
| 	movw	$0x55aa, %bx | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	/* | ||||
| 	 *  %dl may have been clobbered by INT 13, AH=41H. | ||||
| 	 *  This happens, for example, with AST BIOS 1.04. | ||||
| 	 */ | ||||
| 	popw	%dx | ||||
| 	pushw	%dx | ||||
| 
 | ||||
| 	/* use CHS if fails */ | ||||
| 	jc	LOCAL(chs_mode) | ||||
| 	cmpw	$0xaa55, %bx | ||||
| 	jne	LOCAL(chs_mode) | ||||
| 
 | ||||
| 	andw	$1, %cx | ||||
| 	jz	LOCAL(chs_mode) | ||||
| 
 | ||||
| lba_mode: | ||||
| 	xorw	%ax, %ax | ||||
| 	movw	%ax, 4(%si) | ||||
| 
 | ||||
| 	incw	%ax | ||||
| 	/* set the mode to non-zero */ | ||||
| 	movb	%al, -1(%si) | ||||
| 
 | ||||
| 	/* the blocks */ | ||||
| 	movw	%ax, 2(%si) | ||||
| 
 | ||||
| 	/* the size and the reserved byte */ | ||||
| 	movw	$0x0010, (%si) | ||||
| 
 | ||||
| 	/* the absolute address */ | ||||
| 	movl	kernel_sector, %ebx | ||||
| 	movl	%ebx, 8(%si) | ||||
| 	movl	kernel_sector + 4, %ebx | ||||
| 	movl	%ebx, 12(%si) | ||||
| 
 | ||||
| 	/* the segment of buffer address */ | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si) | ||||
| 
 | ||||
| /* | ||||
|  * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory | ||||
|  *	Call with	%ah = 0x42 | ||||
|  *			%dl = drive number | ||||
|  *			%ds:%si = segment:offset of disk address packet | ||||
|  *	Return: | ||||
|  *			%al = 0x0 on success; err code on failure
 | ||||
|  */ | ||||
| 
 | ||||
| 	movb	$0x42, %ah | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	/* LBA read is not supported, so fallback to CHS.  */ | ||||
| 	jc	LOCAL(chs_mode) | ||||
| 
 | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, %bx | ||||
| 	jmp	LOCAL(copy_buffer) | ||||
| 
 | ||||
| LOCAL(chs_mode): | ||||
| 	/* | ||||
| 	 *  Determine the hard disk geometry from the BIOS! | ||||
| 	 *  We do this first, so that LS-120 IDE floppies work correctly. | ||||
| 	 */ | ||||
| 	movb	$8, %ah | ||||
| 	int	$0x13 | ||||
| 	jnc	LOCAL(final_init) | ||||
| 
 | ||||
| 	/* | ||||
| 	 *  The call failed, so maybe use the floppy probe instead. | ||||
| 	 */ | ||||
| 	testb	$GRUB_BOOT_MACHINE_BIOS_HD_FLAG, %dl | ||||
| 	jz	LOCAL(floppy_probe) | ||||
| 
 | ||||
| 	/* Nope, we definitely have a hard disk, and we're screwed. */ | ||||
| 	ERR(hd_probe_error_string) | ||||
| 
 | ||||
| LOCAL(final_init): | ||||
| 	/* set the mode to zero */ | ||||
| 	movzbl	%dh, %eax | ||||
| 	movb	%ah, -1(%si) | ||||
| 
 | ||||
| 	/* save number of heads */ | ||||
| 	incw	%ax | ||||
| 	movl	%eax, 4(%si) | ||||
| 
 | ||||
| 	movzbw	%cl, %dx | ||||
| 	shlw	$2, %dx | ||||
| 	movb	%ch, %al | ||||
| 	movb	%dh, %ah | ||||
| 
 | ||||
| 	/* save number of cylinders */ | ||||
| 	incw	%ax | ||||
| 	movw	%ax, 8(%si) | ||||
| 
 | ||||
| 	movzbw	%dl, %ax | ||||
| 	shrb	$2, %al | ||||
| 
 | ||||
| 	/* save number of sectors */ | ||||
| 	movl	%eax, (%si) | ||||
| 
 | ||||
| setup_sectors: | ||||
| 	/* load logical sector start (top half) */ | ||||
| 	movl	kernel_sector + 4, %eax | ||||
| 
 | ||||
| 	orl	%eax, %eax | ||||
| 	jnz	LOCAL(geometry_error) | ||||
| 
 | ||||
| 	/* load logical sector start (bottom half) */ | ||||
| 	movl	kernel_sector, %eax | ||||
| 
 | ||||
| 	/* zero %edx */ | ||||
| 	xorl	%edx, %edx | ||||
| 
 | ||||
| 	/* divide by number of sectors */ | ||||
| 	divl	(%si) | ||||
| 
 | ||||
| 	/* save sector start */ | ||||
| 	movb	%dl, %cl | ||||
| 
 | ||||
| 	xorw	%dx, %dx	/* zero %edx */ | ||||
| 	divl	4(%si)		/* divide by number of heads */ | ||||
| 
 | ||||
| 	/* do we need too many cylinders? */ | ||||
| 	cmpw	8(%si), %ax | ||||
| 	jge	LOCAL(geometry_error) | ||||
| 
 | ||||
| 	/* normalize sector start (1-based) */ | ||||
| 	incb	%cl | ||||
| 
 | ||||
| 	/* low bits of cylinder start */ | ||||
| 	movb	%al, %ch | ||||
| 
 | ||||
| 	/* high bits of cylinder start */ | ||||
| 	xorb	%al, %al | ||||
| 	shrw	$2, %ax | ||||
| 	orb	%al, %cl | ||||
| 
 | ||||
| 	/* save head start */ | ||||
| 	movb	%dl, %al | ||||
| 
 | ||||
| 	/* restore %dl */ | ||||
| 	popw	%dx | ||||
| 
 | ||||
| 	/* head start */ | ||||
| 	movb	%al, %dh | ||||
| 
 | ||||
| /* | ||||
|  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory | ||||
|  *	Call with	%ah = 0x2 | ||||
|  *			%al = number of sectors | ||||
|  *			%ch = cylinder | ||||
|  *			%cl = sector (bits 6-7 are high bits of "cylinder") | ||||
|  *			%dh = head | ||||
|  *			%dl = drive (0x80 for hard disk, 0x0 for floppy disk) | ||||
|  *			%es:%bx = segment:offset of buffer | ||||
|  *	Return: | ||||
|  *			%al = 0x0 on success; err code on failure
 | ||||
|  */ | ||||
| 
 | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, %bx | ||||
| 	movw	%bx, %es	/* load %es segment with disk buffer */ | ||||
| 
 | ||||
| 	xorw	%bx, %bx	/* %bx = 0, put it at 0 in the segment */ | ||||
| 	movw	$0x0201, %ax	/* function 2 */ | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	jc	LOCAL(read_error) | ||||
| 
 | ||||
| 	movw	%es, %bx | ||||
| 
 | ||||
| LOCAL(copy_buffer): | ||||
| 	/* | ||||
| 	 * We need to save %cx and %si because the startup code in | ||||
| 	 * kernel uses them without initializing them. | ||||
| 	 */ | ||||
| 	pusha | ||||
| 	pushw	%ds | ||||
| 
 | ||||
| 	movw	$0x100, %cx | ||||
| 	movw	%bx, %ds | ||||
| 	xorw	%si, %si | ||||
| 	movw	$GRUB_BOOT_MACHINE_KERNEL_ADDR, %di | ||||
| 	movw	%si, %es | ||||
| 
 | ||||
| 	cld | ||||
| 
 | ||||
| 	rep | ||||
| 	movsw | ||||
| 
 | ||||
| 	popw	%ds | ||||
| 	popa | ||||
| 
 | ||||
| 	/* boot kernel */ | ||||
| 	jmp	*(kernel_address) | ||||
| 
 | ||||
| /* END OF MAIN LOOP */ | ||||
| 
 | ||||
| /* | ||||
|  * BIOS Geometry translation error (past the end of the disk geometry!). | ||||
|  */ | ||||
| LOCAL(geometry_error): | ||||
| 	ERR(geometry_error_string) | ||||
| 
 | ||||
| /* | ||||
|  * Read error on the disk. | ||||
|  */ | ||||
| LOCAL(read_error): | ||||
| 	movw	$read_error_string, %si | ||||
| LOCAL(error_message): | ||||
| 	call	LOCAL(message) | ||||
| LOCAL(general_error): | ||||
| 	MSG(general_error_string) | ||||
| 
 | ||||
| /* go here when you need to stop the machine hard after an error condition */ | ||||
|         /* tell the BIOS a boot failure, which may result in no effect */ | ||||
|         int	$0x18 | ||||
| LOCAL(stop): | ||||
| 	jmp	LOCAL(stop) | ||||
| 
 | ||||
| notification_string:	.asciz "GRUB " | ||||
| geometry_error_string:	.asciz "Geom" | ||||
| hd_probe_error_string:	.asciz "Hard Disk" | ||||
| read_error_string:	.asciz "Read" | ||||
| general_error_string:	.asciz " Error\r\n" | ||||
| 
 | ||||
| /* | ||||
|  * message: write the string pointed to by %si | ||||
|  * | ||||
|  *   WARNING: trashes %si, %ax, and %bx | ||||
|  */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode | ||||
| 	 *	%ah = 0xe	%al = character | ||||
| 	 *	%bh = page	%bl = foreground color (graphics modes) | ||||
| 	 */ | ||||
| 1: | ||||
| 	movw	$0x0001, %bx | ||||
| 	movb	$0xe, %ah | ||||
| 	int	$0x10		/* display a byte */ | ||||
| LOCAL(message): | ||||
| 	lodsb | ||||
| 	cmpb	$0, %al | ||||
| 	jne	1b	/* if not end of string, jmp to display */ | ||||
| 	ret | ||||
| 
 | ||||
| 	/* | ||||
| 	 *  Windows NT breaks compatibility by embedding a magic | ||||
| 	 *  number here. | ||||
| 	 */ | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC | ||||
| nt_magic: | ||||
| 	.long 0
 | ||||
| 	.word 0
 | ||||
| 
 | ||||
| 	/* | ||||
| 	 *  This is where an MBR would go if on a hard disk.  The code | ||||
| 	 *  here isn't even referenced unless we're on a floppy.  Kinda | ||||
| 	 *  sneaky, huh? | ||||
| 	 */ | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_PART_START | ||||
| part_start: | ||||
| 
 | ||||
| probe_values: | ||||
| 	.byte	36, 18, 15, 9, 0 | ||||
| 
 | ||||
| LOCAL(floppy_probe): | ||||
| /* | ||||
|  *  Perform floppy probe. | ||||
|  */ | ||||
| 
 | ||||
| 	movw	$probe_values - 1, %si | ||||
| 
 | ||||
| LOCAL(probe_loop): | ||||
| 	/* reset floppy controller INT 13h AH=0 */ | ||||
| 	xorw	%ax, %ax | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	incw	%si | ||||
| 	movb	(%si), %cl | ||||
| 
 | ||||
| 	/* if number of sectors is 0, display error and die */ | ||||
| 	cmpb	$0, %cl | ||||
| 	jne	1f | ||||
| 
 | ||||
| /* | ||||
|  * Floppy disk probe failure. | ||||
|  */ | ||||
| 	MSG(fd_probe_error_string) | ||||
| 	jmp	LOCAL(general_error) | ||||
| 
 | ||||
| /* "Floppy" */ | ||||
| fd_probe_error_string:	.asciz "Floppy" | ||||
| 
 | ||||
| 1: | ||||
| 	/* perform read */ | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, %bx | ||||
| 	movw	$0x201, %ax | ||||
| 	movb	$0, %ch | ||||
| 	movb	$0, %dh | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	/* if error, jump to "LOCAL(probe_loop)" */ | ||||
| 	jc	LOCAL(probe_loop) | ||||
| 
 | ||||
| 	/* %cl is already the correct value! */ | ||||
| 	movb	$1, %dh | ||||
| 	movb	$79, %ch | ||||
| 
 | ||||
| 	jmp	LOCAL(final_init) | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_PART_END | ||||
| 
 | ||||
| /* the last 2 bytes in the sector 0 contain the signature */ | ||||
| 	.word	GRUB_BOOT_MACHINE_SIGNATURE
 | ||||
							
								
								
									
										173
									
								
								grub-core/boot/i386/pc/cdboot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								grub-core/boot/i386/pc/cdboot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,173 @@ | |||
| /* -*-Asm-*- */ | ||||
| /* | ||||
|  *  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/symbol.h> | ||||
| #include <grub/boot.h> | ||||
| #include <grub/machine/boot.h> | ||||
| #include <grub/machine/kernel.h> | ||||
| #include <multiboot.h> | ||||
| 
 | ||||
|         .file   "cdboot.S" | ||||
| 
 | ||||
| #define CODE_ADDR	0x6000 | ||||
| #define DATA_ADDR	((GRUB_BOOT_MACHINE_KERNEL_ADDR) + 0x200) | ||||
| 
 | ||||
| #define CDSEC_SHIFT	11 | ||||
| #define CDBLK_LENG	16 | ||||
| 
 | ||||
| 	.text | ||||
| 
 | ||||
|         .code16 | ||||
| 
 | ||||
|         .globl  start, _start | ||||
| 
 | ||||
| start: | ||||
| _start: | ||||
| 	call	LOCAL(next) | ||||
| 
 | ||||
| LOCAL(next): | ||||
| 	jmp	1f | ||||
| 
 | ||||
| 	. = start + 8 | ||||
| 
 | ||||
| bi_pvd: | ||||
| 	.long 0		/* LBA of primary volume descriptor.  */ | ||||
| bi_file: | ||||
| 	.long 0		/* LBA of boot file. */ | ||||
| bi_length: | ||||
| 	.long 0		/* Length of boot file. */ | ||||
| bi_csum: | ||||
| 	.long 0		/* Checksum of boot file */ | ||||
| bi_reserved: | ||||
| 	.space (10*4)	/* Reserved */ | ||||
| 
 | ||||
| 1: | ||||
| 	popw	%bx | ||||
| 
 | ||||
| 	/* Boot from CDROM.  */ | ||||
| 
 | ||||
| 	xorw	%ax, %ax | ||||
| 	movw	%ax, %ss | ||||
| 	movw	$(CODE_ADDR), %sp | ||||
| 	movw	%ax, %ds | ||||
| 	movw	%ax, %es | ||||
| 
 | ||||
| 	movw	$(0x7C00 + err_noboot_msg - start), %si | ||||
| 	movl	%cs: bi_length - LOCAL(next)(%bx), %ecx | ||||
| 	orl	%ecx, %ecx | ||||
| 	jz	LOCAL(fail) | ||||
| 
 | ||||
| 	addl	$((1 << CDSEC_SHIFT) - 1), %ecx | ||||
| 	shrl	$CDSEC_SHIFT, %ecx | ||||
| 
 | ||||
| 	movl	%cs: bi_file - LOCAL(next)(%bx), %esi | ||||
| 
 | ||||
| 	call	LOCAL(read_cdrom) | ||||
| 
 | ||||
| 	ljmp	$(DATA_ADDR >> 4), $0 | ||||
| 
 | ||||
| /* | ||||
|  * Parameters: | ||||
|  *   esi: start sector | ||||
|  *   ecx: number of sectors | ||||
|  */ | ||||
| LOCAL(read_cdrom): | ||||
| 	xorl	%eax, %eax | ||||
| 
 | ||||
| 	/* Number of blocks to read.  */ | ||||
| 	pushw	$CDBLK_LENG | ||||
| 
 | ||||
| 	/* Block number.  */ | ||||
| 	pushl	%eax | ||||
| 	pushl	%esi | ||||
| 
 | ||||
| 	/* Buffer address.  */ | ||||
| 	pushw	$((DATA_ADDR - 0x400)>> 4) | ||||
| 	pushl	%eax | ||||
| 	pushw	$0x10 | ||||
| 
 | ||||
| 	xorl	%edi, %edi | ||||
| 	movw	%sp, %si | ||||
| 
 | ||||
| 1: | ||||
| 	movw	0x10(%si), %di | ||||
| 	cmpl	%ecx, %edi | ||||
| 	jbe	2f | ||||
| 	movl	%ecx, %edi | ||||
| 
 | ||||
| 2: | ||||
| 	mov	%di, 2(%si) | ||||
| 
 | ||||
| 	pushl	%ecx | ||||
| 
 | ||||
| 	movb	$0x42, %ah | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	jnc	3f | ||||
| 
 | ||||
| 	movb	$0x42, %ah		/* Try again.  */ | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	jnc	3f | ||||
| 
 | ||||
| 2: | ||||
| 	shrw	$1, %di			/* Reduce transfer size.  */ | ||||
| 	jz	LOCAL(cdrom_fail) | ||||
| 	movw	%di, 0x10(%si) | ||||
| 	movw	%di, 2(%si) | ||||
| 	movb	$0x42, %ah | ||||
| 	int	$0x13 | ||||
| 	jc	2b | ||||
| 
 | ||||
| 3: | ||||
| 
 | ||||
| 	movw	%di, %ax | ||||
| 	shlw	$(CDSEC_SHIFT - 4), %ax | ||||
| 	addw	%ax, 6(%si) | ||||
| 	addl	%edi, 8(%si) | ||||
| 
 | ||||
| 	popl	%ecx | ||||
| 	subl	%edi, %ecx | ||||
| 	jnz	1b | ||||
| 
 | ||||
| 	addw	$0x12, %sp | ||||
| 	ret | ||||
| 
 | ||||
| LOCAL(cdrom_fail): | ||||
| 	movw	$(0x7C00 + err_cdfail_msg - start), %si | ||||
| 
 | ||||
| LOCAL(fail): | ||||
| 	movb	$0x0e, %ah | ||||
| 	xorw	%bx, %bx | ||||
| 1: | ||||
| 	lodsb	(%si), %al | ||||
| 	int	$0x10 | ||||
| 	cmpb	$0, %al | ||||
| 	jne	1b | ||||
| 1:	jmp	1b | ||||
| 
 | ||||
| err_noboot_msg: | ||||
| 	.ascii	"no boot info\0" | ||||
| 
 | ||||
| err_cdfail_msg: | ||||
| 	.ascii	"cdrom read fails\0" | ||||
| 
 | ||||
| 	. = start + 0x1FF | ||||
| 
 | ||||
| 	.byte	0
 | ||||
							
								
								
									
										380
									
								
								grub-core/boot/i386/pc/diskboot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								grub-core/boot/i386/pc/diskboot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,380 @@ | |||
| /* | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 1999,2000,2001,2002,2006,2007,2009,2010   Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/symbol.h> | ||||
| #include <grub/machine/boot.h> | ||||
| 
 | ||||
| /* | ||||
|  *  defines for the code go here | ||||
|  */ | ||||
| 
 | ||||
| #define MSG(x)	movw $x, %si; call LOCAL(message)
 | ||||
| 
 | ||||
| 	.file	"diskboot.S" | ||||
| 
 | ||||
| 	.text | ||||
| 
 | ||||
| 	/* Tell GAS to generate 16-bit instructions so that this code works | ||||
| 	   in real mode. */ | ||||
| 	.code16 | ||||
| 
 | ||||
| 	.globl	start, _start | ||||
| start: | ||||
| _start: | ||||
| 	/* | ||||
| 	 * _start is loaded at 0x2000 and is jumped to with | ||||
| 	 * CS:IP 0:0x2000 in kernel. | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 * we continue to use the stack for boot.img and assume that | ||||
| 	 * some registers are set to correct values. See boot.S | ||||
| 	 * for more information. | ||||
| 	 */ | ||||
| 
 | ||||
| 	/* save drive reference first thing! */ | ||||
| 	pushw	%dx | ||||
| 
 | ||||
| 	/* print a notification message on the screen */ | ||||
| 	pushw	%si | ||||
| 	MSG(notification_string) | ||||
| 	popw	%si | ||||
| 
 | ||||
| 	/* this sets up for the first run through "bootloop" */ | ||||
| 	movw	$(firstlist - GRUB_BOOT_MACHINE_LIST_SIZE), %di | ||||
| 
 | ||||
| 	/* save the sector number of the second sector in %ebp */ | ||||
| 	movl	(%di), %ebp | ||||
| 
 | ||||
|         /* this is the loop for reading the rest of the kernel in */ | ||||
| LOCAL(bootloop): | ||||
| 
 | ||||
| 	/* check the number of sectors to read */ | ||||
| 	cmpw	$0, 8(%di) | ||||
| 
 | ||||
| 	/* if zero, go to the start function */ | ||||
| 	je	LOCAL(bootit) | ||||
| 
 | ||||
| LOCAL(setup_sectors): | ||||
| 	/* check if we use LBA or CHS */ | ||||
| 	cmpb	$0, -1(%si) | ||||
| 
 | ||||
| 	/* use CHS if zero, LBA otherwise */ | ||||
| 	je	LOCAL(chs_mode) | ||||
| 
 | ||||
| 	/* load logical sector start */ | ||||
| 	movl	(%di), %ebx | ||||
| 	movl	4(%di), %ecx | ||||
| 
 | ||||
| 	/* the maximum is limited to 0x7f because of Phoenix EDD */ | ||||
| 	xorl	%eax, %eax | ||||
| 	movb	$0x7f, %al | ||||
| 
 | ||||
| 	/* how many do we really want to read? */ | ||||
| 	cmpw	%ax, 8(%di)	/* compare against total number of sectors */ | ||||
| 
 | ||||
| 	/* which is greater? */ | ||||
| 	jg	1f | ||||
| 
 | ||||
| 	/* if less than, set to total */ | ||||
| 	movw	8(%di), %ax | ||||
| 
 | ||||
| 1: | ||||
| 	/* subtract from total */ | ||||
| 	subw	%ax, 8(%di) | ||||
| 
 | ||||
| 	/* add into logical sector start */ | ||||
| 	addl	%eax, (%di) | ||||
| 	adcl	$0, 4(%di) | ||||
| 
 | ||||
| 	/* set up disk address packet */ | ||||
| 
 | ||||
| 	/* the size and the reserved byte */ | ||||
| 	movw	$0x0010, (%si) | ||||
| 
 | ||||
| 	/* the number of sectors */ | ||||
| 	movw	%ax, 2(%si) | ||||
| 
 | ||||
| 	/* the absolute address */ | ||||
| 	movl	%ebx, 8(%si) | ||||
| 	movl	%ecx, 12(%si) | ||||
| 
 | ||||
| 	/* the segment of buffer address */ | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si) | ||||
| 
 | ||||
| 	/* save %ax from destruction! */ | ||||
| 	pushw	%ax | ||||
| 
 | ||||
| 	/* the offset of buffer address */ | ||||
| 	movw	$0, 4(%si) | ||||
| 
 | ||||
| /* | ||||
|  * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory | ||||
|  *	Call with	%ah = 0x42 | ||||
|  *			%dl = drive number | ||||
|  *			%ds:%si = segment:offset of disk address packet | ||||
|  *	Return: | ||||
|  *			%al = 0x0 on success; err code on failure
 | ||||
|  */ | ||||
| 
 | ||||
| 	movb	$0x42, %ah | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	jc	LOCAL(read_error) | ||||
| 
 | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, %bx | ||||
| 	jmp	LOCAL(copy_buffer) | ||||
| 
 | ||||
| LOCAL(chs_mode): | ||||
| 	/* load logical sector start (top half) */ | ||||
| 	movl	4(%di), %eax | ||||
| 	orl	%eax, %eax | ||||
| 	jnz	LOCAL(geometry_error) | ||||
| 
 | ||||
| 	/* load logical sector start (bottom half) */ | ||||
| 	movl	(%di), %eax | ||||
| 
 | ||||
| 	/* zero %edx */ | ||||
| 	xorl	%edx, %edx | ||||
| 
 | ||||
| 	/* divide by number of sectors */ | ||||
| 	divl	(%si) | ||||
| 
 | ||||
| 	/* save sector start */ | ||||
| 	movb	%dl, 10(%si) | ||||
| 
 | ||||
| 	xorl	%edx, %edx	/* zero %edx */ | ||||
| 	divl	4(%si)		/* divide by number of heads */ | ||||
| 
 | ||||
| 	/* save head start */ | ||||
| 	movb	%dl, 11(%si) | ||||
| 
 | ||||
| 	/* save cylinder start */ | ||||
| 	movw	%ax, 12(%si) | ||||
| 
 | ||||
| 	/* do we need too many cylinders? */ | ||||
| 	cmpw	8(%si), %ax | ||||
| 	jge	LOCAL(geometry_error) | ||||
| 
 | ||||
| 	/* determine the maximum sector length of this read */ | ||||
| 	movw	(%si), %ax	/* get number of sectors per track/head */ | ||||
| 
 | ||||
| 	/* subtract sector start */ | ||||
| 	subb	10(%si), %al | ||||
| 
 | ||||
| 	/* how many do we really want to read? */ | ||||
| 	cmpw	%ax, 8(%di)	/* compare against total number of sectors */ | ||||
| 
 | ||||
| 
 | ||||
| 	/* which is greater? */ | ||||
| 	jg	2f | ||||
| 
 | ||||
| 	/* if less than, set to total */ | ||||
| 	movw	8(%di), %ax | ||||
| 
 | ||||
| 2: | ||||
| 	/* subtract from total */ | ||||
| 	subw	%ax, 8(%di) | ||||
| 
 | ||||
| 	/* add into logical sector start */ | ||||
| 	addl	%eax, (%di) | ||||
| 	adcl	$0, 4(%di) | ||||
| 
 | ||||
| /* | ||||
|  *  This is the loop for taking care of BIOS geometry translation (ugh!) | ||||
|  */ | ||||
| 
 | ||||
| 	/* get high bits of cylinder */ | ||||
| 	movb	13(%si), %dl | ||||
| 
 | ||||
| 	shlb	$6, %dl		/* shift left by 6 bits */ | ||||
| 	movb	10(%si), %cl	/* get sector */ | ||||
| 
 | ||||
| 	incb	%cl		/* normalize sector (sectors go | ||||
| 					from 1-N, not 0-(N-1) ) */ | ||||
| 	orb	%dl, %cl	/* composite together */ | ||||
| 	movb	12(%si), %ch	/* sector+hcyl in cl, cylinder in ch */ | ||||
| 
 | ||||
| 	/* restore %dx */ | ||||
| 	popw	%dx | ||||
| 	pushw	%dx | ||||
| 
 | ||||
| 	/* head number */ | ||||
| 	movb	11(%si), %dh | ||||
| 
 | ||||
| 	pushw	%ax	/* save %ax from destruction! */ | ||||
| 
 | ||||
| /* | ||||
|  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory | ||||
|  *	Call with	%ah = 0x2 | ||||
|  *			%al = number of sectors | ||||
|  *			%ch = cylinder | ||||
|  *			%cl = sector (bits 6-7 are high bits of "cylinder") | ||||
|  *			%dh = head | ||||
|  *			%dl = drive (0x80 for hard disk, 0x0 for floppy disk) | ||||
|  *			%es:%bx = segment:offset of buffer | ||||
|  *	Return: | ||||
|  *			%al = 0x0 on success; err code on failure
 | ||||
|  */ | ||||
| 
 | ||||
| 	movw	$GRUB_BOOT_MACHINE_BUFFER_SEG, %bx | ||||
| 	movw	%bx, %es	/* load %es segment with disk buffer */ | ||||
| 
 | ||||
| 	xorw	%bx, %bx	/* %bx = 0, put it at 0 in the segment */ | ||||
| 	movb	$0x2, %ah	/* function 2 */ | ||||
| 	int	$0x13 | ||||
| 
 | ||||
| 	jc	LOCAL(read_error) | ||||
| 
 | ||||
| 	/* save source segment */ | ||||
| 	movw	%es, %bx | ||||
| 
 | ||||
| LOCAL(copy_buffer): | ||||
| 
 | ||||
| 	/* load addresses for copy from disk buffer to destination */ | ||||
| 	movw	10(%di), %es	/* load destination segment */ | ||||
| 
 | ||||
| 	/* restore %ax */ | ||||
| 	popw	%ax | ||||
| 
 | ||||
| 	/* determine the next possible destination address (presuming | ||||
| 		512 byte sectors!) */ | ||||
| 	shlw	$5, %ax		/* shift %ax five bits to the left */ | ||||
| 	addw	%ax, 10(%di)	/* add the corrected value to the destination | ||||
| 				   address for next time */ | ||||
| 
 | ||||
| 	/* save addressing regs */ | ||||
| 	pusha | ||||
| 	pushw	%ds | ||||
| 
 | ||||
| 	/* get the copy length */ | ||||
| 	shlw	$3, %ax | ||||
| 	movw	%ax, %cx | ||||
| 
 | ||||
| 	xorw	%di, %di	/* zero offset of destination addresses */ | ||||
| 	xorw	%si, %si	/* zero offset of source addresses */ | ||||
| 	movw	%bx, %ds	/* restore the source segment */ | ||||
| 
 | ||||
| 	cld		/* sets the copy direction to forward */ | ||||
| 
 | ||||
| 	/* perform copy */ | ||||
| 	rep		/* sets a repeat */ | ||||
| 	movsw		/* this runs the actual copy */ | ||||
| 
 | ||||
| 	/* restore addressing regs and print a dot with correct DS | ||||
| 	   (MSG modifies SI, which is saved, and unused AX and BX) */ | ||||
| 	popw	%ds | ||||
| 	MSG(notification_step) | ||||
| 	popa | ||||
| 
 | ||||
| 	/* check if finished with this dataset */ | ||||
| 	cmpw	$0, 8(%di) | ||||
| 	jne	LOCAL(setup_sectors) | ||||
| 
 | ||||
| 	/* update position to load from */ | ||||
| 	subw	$GRUB_BOOT_MACHINE_LIST_SIZE, %di | ||||
| 
 | ||||
| 	/* jump to bootloop */ | ||||
| 	jmp	LOCAL(bootloop) | ||||
| 
 | ||||
| /* END OF MAIN LOOP */ | ||||
| 
 | ||||
| LOCAL(bootit): | ||||
| 	/* print a newline */ | ||||
| 	MSG(notification_done) | ||||
| 	popw	%dx	/* this makes sure %dl is our "boot" drive */ | ||||
| 	ljmp	$0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
|  * BIOS Geometry translation error (past the end of the disk geometry!). | ||||
|  */ | ||||
| LOCAL(geometry_error): | ||||
| 	MSG(geometry_error_string) | ||||
| 	jmp	LOCAL(general_error) | ||||
| 
 | ||||
| /* | ||||
|  * Read error on the disk. | ||||
|  */ | ||||
| LOCAL(read_error): | ||||
| 	MSG(read_error_string) | ||||
| 
 | ||||
| LOCAL(general_error): | ||||
| 	MSG(general_error_string) | ||||
| 
 | ||||
| /* go here when you need to stop the machine hard after an error condition */ | ||||
| LOCAL(stop):	jmp	LOCAL(stop) | ||||
| 
 | ||||
| notification_string:	.asciz "loading" | ||||
| 
 | ||||
| notification_step:	.asciz "." | ||||
| notification_done:	.asciz "\r\n" | ||||
| 
 | ||||
| geometry_error_string:	.asciz "Geom" | ||||
| read_error_string:	.asciz "Read" | ||||
| general_error_string:	.asciz " Error" | ||||
| 
 | ||||
| /* | ||||
|  * message: write the string pointed to by %si | ||||
|  * | ||||
|  *   WARNING: trashes %si, %ax, and %bx | ||||
|  */ | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode | ||||
| 	 *	%ah = 0xe	%al = character | ||||
| 	 *	%bh = page	%bl = foreground color (graphics modes) | ||||
| 	 */ | ||||
| 1: | ||||
| 	movw	$0x0001, %bx | ||||
| 	movb	$0xe, %ah | ||||
| 	int	$0x10		/* display a byte */ | ||||
| 
 | ||||
| 	incw	%si | ||||
| LOCAL(message): | ||||
| 	movb	(%si), %al | ||||
| 	cmpb	$0, %al | ||||
| 	jne	1b	/* if not end of string, jmp to display */ | ||||
| 	ret | ||||
| 
 | ||||
| /* | ||||
|  *  This area is an empty space between the main body of code below which | ||||
|  *  grows up (fixed after compilation, but between releases it may change | ||||
|  *  in size easily), and the lists of sectors to read, which grows down | ||||
|  *  from a fixed top location. | ||||
|  */ | ||||
| 
 | ||||
| 	.word 0
 | ||||
| 	.word 0
 | ||||
| 
 | ||||
| 	. = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE | ||||
| 
 | ||||
|         /* fill the first data listing with the default */ | ||||
| blocklist_default_start: | ||||
| 	/* this is the sector start parameter, in logical sectors from | ||||
| 	   the start of the disk, sector 0 */ | ||||
| 	.long 2, 0 | ||||
| blocklist_default_len: | ||||
| 	/* this is the number of sectors to read.  grub-mkimage | ||||
| 	   will fill this up */ | ||||
| 	.word 0
 | ||||
| blocklist_default_seg: | ||||
| 	/* this is the segment of the starting address to load the data into */ | ||||
| 	.word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20) | ||||
| 
 | ||||
| firstlist:	/* this label has to be after the list data!!! */ | ||||
							
								
								
									
										290
									
								
								grub-core/boot/i386/pc/lnxboot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								grub-core/boot/i386/pc/lnxboot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,290 @@ | |||
| /* -*-Asm-*- */ | ||||
| /* | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| #include <config.h> | ||||
| #include <grub/symbol.h> | ||||
| #include <grub/boot.h> | ||||
| #include <grub/machine/boot.h> | ||||
| #include <grub/machine/kernel.h> | ||||
| #include <multiboot.h> | ||||
| 
 | ||||
|         .file   "lnxboot.S" | ||||
| 
 | ||||
| #define CODE_ADDR	0x6000 | ||||
| #define CODE_SECTORS	1 | ||||
| #define DATA_ADDR	((GRUB_BOOT_MACHINE_KERNEL_ADDR) + 0x200) | ||||
| 
 | ||||
| #define BLCK_LENG	0x4000 | ||||
| 
 | ||||
| 	.text | ||||
| 
 | ||||
|         .code16 | ||||
| 
 | ||||
|         .globl  start, _start | ||||
| 
 | ||||
| data_start: | ||||
| 	xorl	%ebp, %ebp | ||||
| 	jmp	LOCAL(linux_next) | ||||
| 
 | ||||
| 	. = data_start + 0x1F1 | ||||
| 
 | ||||
| setup_sects: | ||||
| 	.byte	CODE_SECTORS
 | ||||
| root_flags: | ||||
| 	.word	0
 | ||||
| syssize: | ||||
| 	.word	0
 | ||||
| swap_dev: | ||||
| 	.word	0
 | ||||
| ram_size: | ||||
| 	.word	0
 | ||||
| vid_mode: | ||||
| 	.word	0
 | ||||
| root_dev: | ||||
| 	.word	0
 | ||||
| boot_flag: | ||||
| 	.word	0xAA55
 | ||||
| 
 | ||||
| start: | ||||
| _start: | ||||
| 
 | ||||
| 	jmp LOCAL(linux_init) | ||||
| 
 | ||||
| 	.ascii	"HdrS"			/* Header signature.  */ | ||||
| 	.word	0x0203			/* Header version number.  */ | ||||
| 
 | ||||
| realmode_swtch: | ||||
| 	.word	0, 0			/* default_switch, SETUPSEG.  */ | ||||
| start_sys_seg: | ||||
| 	.word	0x1000			/* Obsolete.  */ | ||||
| version_ptr: | ||||
| 	.word	0			/* Version string ptr.  */ | ||||
| type_of_loader: | ||||
| 	.byte	0			/* Filled in by boot loader.  */ | ||||
| loadflags: | ||||
| 	.byte	1			/* Please load high.  */ | ||||
| setup_move_size: | ||||
| 	.word	0			/* Unused.  */ | ||||
| code32_start: | ||||
| 	.long	0x100000		/* 32-bit start address.  */ | ||||
| ramdisk_image: | ||||
| 	.long	0			/* Loaded ramdisk image address.  */ | ||||
| ramdisk_size: | ||||
| 	.long	0			/* Size of loaded ramdisk.  */ | ||||
| bootsect_kludge: | ||||
| 	.word	0, 0 | ||||
| heap_end_ptr: | ||||
| 	.word	0
 | ||||
| pad1: | ||||
| 	.word	0
 | ||||
| cmd_line_ptr: | ||||
| 	.long	0			/* Command line.  */ | ||||
| ramdisk_max: | ||||
| 	.long	0xffffffff		/* Highest allowed ramdisk address.  */ | ||||
| 
 | ||||
| gdt: | ||||
| 	.long	0, 0, 0, 0		/* Must be zero.  */ | ||||
| 	.word	0xffff			/* 64 K segment size.  */ | ||||
| gdt_src1: | ||||
| 	.byte	0, 0 ,0			/* Low 24 bits of source address.  */ | ||||
| 	.byte	0x93			/* Access rights.  */ | ||||
| 	.byte	0			/* Extended access rights.  */ | ||||
| gdt_src2: | ||||
| 	.byte	0			/* High 8 bits of source address.  */ | ||||
| 	.word	0xffff			/* 64 K segment size.  */ | ||||
| gdt_dst1: | ||||
| 	.byte	0, 0, 0			/* Low 24 bits of target address.  */ | ||||
| 	.byte	0x93			/* Access rights.  */ | ||||
| 	.byte	0			/* Extended access rights.  */ | ||||
| gdt_dst2: | ||||
| 	.byte	0			/* High 8 bits of source address.  */ | ||||
| 	.long	0, 0, 0, 0		/* More space for the BIOS.  */ | ||||
| 
 | ||||
| reg_edx: | ||||
| 	.byte	0x80, 0, 0xFF, 0xFF | ||||
| 
 | ||||
| data_leng: | ||||
| 	.long	0
 | ||||
| 
 | ||||
| LOCAL(linux_init): | ||||
| 	movw	%cs:(reg_edx - start), %dx | ||||
| 	movl	%cs:(code32_start - start), %ebp | ||||
| 
 | ||||
| LOCAL(linux_next): | ||||
| 
 | ||||
| 	call	LOCAL(normalize) | ||||
| 
 | ||||
| LOCAL(normalize): | ||||
| 	popw	%bx | ||||
| 	subw	$(LOCAL(normalize) - start), %bx | ||||
| 	shrw	$4, %bx | ||||
| 	movw	%cs, %ax | ||||
| 	addw	%bx, %ax | ||||
| 	pushw	%ax | ||||
| 	pushw	$(real_code - start) | ||||
| 	lret				/* Jump to real_code.  */ | ||||
| 
 | ||||
| real_code: | ||||
| 	subw	$0x20, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	(setup_sects - data_start), %cx | ||||
| 	shlw	$7, %cx | ||||
| 
 | ||||
| 	/* Setup stack.  */ | ||||
| 
 | ||||
| 	xorw	%si, %si | ||||
| 	movw	%si, %ss | ||||
| 	movw	$(CODE_ADDR), %sp | ||||
| 
 | ||||
| 	/* Move itself to 0:CODE_ADDR.  */ | ||||
| 
 | ||||
| 	cld | ||||
| 	movw	%cs, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	$(CODE_ADDR >> 4), %ax | ||||
| 	movw	%ax, %es | ||||
| 	movw	%si, %di | ||||
| 
 | ||||
| 	rep | ||||
| 	movsl | ||||
| 	ljmp	$(CODE_ADDR >> 4), $(real_code_2  - start) | ||||
| 
 | ||||
| real_code_2: | ||||
| 
 | ||||
| 	xchgl	%ebp, %esi | ||||
| 	orl	%esi, %esi | ||||
| 	jnz	1f | ||||
| 	movw	%ds, %si | ||||
| 	shll	$4, %esi | ||||
| 	addl	%ebp, %esi | ||||
| 1: | ||||
| 
 | ||||
| 	pushw	%es | ||||
| 	popw	%ds | ||||
| 
 | ||||
| 	movl	$0x200, %ecx | ||||
| 	addl	%ecx, %esi | ||||
| 	movl	$DATA_ADDR, %edi | ||||
| 
 | ||||
| 	call	LOCAL(move_memory) | ||||
| 
 | ||||
| 	/* Check for multiboot signature.  */ | ||||
| 	cmpl	$MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END) | ||||
| 	jz	1f | ||||
| 
 | ||||
| 	movl	(ramdisk_image - start), %esi | ||||
| 	movl	(ramdisk_size - start), %ecx | ||||
| 	movl	$(DATA_ADDR - 0x200), %edi | ||||
| 	jmp	2f | ||||
| 
 | ||||
| 1: | ||||
| 
 | ||||
| 	movl	%ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE), %ecx | ||||
| 	addl	$(GRUB_KERNEL_MACHINE_RAW_SIZE - 0x200), %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 | ||||
| 
 | ||||
| /* | ||||
|  * Parameters: | ||||
|  *   esi: source address | ||||
|  *   edi: target address | ||||
|  *   ecx: number of bytes | ||||
|  */ | ||||
| 
 | ||||
| LOCAL(move_memory): | ||||
| 	incl	%ecx | ||||
| 	andb	$0xFE, %cl | ||||
| 	pushw	%dx | ||||
| 1: | ||||
| 	pushl	%esi | ||||
| 	pushl	%edi | ||||
| 	pushl	%ecx | ||||
| 	cmpl	$BLCK_LENG, %ecx | ||||
| 	jbe	2f | ||||
| 	movl	$BLCK_LENG, %ecx | ||||
| 2: | ||||
| 	pushl	%ecx | ||||
| 
 | ||||
| 	movl	%esi, %eax | ||||
| 	movw	%si, (gdt_src1 - start) | ||||
| 	shrl	$16, %eax | ||||
| 	movb	%al, (gdt_src1 + 2 - start) | ||||
| 	movb	%ah, (gdt_src2 - start) | ||||
| 
 | ||||
| 	movl	%edi, %eax | ||||
| 	movw	%di, (gdt_dst1 - start) | ||||
| 	shrl	$16, %eax | ||||
| 	movb	%al, (gdt_dst1 + 2 - start) | ||||
| 	movb	%ah, (gdt_dst2 - start) | ||||
| 
 | ||||
| 	movw	$(gdt - start), %si | ||||
| 	movb	$0x87, %ah | ||||
| 	shrw	$1, %cx | ||||
| 
 | ||||
| 	int	$0x15 | ||||
| 
 | ||||
| 	popl	%eax | ||||
| 	popl	%ecx | ||||
| 	popl	%edi | ||||
| 	popl	%esi | ||||
| 
 | ||||
| 	jnc	2f | ||||
| 	movw	$(err_int15_msg - start), %si | ||||
| 	jmp	LOCAL(fail) | ||||
| 
 | ||||
| 2: | ||||
| 
 | ||||
| 	addl	%eax, %esi | ||||
| 	addl	%eax, %edi | ||||
| 	subl	%eax, %ecx | ||||
| 	jnz	1b | ||||
| 
 | ||||
| 
 | ||||
| 	popw	%dx | ||||
| 	ret | ||||
| 
 | ||||
| /* | ||||
|  * Parameters: | ||||
|  *   si: message | ||||
|  */ | ||||
| 
 | ||||
| LOCAL(fail): | ||||
| 	movb	$0x0e, %ah | ||||
| 	xorw	%bx, %bx | ||||
| 1: | ||||
| 	lodsb	(%si), %al | ||||
| 	int	$0x10 | ||||
| 	cmpb	$0, %al | ||||
| 	jne	1b | ||||
| 1:	jmp	1b | ||||
| 
 | ||||
| err_int15_msg: | ||||
| 	.ascii	"move memory fails\0" | ||||
| 
 | ||||
| 	. = _start + CODE_SECTORS * 512 | ||||
							
								
								
									
										42
									
								
								grub-core/boot/i386/pc/pxeboot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								grub-core/boot/i386/pc/pxeboot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| /* | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2000,2005,2007,2008,2009,2010   Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/machine/boot.h> | ||||
| 
 | ||||
| 	.file	"pxeboot.S" | ||||
| 	.text | ||||
| 
 | ||||
| 	/* Start with the prehistoric environment... */ | ||||
| 	.code16 | ||||
| 
 | ||||
| 	/* Let's go */ | ||||
| .globl start, _start;
 | ||||
| _start: | ||||
| start: | ||||
| 
 | ||||
| 	/* Use drive number 0x7F for PXE */ | ||||
|         movb	$GRUB_BOOT_MACHINE_PXE_DL, %dl | ||||
| 
 | ||||
| 	/* Jump to the real world */ | ||||
| 	ljmp	$0, $0x8200 | ||||
| 
 | ||||
| 	/* This region is a junk. Do you say that this is wasteful? | ||||
| 	   But I like that the memory layout of the body is consistent | ||||
| 	   among different kernels rather than scamping just for 1.5KB. */ | ||||
| 	. = _start + 0x8200 - 0x7C00 - 0x200 - 1 | ||||
| 	.byte	0
 | ||||
							
								
								
									
										67
									
								
								grub-core/boot/i386/qemu/boot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								grub-core/boot/i386/qemu/boot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,67 @@ | |||
| /* | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| #include <config.h> | ||||
| #include <grub/symbol.h> | ||||
| #include <grub/machine/memory.h> | ||||
| #include <grub/machine/boot.h> | ||||
| #include <grub/machine/kernel.h> | ||||
| 
 | ||||
| 	.text | ||||
| 	.code16 | ||||
| 	.globl _start
 | ||||
| _start: | ||||
| 	/* Disable interrupts.  */ | ||||
| 	cli | ||||
| 
 | ||||
| 	jmp	1f | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR | ||||
| VARIABLE(grub_core_entry_addr) | ||||
| 	.long	0
 | ||||
| 1: | ||||
| 
 | ||||
| 	/* Set up %ds, %ss, and %es.  */ | ||||
| 	xorw	%ax, %ax | ||||
| 	movw	%ax, %ds | ||||
| 	movw	%ax, %ss | ||||
| 	movw	%ax, %es | ||||
| 
 | ||||
| 	/* Set up the real mode stack.  */ | ||||
| 	movl	$GRUB_MEMORY_MACHINE_REAL_STACK, %esp | ||||
| 
 | ||||
| 	/* Transition to protected mode.  We use pushl to force generation | ||||
| 	   of a flat return address.  */ | ||||
| 	pushl	$1f | ||||
| 	DATA32	jmp real_to_prot | ||||
| 	.code32 | ||||
| 1: | ||||
| 	movl	grub_core_entry_addr, %edx | ||||
| 	jmp	*%edx | ||||
| 
 | ||||
| #include "../../../kern/i386/realmode.S" | ||||
| 
 | ||||
| 	/* Intel, in its infinite wisdom, decided to put the i8086 entry point | ||||
| 	   *right here* and this is why we need this kludge.  */ | ||||
| 
 | ||||
| 	. = GRUB_BOOT_MACHINE_SIZE - 16 | ||||
| 
 | ||||
|        .code16 | ||||
|         | ||||
| 	jmp	_start | ||||
| 	. = GRUB_BOOT_MACHINE_SIZE | ||||
							
								
								
									
										631
									
								
								grub-core/boot/mips/yeeloong/fwstart.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										631
									
								
								grub-core/boot/mips/yeeloong/fwstart.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,631 @@ | |||
| /* | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/mips/yeeloong/serial.h> | ||||
| #include <grub/mips/yeeloong/pci.h> | ||||
| #include <grub/mips/loongson.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/machine/serial.h> | ||||
| #include <grub/ns8250.h> | ||||
| #include <grub/cs5536.h> | ||||
| #include <grub/smbus.h> | ||||
| 
 | ||||
| 	.set noreorder
 | ||||
| 	.set noat
 | ||||
| 	.set nomacro
 | ||||
| 
 | ||||
| 	.global start,_start,__start | ||||
| start: | ||||
| _start: | ||||
| __start:	 | ||||
| 	bal serial_hw_init | ||||
| 	 nop | ||||
| 	/* Find CS5536 controller.  */ | ||||
| 	/* $t4 chooses device in priority encoding.  */ | ||||
| 	/* Resulting value is kept in GRUB_MACHINE_PCI_CONF_CTRL_REG. | ||||
| 	   This way we don't need to sacrifice a register for it.  */ | ||||
| 	/* We have only one bus (0). Function is 0.  */ | ||||
| 	lui $t0, %hi(GRUB_MACHINE_PCI_CONF_CTRL_REG_ADDR) | ||||
| 	lui $t1, %hi(GRUB_MACHINE_PCI_CONFSPACE) | ||||
| 	lui $t3, %hi(GRUB_CS5536_PCIID) | ||||
| 	addiu $t3, $t3, %lo(GRUB_CS5536_PCIID) | ||||
| 	ori $t4, $zero, 1 | ||||
| 	lui $a0, %hi(no_cs5536) | ||||
| 1: | ||||
| 	andi $t4, $t4, ((1 << GRUB_PCI_NUM_DEVICES) - 1) | ||||
| 	beql  $t4, $zero, fatal | ||||
| 	 addiu $a0, $a0, %lo(no_cs5536) | ||||
| 	sw   $t4, %lo(GRUB_MACHINE_PCI_CONF_CTRL_REG_ADDR) ($t0) | ||||
| 	lw   $t2, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_PCI_REG_PCI_ID) ($t1) | ||||
| 	bnel  $t2, $t3, 1b | ||||
| 	 sll $t4, $t4, 1 | ||||
| 
 | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(cs5536_found) | ||||
| 	bal printhex | ||||
| 	 move $a0, $t4 | ||||
| 
 | ||||
| 	/* Initialise SMBus controller.  */ | ||||
| 	/* Set GPIO LBAR.  */ | ||||
| 	lui $a0, %hi(GRUB_CS5536_MSR_GPIO_BAR) | ||||
| 	addiu $a0, $a0, %lo(GRUB_CS5536_MSR_GPIO_BAR) | ||||
| 	ori $a1, $zero, GRUB_CS5536_LBAR_GPIO | ||||
| 	/* Set mask to 0xf and enabled bit to 1.  */ | ||||
| 	bal wrmsr | ||||
| 	 ori $a2, $zero, ((GRUB_CS5536_LBAR_MASK_MASK \ | ||||
| 	                  | GRUB_CS5536_LBAR_ENABLE) >> 32) | ||||
| 
 | ||||
| 	/* Set SMBUS LBAR.  */ | ||||
| 	lui $a0, %hi(GRUB_CS5536_MSR_SMB_BAR) | ||||
| 	addiu $a0, $a0, %lo(GRUB_CS5536_MSR_SMB_BAR) | ||||
| 	ori $a1, $zero, GRUB_CS5536_LBAR_SMBUS | ||||
| 	/* Set mask to 0xf and enabled bit to 1.  */ | ||||
| 	bal wrmsr | ||||
| 	 ori $a2, $zero, ((GRUB_CS5536_LBAR_MASK_MASK \ | ||||
| 	                   | GRUB_CS5536_LBAR_ENABLE) >> 32) | ||||
| 
 | ||||
| 	lui $a0, %hi(smbus_enabled) | ||||
| 	bal message | ||||
| 	  addiu $a0, $a0, %lo(smbus_enabled) | ||||
| 
 | ||||
| 	/* Enable SMBus controller pins.  */ | ||||
| 	lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO) | ||||
| 	ori $t1, $zero, GRUB_GPIO_SMBUS_PINS | ||||
| 	sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_OUT_EN) ($t0) | ||||
| 	sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_OUT_AUX1) ($t0) | ||||
| 	sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_IN_EN) ($t0) | ||||
| 	sw  $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_GPIO + GRUB_GPIO_REG_IN_AUX1) ($t0) | ||||
| 
 | ||||
| 	lui $t0, %hi(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS) | ||||
| 
 | ||||
| 	/* Disable SMB.  */ | ||||
| 	sb $zero, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0) | ||||
| 
 | ||||
| 	/* Disable interrupts.  */ | ||||
| 	sb $zero, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1) ($t0) | ||||
| 
 | ||||
| 	/* Set as master.  */ | ||||
| 	sb $zero, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_ADDR) ($t0) | ||||
| 
 | ||||
| 	/* Launch SMBus controller at slowest speed possible.  */ | ||||
| 	ori $t1, $zero, 0xff | ||||
| 	sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL3) ($t0) | ||||
| 	sb $t1, %lo(GRUB_MACHINE_PCI_IO_BASE + GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL2) ($t0) | ||||
| 
 | ||||
| 	/* Yeeloong has only one memory slot.  */ | ||||
| 	/* Output first byte on serial for debugging.  */ | ||||
| 	ori $a1, $zero, GRUB_SMB_RAM_START_ADDR | ||||
| 	bal read_spd | ||||
| 	 move $a0, $zero | ||||
| 	bal printhex | ||||
| 	 move $a0, $v0 | ||||
| 
 | ||||
| 	bal read_spd | ||||
| 	 ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_TYPE_ADDR | ||||
| 	ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_TYPE_DDR2 | ||||
| 	lui $a0, %hi(unimplemented_memory_type) | ||||
| 	bne $t0, $v0, fatal | ||||
| 	 addiu $a0, $a0, %hi(unimplemented_memory_type) | ||||
| 
 | ||||
| 	/* And here is our goal: DDR2 controller initialisation.  */ | ||||
|         lui	$t0, %hi(GRUB_CPU_LOONGSON_CORECFG) | ||||
|         ld	$t1, %lo(GRUB_CPU_LOONGSON_CORECFG) ($t0) | ||||
| 	/* Use addiu for sign-extension.  */ | ||||
| 	addiu	$t2, $zero, ~(GRUB_CPU_LOONGSON_CORECFG_DISABLE_DDR2_SPACE|GRUB_CPU_LOONGSON_CORECFG_BUFFER_CPU) | ||||
| 	and	$t1, $t1, $t2 | ||||
| 	sd	$t1, %lo (GRUB_CPU_LOONGSON_CORECFG) ($t0) | ||||
| 
 | ||||
| 	b continue | ||||
| 
 | ||||
| 	. = start + GRUB_CPU_LOONGSON_FLASH_TLB_REFILL - GRUB_CPU_LOONGSON_FLASH_START | ||||
| tlb_refill:	 | ||||
| 	mfc0 $s1, GRUB_CPU_LOONGSON_COP0_EPC | ||||
| 	mfc0 $s2, GRUB_CPU_LOONGSON_COP0_BADVADDR | ||||
| 	move $s3, $ra | ||||
| 	lui $a0, %hi(epc) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(epc) | ||||
| 
 | ||||
| 	bal printhex | ||||
| 	 move $a0, $s1 | ||||
| 
 | ||||
| 	lui $a0, %hi(badvaddr) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(badvaddr) | ||||
| 
 | ||||
| 	bal printhex | ||||
| 	 move $a0, $s2 | ||||
| 
 | ||||
| 	lui $a0, %hi(return_msg) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(return_msg) | ||||
| 
 | ||||
| 	bal printhex | ||||
| 	 move $a0, $s3 | ||||
| 	 | ||||
| 	lui $a0, %hi(newline) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(newline) | ||||
| 
 | ||||
| 	lui $a0, %hi(unhandled_tlb_refill) | ||||
| 	b fatal | ||||
| 	 addiu $a0, $a0, %lo(unhandled_tlb_refill) | ||||
| 
 | ||||
| 	. = start + GRUB_CPU_LOONGSON_FLASH_CACHE_ERROR - GRUB_CPU_LOONGSON_FLASH_START | ||||
| cache_error: | ||||
| 	lui $a0, %hi(unhandled_cache_error) | ||||
| 	b fatal | ||||
| 	 addiu $a0, $a0, %lo(unhandled_cache_error) | ||||
| 
 | ||||
| 	. = start + GRUB_CPU_LOONGSON_FLASH_OTHER_EXCEPTION - GRUB_CPU_LOONGSON_FLASH_START | ||||
| other_exception: | ||||
| 	mfc0 $s0, GRUB_CPU_LOONGSON_COP0_CAUSE | ||||
| 	mfc0 $s1, GRUB_CPU_LOONGSON_COP0_EPC | ||||
| 	mfc0 $s2, GRUB_CPU_LOONGSON_COP0_BADVADDR | ||||
| 	lui $a0, %hi(cause) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(cause) | ||||
| 
 | ||||
| 	bal printhex | ||||
| 	 move $a0, $s0 | ||||
| 
 | ||||
| 	lui $a0, %hi(epc) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(epc) | ||||
| 
 | ||||
| 	bal printhex | ||||
| 	 move $a0, $s1 | ||||
| 
 | ||||
| 	lui $a0, %hi(badvaddr) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(badvaddr) | ||||
| 
 | ||||
| 	bal printhex | ||||
| 	 move $a0, $s2 | ||||
| 	 | ||||
| 	lui $a0, %hi(newline) | ||||
| 	bal message | ||||
| 	 addiu $a0, $a0, %lo(newline) | ||||
| 	 | ||||
| 	lui $a0, %hi(unhandled_exception) | ||||
| 	b fatal | ||||
| 	 addiu $a0, $a0, %lo(unhandled_exception) | ||||
| 
 | ||||
| 	/* Same as similarly named C function but in asm since | ||||
| 	   we need it early.  */ | ||||
| 	/* In: none. Out: none. Clobbered: $t0, $t1, $a0.  */ | ||||
| serial_hw_init: | ||||
| 	lui $t0, %hi (GRUB_MACHINE_SERIAL_PORT) | ||||
| 
 | ||||
| 	/* Turn off the interrupt.  */ | ||||
| 	sb $zero, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_IER)($t0) | ||||
| 
 | ||||
| 	/* Set DLAB.  */ | ||||
| 	ori $t1, $zero, UART_DLAB | ||||
| 	sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LCR)($t0) | ||||
| 
 | ||||
| 	/* Set the baud rate 115200.  */ | ||||
| 	ori $t1, $zero, GRUB_MACHINE_SERIAL_DIVISOR_115200 | ||||
| 	sb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_DLL)($t0)  | ||||
| 	sb $zero, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_DLH)($t0)  | ||||
| 
 | ||||
| 	/* Set the line status.  */ | ||||
| 	ori $t1, $zero, (UART_NO_PARITY | UART_8BITS_WORD | UART_1_STOP_BIT) | ||||
|         sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LCR)($t0) | ||||
| 
 | ||||
| 	/* Enable the FIFO.  */ | ||||
| 	ori $t1, $zero, UART_ENABLE_FIFO_TRIGGER1 | ||||
| 	sb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_FCR)($t0) | ||||
| 
 | ||||
| 	/* Turn on DTR and RTS.  */ | ||||
| 	ori $t1, $zero, UART_ENABLE_DTRRTS | ||||
| 	sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_MCR)($t0) | ||||
| 
 | ||||
| 	/* Let message return to original caller.  */ | ||||
| 	lui  $a0, %hi(notification_string) | ||||
| 	addiu $a0, $a0, %lo(notification_string) | ||||
| 
 | ||||
| 	/* Print message on serial console.  */ | ||||
| 	/* In: $a0 = asciiz message. Out: none. Clobbered: $t0, $t1, $a0.  */ | ||||
| message: | ||||
| 	lui $t0, %hi (GRUB_MACHINE_SERIAL_PORT) | ||||
| 1: | ||||
| 	lb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LSR)($t0) | ||||
| 	andi $t1, $t1, UART_EMPTY_TRANSMITTER | ||||
| 	beq $t1, $zero, 1b | ||||
| 	 nop | ||||
| 	lb  $t1, 0($a0) | ||||
| 	sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_TX)($t0) | ||||
| 	bne $t1, $zero, 1b | ||||
| 	 addiu $a0, $a0, 1 | ||||
| 	jr  $ra | ||||
| 	 nop | ||||
| 	 | ||||
| 	/* Print 32-bit hexadecimal on serial. | ||||
|            In:	$a0. Out: None. Clobbered: $a0, $t0, $t1, $t2 | ||||
| 	*/ | ||||
| printhex: | ||||
| 	lui $t0, %hi  (GRUB_MACHINE_SERIAL_PORT) | ||||
| 	ori $t2, $zero, 8 | ||||
| 1: | ||||
| 	lb $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_LSR)($t0) | ||||
| 	andi $t1, $t1, UART_EMPTY_TRANSMITTER | ||||
| 	beq $t1, $zero, 1b | ||||
| 	 nop | ||||
| 	srl  $t1, $a0, 28 | ||||
| 	addiu $t1, $t1, -10 | ||||
| 	blt  $t1, $zero, 2f | ||||
| 	 sll  $a0, $a0, 4 | ||||
| 	addiu $t1, $t1, 'A'-10-'0'  | ||||
| 2:	addiu $t1, $t1, '0'+10 | ||||
| 	sb  $t1, (%lo (GRUB_MACHINE_SERIAL_PORT) + UART_TX)($t0) | ||||
| 	addiu $t2, $t2, -1 | ||||
| 	bne $t2, $zero, 1b | ||||
| 	 nop | ||||
| 	jr  $ra | ||||
| 	 nop | ||||
| 
 | ||||
| fatal: | ||||
| 	bal message | ||||
| 	 nop | ||||
| self: | ||||
| 	b self | ||||
| 	 nop | ||||
| 	 | ||||
| 	/* Write CS5536 MSR. | ||||
|            In:   $a0 address, $a1 lower word, $a2 upper word. | ||||
|            Out:	 None | ||||
|            Clobbered:	 $t0 | ||||
| 	*/ | ||||
| wrmsr: | ||||
| 	lui $t0, %hi(GRUB_MACHINE_PCI_CONFSPACE) | ||||
| 	sw  $a0, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_ADDR) ($t0) | ||||
| 	sw  $a1, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_DATA0) ($t0) | ||||
| 	jr $ra | ||||
| 	 sw  $a2, (%lo(GRUB_MACHINE_PCI_CONFSPACE) + GRUB_CS5536_MSR_MAILBOX_DATA1) ($t0) | ||||
| 
 | ||||
| 	/* Wait for SMBus data or empty transmitter.  */ | ||||
| 	/* In: $a0 = exception handler. Out: none. Clobbered: $t0, $t1  */ | ||||
| smbus_wait: | ||||
| 1:	 | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_STATUS + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	lb $t0, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_STATUS + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	andi $t1, $t0, GRUB_CS5536_SMB_REG_STATUS_SDAST | ||||
| 	bne $t1, $zero, return | ||||
| 	 nop | ||||
| 	andi $t1, $t0, (GRUB_CS5536_SMB_REG_STATUS_BER | GRUB_CS5536_SMB_REG_STATUS_NACK) | ||||
| 	beq $t1, $zero, 1b | ||||
| 	 nop | ||||
| 	jr $a0 | ||||
| 	 nop | ||||
| return: | ||||
| 	jr $ra | ||||
| 	 nop | ||||
| 	 | ||||
| 	/* Read SPD byte. In: $a0 byte, $a1 device. Out: $v0 read byte (0x100 on failure). | ||||
|            Clobbered: $t0, $t1, $t2, $t3, $a0. */ | ||||
| read_spd: | ||||
| 	move $t2, $a0 | ||||
| 	move $t3, $ra | ||||
| 	lui $a0, %hi(read_spd_fail) | ||||
| 	addiu $a0, $a0, %hi(read_spd_fail) | ||||
| 
 | ||||
| 	/* Send START.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_START | ||||
| 	bal smbus_wait | ||||
| 	 sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	 | ||||
| 	/* Send device address.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	sll $t1, $a1, 1 | ||||
| 	bal smbus_wait | ||||
| 	 sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 
 | ||||
| 	/* Send ACK.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_ACK | ||||
| 	sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 
 | ||||
| 	/* Send byte address.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	bal smbus_wait | ||||
| 	 sb $t2, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 
 | ||||
| 	/* Send START.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_START | ||||
| 	bal smbus_wait | ||||
| 	 sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 
 | ||||
| 	/* Send device address.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	sll $t1, $a1, 1 | ||||
| 	ori $t1, $t1, 1 | ||||
| 	bal smbus_wait | ||||
| 	 sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 
 | ||||
| 	/* Send STOP.  */ | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	lb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	ori $t1, $t1, GRUB_CS5536_SMB_REG_CTRL1_STOP | ||||
| 	bal smbus_wait | ||||
| 	 sb $t1, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_CTRL1 + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 
 | ||||
| 	lui $t0, %hi(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) | ||||
| 	lb $v0, %lo(GRUB_CS5536_LBAR_SMBUS + GRUB_CS5536_SMB_REG_DATA + GRUB_MACHINE_PCI_IO_BASE) ($t0) | ||||
| 	jr $t3 | ||||
| 	 andi $v0, $v0, 0xff | ||||
| read_spd_fail: | ||||
| 	jr $t3 | ||||
| 	 ori $v0, $v0, 0x100 | ||||
| 
 | ||||
| notification_string:	.asciz "GRUB " | ||||
| no_cs5536:	.asciz "No CS5536 found.\n\r" | ||||
| cs5536_found:	.asciz "CS5536 at " | ||||
| sm_failed: .asciz "SM transaction failed.\n\r" | ||||
| unhandled_tlb_refill:	.asciz "Unhandled TLB refill.\n\r" | ||||
| unhandled_cache_error:	.asciz "Unhandled cache error.\n\r" | ||||
| unhandled_exception:	.asciz "Unhandled exception.\n\r" | ||||
| smbus_enabled:	.asciz "SMBus controller enabled.\n\r" | ||||
| unimplemented_memory_type:	.asciz "non-DDR2 memory isn't supported.\n\r" | ||||
| no_cas_latency:		.asciz "Couldn't determine CAS latency.\n\r" | ||||
| cause:	 .asciz "Cause: " | ||||
| epc:	.asciz "\n\rEPC: " | ||||
| badvaddr:	.asciz "\n\rBadVaddr: " | ||||
| newline:	.asciz "\n\r" | ||||
| return_msg:	  .asciz "\n\rReturn address: " | ||||
| caches_enabled:	.asciz "Caches enabled\n\r" | ||||
| 
 | ||||
| 	.p2align 3
 | ||||
| 
 | ||||
| regdump: | ||||
| 	.quad 0x0100010000000101 /* 0 */ | ||||
| 	.quad 0x0100010100000000 /* 2 */ | ||||
| 	.quad 0x0101000001000000 /* 3 */ | ||||
| 	.quad 0x0100020200010101 /* 4 */ | ||||
| 	.quad 0x0a04030603050203 /* 6 */ | ||||
| 	.quad 0x0f0e040000010a0b /* 7 */ | ||||
| 	.quad 0x0000010200000102 /* 8 */ | ||||
| 	.quad 0x0000060c00000000 /* 9 */ | ||||
| 	.quad 0x2323233f3f1f0200 /* a */ | ||||
| 	.quad 0x5f7f232323232323 /* b */ | ||||
| 	.quad 0x002a3c0615000000 /* c */ | ||||
| 	.quad 0x002a002a002a002a /* d */ | ||||
| 	.quad 0x002a002a002a002a /* e */ | ||||
| 	.quad 0x00b40020006d0004 /* f */ | ||||
| 	.quad 0x070007ff00000087 /* 10 */ | ||||
| 	.quad 0x000000000016101f /* 11 */ | ||||
| 	.quad 0x001c000000000000 /* 12 */ | ||||
| 	.quad 0x28e1000200c8006b /* 13 */ | ||||
| 	.quad 0x0000204200c8002f /* 14 */ | ||||
| 	.quad 0x0000000000030d40 /* 15 */ | ||||
| 	.quad 0 /* 16 */ | ||||
| 	.quad 0 /* 17 */ | ||||
| 	.quad 0 /* 18 */ | ||||
| 	.quad 0 /* 19 */ | ||||
| 	.quad 0 /* 1a */ | ||||
| 	.quad 0 /* 1b */ | ||||
| 	.quad 0 /* 1c */ | ||||
| 
 | ||||
| 	.p2align | ||||
| 
 | ||||
| write_dumpreg:	 | ||||
| 	ld $t2, 0($t6) | ||||
| 	sd $t2, 0($t4) | ||||
| 	addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP | ||||
| 	jr $ra | ||||
| 	 addiu $t6, $t6, GRUB_CPU_LOONGSON_DDR2_REG_SIZE | ||||
| 
 | ||||
| continue: | ||||
| 	lui $t4, %hi(GRUB_CPU_LOONGSON_DDR2_BASE) | ||||
| 	addiu $t4, $t4, %lo(GRUB_CPU_LOONGSON_DDR2_BASE) | ||||
| 	lui $t6, %hi(regdump) | ||||
| 
 | ||||
| 	/* 0 */ | ||||
| 	bal write_dumpreg | ||||
| 	 addiu $t6, $t6, %lo(regdump) | ||||
| 
 | ||||
| 	/* 1 */ | ||||
| 	ori $a1, $a1, GRUB_SMB_RAM_START_ADDR | ||||
| 	move $t8, $zero | ||||
| 	lui  $t5, 0x0001 | ||||
| 	bal read_spd | ||||
| 	 ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_BANKS_ADDR | ||||
| 	ori $t7, $zero, 8 | ||||
| 	bne $v0, $t7, 1f | ||||
| 	 ori $t5, $t5, 0x0001 | ||||
| 	ori $t8, $t8, GRUB_CPU_LOONGSON_DDR2_REG1_HI_8BANKS | ||||
| 1: | ||||
| 	dsll $t8, $t8, 32 | ||||
| 	or $t5, $t5, $t8 | ||||
| 	sd  $t5, 0 ($t4) | ||||
| 	addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP | ||||
| 
 | ||||
| 	/* 2 */ | ||||
| 	bal write_dumpreg | ||||
| 	 nop | ||||
| 
 | ||||
| 	/* 3 */ | ||||
| 	bal write_dumpreg | ||||
| 	 nop | ||||
| 
 | ||||
| 	/* 4 */ | ||||
| 	bal write_dumpreg | ||||
| 	 nop | ||||
| 
 | ||||
| 	/* 5 */ | ||||
| 	/* FIXME: figure termination resistance.  */ | ||||
| 	ori $t5, $zero, 0x2 | ||||
| 	bal read_spd | ||||
| 	 ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_ROWS_ADDR | ||||
| 	/* $v0 = 15 - $v0.  */ | ||||
| 	xori $v0, $v0, 0xf | ||||
| 	andi $v0, $v0, 0x7 | ||||
| 	sll $v0, $v0, 8 | ||||
| 	or $t5, $t5, $v0 | ||||
| 
 | ||||
| 	/* Find the fastest supported CAS latency.  */ | ||||
| 	bal read_spd | ||||
| 	 ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_ADDR | ||||
| 	ori $t0, $zero, GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE | ||||
| 	ori $t1, $zero, (1 << GRUB_SMBUS_SPD_MEMORY_CAS_LATENCY_MIN_VALUE) | ||||
| 2:	 | ||||
| 	and $t2, $t1, $v0 | ||||
| 	bne $t2, $zero, 1f | ||||
| 	 ori $t3, $zero, 8 | ||||
| 	lui $a0, %hi(no_cas_latency) | ||||
| 	beq $t0, $t3, fatal | ||||
| 	 addiu $a0, $a0, %lo(no_cas_latency) | ||||
| 	addiu $t0, $t0, 1 | ||||
| 	b 2b | ||||
| 	 sll $t1, $t1, 1 | ||||
| 1: | ||||
| 	sll $t0, $t0, 16 | ||||
| 	or $t5, $t5, $t0 | ||||
| 	 | ||||
| 	bal read_spd | ||||
| 	 ori $a0, $zero, GRUB_SMBUS_SPD_MEMORY_NUM_COLUMNS_ADDR | ||||
| 	/* $v0 = 15 - ($v0 + 1) = 14 - $v0.  */ | ||||
| 	addiu $v0, $v0, 1 | ||||
| 	xori $v0, $v0, 0xf | ||||
| 	andi $v0, $v0, 0x7 | ||||
| 	sll $v0, 24 | ||||
| 	or $t5, $t5, $v0 | ||||
| 	sd  $t5, 0 ($t4) | ||||
| 
 | ||||
| 	addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP | ||||
| 	 | ||||
| 	ori $t7, $zero, 0x16 | ||||
| 
 | ||||
| 1:	 | ||||
| 	ld $t2, 0($t6) | ||||
| 	sd $t2, 0($t4) | ||||
| 	addiu $t4, $t4, GRUB_CPU_LOONGSON_DDR2_REG_STEP | ||||
| 	addiu $t7, $t7, -1 | ||||
| 	bne $t7, $zero, 1b | ||||
| 	 addiu $t6, $t6, GRUB_CPU_LOONGSON_DDR2_REG_SIZE | ||||
| 	 | ||||
| 	lui $t4, %hi(GRUB_CPU_LOONGSON_DDR2_BASE) | ||||
| 	ld  $t5, (%lo(GRUB_CPU_LOONGSON_DDR2_BASE) + 0x30) ($t4) | ||||
| 	ori $t0, $zero, 1 | ||||
| 	dsll $t0, $t0, 40 | ||||
| 	or $t5, $t5, $t0 | ||||
| 	sd  $t5, (%lo(GRUB_CPU_LOONGSON_DDR2_BASE) + 0x30) ($t4) | ||||
| 
 | ||||
| 	/* Desactivate DDR2 registers.  */ | ||||
|         lui	$t0, %hi (GRUB_CPU_LOONGSON_CORECFG) | ||||
|         ld	$t1, %lo (GRUB_CPU_LOONGSON_CORECFG) ($t0) | ||||
| 	ori	$t1, $t1, GRUB_CPU_LOONGSON_CORECFG_DISABLE_DDR2_SPACE | ||||
|         sd	$t1, %lo (GRUB_CPU_LOONGSON_CORECFG) ($t0) | ||||
| 
 | ||||
| 	/* Enable cache.  */ | ||||
| 	mfc0	$t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG | ||||
| 	addiu 	$t1, $zero, ~GRUB_CPU_LOONGSON_CACHE_TYPE_MASK | ||||
| 	and     $t0, $t1, $t1 | ||||
| 	/* Set line size to 32 bytes and disabled cache.  */ | ||||
| 	ori   	$t0, $t0, (GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG_ILINESIZE \ | ||||
| 	                   | GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG_DLINESIZE \ | ||||
| 	                   | GRUB_CPU_LOONGSON_CACHE_ACCELERATED) | ||||
| 	mtc0	$t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG | ||||
| 
 | ||||
| 	/* Invalidate all I-cache entries.  */ | ||||
| 	srl $t1, $t0, GRUB_CPU_LOONGSON_COP0_CACHE_ISIZE_SHIFT | ||||
| 	andi $t1, $t1, GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_MASK | ||||
| 	ori $t2, $zero, (1 << (GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_OFFSET \ | ||||
| 	                       - GRUB_CPU_LOONGSON_CACHE_LINE_SIZE_LOG_BIG \ | ||||
| 	                       - GRUB_CPU_LOONGSON_I_CACHE_LOG_WAYS)) | ||||
| 	sll $t1, $t2, $t1 | ||||
| 	lui $t2, 0x8000 | ||||
| 
 | ||||
| 1:	 | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_I_INDEX_INVALIDATE, 0($t2) | ||||
| 	addiu $t1, $t1, -1 | ||||
| 	bne $t1, $zero, 1b | ||||
| 	 addiu $t2, $t2, (1 << GRUB_CPU_LOONGSON_COP0_I_INDEX_BIT_OFFSET) | ||||
| 
 | ||||
| 	/* Invalidate all D-cache entries.  */ | ||||
| 	srl $t1, $t0, GRUB_CPU_LOONGSON_COP0_CACHE_DSIZE_SHIFT | ||||
| 	andi $t1, $t1, GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_MASK | ||||
| 	ori $t2, $zero, (1 << (GRUB_CPU_LOONGSON_COP0_CACHE_SIZE_OFFSET \ | ||||
| 	                       - GRUB_CPU_LOONGSON_CACHE_LINE_SIZE_LOG_BIG \ | ||||
| 	                       - GRUB_CPU_LOONGSON_D_CACHE_LOG_WAYS)) | ||||
| 	sll $t1, $t2, $t1 | ||||
| 	lui $t2, 0x8000 | ||||
| 	mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGLO | ||||
| 	mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGHI | ||||
| 1: | ||||
| 	/* All four ways.  */ | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 0($t2) | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 1($t2) | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 2($t2) | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_D_INDEX_TAG_STORE, 3($t2) | ||||
| 	addiu $t1, $t1, -1 | ||||
| 	bne $t1, $zero, 1b | ||||
| 	 addiu $t2, $t2, (1 << GRUB_CPU_LOONGSON_COP0_D_INDEX_BIT_OFFSET) | ||||
| 
 | ||||
| 	/* Invalidate all S-cache entries.  */ | ||||
| 	ori $t1, $zero, (1 << (GRUB_CPU_LOONGSON_SECONDARY_CACHE_LOG_SIZE \ | ||||
| 	                       - GRUB_CPU_LOONGSON_CACHE_LINE_SIZE_LOG_BIG \ | ||||
| 	                       - GRUB_CPU_LOONGSON_S_CACHE_LOG_WAYS)) | ||||
| 	lui $t2, 0x8000 | ||||
| 	mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGLO | ||||
| 	mtc0 $zero, GRUB_CPU_LOONGSON_COP0_CACHE_TAGHI | ||||
| 1: | ||||
| 	/* All four ways.  */ | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 0($t2) | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 1($t2) | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 2($t2) | ||||
| 	cache GRUB_CPU_LOONGSON_COP0_S_INDEX_TAG_STORE, 3($t2) | ||||
| 	addiu $t1, $t1, -1 | ||||
| 	bne $t1, $zero, 1b | ||||
| 	 addiu $t2, $t2, (1 << GRUB_CPU_LOONGSON_COP0_D_INDEX_BIT_OFFSET) | ||||
| 	 | ||||
| 	/* Finally enable cache.  */ | ||||
| 	mfc0	$t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG | ||||
| 	addiu 	$t1, $zero, ~GRUB_CPU_LOONGSON_CACHE_TYPE_MASK | ||||
| 	and     $t0, $t1, $t1 | ||||
| 	ori   	$t0, $t0, GRUB_CPU_LOONGSON_CACHE_CACHED | ||||
| 	mtc0	$t0, GRUB_CPU_LOONGSON_COP0_CACHE_CONFIG | ||||
| 
 | ||||
| 	lui $a0, %hi(caches_enabled) | ||||
| 	bal message | ||||
| 	  addiu $a0, $a0, %lo(caches_enabled) | ||||
| 
 | ||||
| 	/* Set ROM delay cycles to 1.  */ | ||||
| 	lui $t0, %hi(GRUB_CPU_LOONGSON_LIOCFG) | ||||
| 	lw  $t1, %lo(GRUB_CPU_LOONGSON_LIOCFG) ($t0) | ||||
| 	addiu $t2, $zero, ~(GRUB_CPU_LOONGSON_ROM_DELAY_MASK \ | ||||
| 	                    << GRUB_CPU_LOONGSON_ROM_DELAY_OFFSET) | ||||
| 	and $t1, $t1, $t2 | ||||
| 	ori $t1, $t1, (1 << GRUB_CPU_LOONGSON_ROM_DELAY_OFFSET) | ||||
| 	sw  $t1, %lo(GRUB_CPU_LOONGSON_LIOCFG) ($t0) | ||||
| 	 | ||||
| 	addiu $a0, $zero, -1 | ||||
| 	addiu $a1, $zero, -1 | ||||
| 
 | ||||
| 	/* Take advantage of cache.  */ | ||||
| 	lui $t0, %hi(cached_continue - 0x20000000) | ||||
| 	addiu $t0, $t0, %lo(cached_continue - 0x20000000) | ||||
| 	jr $t0 | ||||
| 	 addiu $a2, $zero, -1 | ||||
| 
 | ||||
| cached_continue: | ||||
							
								
								
									
										209
									
								
								grub-core/boot/sparc64/ieee1275/boot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								grub-core/boot/sparc64/ieee1275/boot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,209 @@ | |||
| /* -*-Asm-*- */ | ||||
| /* | ||||
|  *  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/boot.h> | ||||
| #include <grub/machine/boot.h> | ||||
| 
 | ||||
| 	.text | ||||
| 	.align	4
 | ||||
| 	.globl	_start
 | ||||
| _start: | ||||
| 	/* OF CIF entry point arrives in %o4 */ | ||||
| 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. | ||||
| 	 * | ||||
| 	 * The boot_path will be the OF device path of the partition where the | ||||
| 	 * rest of the GRUB kernel image resides.  kernel_sector will be set to | ||||
| 	 * the location of the first block of the GRUB kernel, and | ||||
| 	 * kernel_address is the location where we should load that first block. | ||||
| 	 * | ||||
| 	 * 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). | ||||
| 	 */ | ||||
| boot_path: | ||||
| 	. = _start + GRUB_BOOT_MACHINE_KERNEL_BYTE | ||||
| boot_path_end: | ||||
| kernel_byte:		.xword (2 << 9) | ||||
| kernel_address:		.word  GRUB_BOOT_MACHINE_KERNEL_ADDR | ||||
| 
 | ||||
| prom_finddev_name:	.asciz "finddevice" | ||||
| prom_chosen_path:	.asciz "/chosen" | ||||
| prom_getprop_name:	.asciz "getprop" | ||||
| prom_stdout_name:	.asciz "stdout" | ||||
| prom_write_name:	.asciz "write" | ||||
| prom_bootpath_name:	.asciz "bootpath" | ||||
| prom_open_name:		.asciz "open" | ||||
| prom_seek_name:		.asciz "seek" | ||||
| prom_read_name:		.asciz "read" | ||||
| prom_exit_name:		.asciz "exit" | ||||
| grub_name:		.asciz "GRUB " | ||||
| #define GRUB_NAME_LEN	5 | ||||
| 
 | ||||
| 	.align	4
 | ||||
| 
 | ||||
| prom_open_error: | ||||
| 	GET_ABS(prom_open_name, %o2) | ||||
| 	call	console_write | ||||
| 	 mov	4, %o3 | ||||
| 	/* fallthru */ | ||||
| 
 | ||||
| prom_error: | ||||
| 	GET_ABS(prom_exit_name, %o0) | ||||
| 	/* fallthru */ | ||||
| 
 | ||||
| 	/* %o0: OF call name | ||||
| 	 * %o1: input arg 1 | ||||
| 	 */ | ||||
| prom_call_1_1_o2: | ||||
| 	clr	%o2 | ||||
| 	ba	prom_call_x_1 | ||||
| 	 mov	1, %g1 | ||||
| 
 | ||||
| prom_call_getprop: | ||||
| 	mov	4, %g1 | ||||
| 	stx	%g1, [%l1 + 256] | ||||
| 	mov	CHOSEN_NODE_REG, %o1 | ||||
| 	ba	prom_call_x_1 | ||||
| 	 GET_ABS(prom_getprop_name, %o0) | ||||
| 
 | ||||
| prom_call_3_1_o1: | ||||
| 	ba prom_call_3_1 | ||||
| 	 mov	BOOTDEV_REG, %o1 | ||||
| 
 | ||||
| 	 | ||||
| 	/* %o2: message string | ||||
| 	 * %o3: message length | ||||
| 	 */ | ||||
| console_write: | ||||
| 	GET_ABS(prom_write_name, %o0) | ||||
| 	mov	STDOUT_NODE_REG, %o1 | ||||
| 	/* fallthru */ | ||||
| 
 | ||||
| 	/* %o0: OF call name | ||||
| 	 * %o1: input arg 1 | ||||
| 	 * %o2: input arg 2 | ||||
| 	 * %o3: input arg 3 | ||||
| 	 */ | ||||
| prom_call_3_1:	 | ||||
| 	mov	3, %g1 | ||||
| prom_call_x_1: | ||||
| 	mov	1, %o5 | ||||
| 	/* fallthru */ | ||||
| 
 | ||||
| 	/* %o0: OF call name | ||||
| 	 * %g1: num inputs | ||||
| 	 * %o5: num outputs | ||||
| 	 * %o1-%o4: inputs | ||||
| 	 */ | ||||
| prom_call: | ||||
| 	stx	%o0, [%l1 + 0x00] | ||||
| 	stx	%g1, [%l1 + 0x08] | ||||
| 	stx	%o5, [%l1 + 0x10] | ||||
| 	stx	%o1, [%l1 + 0x18] | ||||
| 	stx	%o2, [%l1 + 0x20] | ||||
| 	stx	%o3, [%l1 + 0x28] | ||||
| 	stx	%o4, [%l1 + 0x30] | ||||
| 	jmpl	CIF_REG, %g0 | ||||
| 	 mov	%l1, %o0 | ||||
| 
 | ||||
| boot_continue: | ||||
| 	mov	%o7, PIC_REG		/* PIC base */ | ||||
| 	sethi	%hi(SCRATCH_PAD_BOOT), %l1	/* OF argument slots */ | ||||
| 
 | ||||
| 	/* Find the /chosen node so we can fetch the stdout handle, | ||||
| 	 * and thus perform console output. | ||||
| 	 * | ||||
| 	 * chosen_node = prom_finddevice("/chosen") | ||||
| 	 */ | ||||
| 	GET_ABS(prom_finddev_name, %o0) | ||||
| 	call	prom_call_1_1_o2 | ||||
| 	 GET_ABS(prom_chosen_path, %o1) | ||||
| 
 | ||||
| 	ldx	[%l1 + 0x20], CHOSEN_NODE_REG | ||||
| 	brz	CHOSEN_NODE_REG, prom_error | ||||
| 
 | ||||
| 	/* getprop(chosen_node, "stdout", &buffer, buffer_size) */ | ||||
| 	 GET_ABS(prom_stdout_name, %o2) | ||||
| 	add	%l1, 256, %o3 | ||||
| 	call	prom_call_getprop | ||||
| 	 mov	1024, %o4 | ||||
| 
 | ||||
| 	lduw	[%l1 + 256], STDOUT_NODE_REG | ||||
| 	brz,pn	STDOUT_NODE_REG, prom_error | ||||
| 
 | ||||
| 	/* write(stdout_node, "GRUB ", strlen("GRUB ")) */ | ||||
| 	 GET_ABS(grub_name, %o2) | ||||
| 	call	console_write | ||||
| 	 mov	GRUB_NAME_LEN, %o3 | ||||
| 
 | ||||
| 	GET_ABS(boot_path, %o3) | ||||
| 	ldub	[%o3], %o1 | ||||
| 	brnz,pn	%o1, bootpath_known | ||||
| 
 | ||||
| 	/* getprop(chosen_node, "bootpath", &buffer, buffer_size) */ | ||||
| 	 GET_ABS(prom_bootpath_name, %o2) | ||||
| 	call	prom_call_getprop | ||||
| 	 mov	(boot_path_end - boot_path), %o4 | ||||
| 
 | ||||
| bootpath_known:	 | ||||
| 
 | ||||
| 	/* Open up the boot_path, and use that handle to read the | ||||
| 	 * first block of the GRUB kernel image. | ||||
| 	 * | ||||
| 	 * bootdev_handle = open(boot_path) | ||||
| 	 */ | ||||
| 	GET_ABS(prom_open_name, %o0) | ||||
| 	call	prom_call_1_1_o2 | ||||
| 	 GET_ABS(boot_path, %o1) | ||||
| 
 | ||||
| 	ldx	[%l1 + 0x20], BOOTDEV_REG | ||||
| 	brz,pn	BOOTDEV_REG, prom_open_error | ||||
| 
 | ||||
| 	/* Since we have 64-bit cells, the high cell of the seek offset | ||||
| 	 * is zero and the low cell is the entire value. | ||||
| 	 * | ||||
| 	 * seek(bootdev, 0, *kernel_byte) | ||||
| 	 */ | ||||
| 	 GET_ABS(prom_seek_name, %o0) | ||||
| 	clr	%o2 | ||||
| 	call	prom_call_3_1_o1 | ||||
| 	 LDX_ABS(kernel_byte, 0x00, %o3) | ||||
| 
 | ||||
| 	/* read(bootdev, *kernel_address, 512) */ | ||||
| 	GET_ABS(prom_read_name, %o0) | ||||
| 	LDUW_ABS(kernel_address, 0x00, %o2) | ||||
| 	call	prom_call_3_1_o1 | ||||
| 	 mov	512, %o3 | ||||
| 
 | ||||
| 	LDUW_ABS(kernel_address, 0x00, %o2) | ||||
| 	jmpl	%o2, %o7 | ||||
| 	 nop | ||||
| 
 | ||||
| 	. = _start + GRUB_BOOT_MACHINE_CODE_END | ||||
| 
 | ||||
| /* the last 4 bytes in the sector 0 contain the signature */ | ||||
| 	.word	GRUB_BOOT_MACHINE_SIGNATURE
 | ||||
							
								
								
									
										146
									
								
								grub-core/boot/sparc64/ieee1275/diskboot.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								grub-core/boot/sparc64/ieee1275/diskboot.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,146 @@ | |||
| /* -*-Asm-*- */ | ||||
| /* | ||||
|  *  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/boot.h> | ||||
| #include <grub/machine/boot.h> | ||||
| #include <grub/offsets.h> | ||||
| 
 | ||||
| 	.text | ||||
| 	.align	4
 | ||||
| 	.globl	_start
 | ||||
| _start: | ||||
| 	/* First stage boot block jumps to us here.  */ | ||||
| pic_base: | ||||
| 	call	after_info_block | ||||
| 	 mov	%o7, PIC_REG | ||||
| 
 | ||||
| prom_write_name:		.asciz "write" | ||||
| prom_seek_name:			.asciz "seek" | ||||
| prom_read_name:			.asciz "read" | ||||
| prom_close_name:		.asciz "close" | ||||
| 
 | ||||
| notification_string:		.asciz "Loading kernel" | ||||
| #define NOTIFICATION_STRING_LEN	14 | ||||
| 
 | ||||
| notification_step:		.asciz "." | ||||
| #define NOTIFICATION_STEP_LEN	1 | ||||
| 
 | ||||
| notification_done:		.asciz "\r\n" | ||||
| #define NOTIFICATION_DONE_LEN	2 | ||||
| 
 | ||||
| 	.align	4
 | ||||
| 
 | ||||
| 	/* %o2: message string | ||||
| 	 * %o3: message length | ||||
| 	 */ | ||||
| console_write: | ||||
| 	GET_ABS(prom_write_name, %o0) | ||||
| 	mov	STDOUT_NODE_REG, %o1 | ||||
| 	/* fallthru */ | ||||
| 
 | ||||
| 	/* %o0: OF call name | ||||
| 	 * %o1: input arg 1 | ||||
| 	 * %o2: input arg 2 | ||||
| 	 * %o3: input arg 3 | ||||
| 	 */ | ||||
| prom_call_3_1: | ||||
| 	mov	3, %g1 | ||||
| 	mov	1, %o5 | ||||
| 	/* fallthru */ | ||||
| 
 | ||||
| 	/* %o0: OF call name | ||||
| 	 * %g1: num inputs | ||||
| 	 * %o5: num outputs | ||||
| 	 * %o1-%o4: inputs | ||||
| 	 */ | ||||
| prom_call: | ||||
| 	stx	%o0, [%l1 + 0x00] | ||||
| 	stx	%g1, [%l1 + 0x08] | ||||
| 	stx	%o5, [%l1 + 0x10] | ||||
| 	stx	%o1, [%l1 + 0x18] | ||||
| 	stx	%o2, [%l1 + 0x20] | ||||
| 	stx	%o3, [%l1 + 0x28] | ||||
| 	stx	%o4, [%l1 + 0x30] | ||||
| 	jmpl	CIF_REG, %g0 | ||||
| 	 mov	%l1, %o0 | ||||
| 
 | ||||
| 
 | ||||
| after_info_block: | ||||
| 	sethi	%hi(SCRATCH_PAD_DISKBOOT), %l1	/* OF argument slots */ | ||||
| 
 | ||||
| 	GET_ABS(notification_string, %o2) | ||||
| 	call	console_write | ||||
| 	 mov	NOTIFICATION_STRING_LEN, %o3 | ||||
| 
 | ||||
| 	GET_ABS(firstlist - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE, %l2) | ||||
| 	set	GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS, %l3 | ||||
| bootloop: | ||||
| 	lduw	[%l2 + 0x08], %o0 | ||||
| 	brz	%o0, bootit | ||||
| 	 lduw	[%l2 + 0x00], %o3 | ||||
| 	sllx	%o3, 32, %o3 | ||||
| 	lduw	[%l2 + 0x04], %o4 | ||||
| 	or	%o3, %o4, %o3 | ||||
| 	GET_ABS(prom_seek_name, %o0) | ||||
| 	mov	BOOTDEV_REG, %o1 | ||||
| 	clr	%o2 | ||||
| 	call	prom_call_3_1 | ||||
| 	 sllx	%o3, 9, %o3 | ||||
| 
 | ||||
| 	GET_ABS(prom_read_name, %o0) | ||||
| 	mov	BOOTDEV_REG, %o1 | ||||
| 	lduw	[%l2 + 0x08], %o3 | ||||
| 	sllx	%o3, 9, %o3 | ||||
| 	mov	%l3, %o2 | ||||
| 	call	prom_call_3_1 | ||||
| 	 add	%l3, %o3, %l3 | ||||
| 
 | ||||
| 	GET_ABS(notification_step, %o2) | ||||
| 	call	console_write | ||||
| 	 mov	NOTIFICATION_STEP_LEN, %o3 | ||||
| 
 | ||||
| 	ba	bootloop | ||||
| 	 sub	%l2, GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE, %l2 | ||||
| 
 | ||||
| bootit: | ||||
| 	GET_ABS(prom_close_name, %o0) | ||||
| 	mov	1, %g1 | ||||
| 	mov	0, %o5 | ||||
| 	call	prom_call | ||||
| 	 mov	BOOTDEV_REG, %o1 | ||||
| 
 | ||||
| 	GET_ABS(notification_done, %o2) | ||||
| 	call	console_write | ||||
| 	 mov	NOTIFICATION_DONE_LEN, %o3 | ||||
| 	sethi	%hi(GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS), %o2 | ||||
| 	jmpl	%o2 + %lo(GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS), %o7 | ||||
| 	 mov	CIF_REG, %o4 | ||||
| 1:	ba,a	1b | ||||
| 
 | ||||
| lastlist: | ||||
| 	.word	0
 | ||||
| 	.word	0
 | ||||
| 
 | ||||
| 	. = _start + (0x200 - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE) | ||||
| blocklist_default_start: | ||||
| 	.word	0
 | ||||
| 	.word	2
 | ||||
| blocklist_default_len: | ||||
| 	.word	0
 | ||||
| firstlist: | ||||
							
								
								
									
										90
									
								
								grub-core/bus/bonito.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								grub-core/bus/bonito.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| /* bonito.c - PCI bonito interface.  */ | ||||
| /*
 | ||||
|  *  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/pci.h> | ||||
| #include <grub/misc.h> | ||||
| 
 | ||||
| static grub_uint32_t base_win[GRUB_MACHINE_PCI_NUM_WIN]; | ||||
| static const grub_size_t sizes_win[GRUB_MACHINE_PCI_NUM_WIN] =  | ||||
|   {GRUB_MACHINE_PCI_WIN1_SIZE, GRUB_MACHINE_PCI_WIN_SIZE,  | ||||
|    GRUB_MACHINE_PCI_WIN_SIZE}; | ||||
| /* Usage counters.  */ | ||||
| static int usage_win[GRUB_MACHINE_PCI_NUM_WIN]; | ||||
| static grub_addr_t addr_win[GRUB_MACHINE_PCI_NUM_WIN] =  | ||||
|   {GRUB_MACHINE_PCI_WIN1_ADDR, GRUB_MACHINE_PCI_WIN2_ADDR, | ||||
|    GRUB_MACHINE_PCI_WIN3_ADDR}; | ||||
| 
 | ||||
| static inline void | ||||
| write_bases (void) | ||||
| { | ||||
|   int i; | ||||
|   grub_uint32_t reg = 0; | ||||
|   for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++)  | ||||
|     reg |= (((base_win[i] >> GRUB_MACHINE_PCI_WIN_SHIFT)  | ||||
| 	     & GRUB_MACHINE_PCI_WIN_MASK)  | ||||
| 	    >> (i * GRUB_MACHINE_PCI_WIN_MASK_SIZE)); | ||||
|   GRUB_MACHINE_PCI_IO_CTRL_REG = reg; | ||||
| } | ||||
| 
 | ||||
| volatile void * | ||||
| grub_pci_device_map_range (grub_pci_device_t dev __attribute__ ((unused)), | ||||
| 			   grub_addr_t base, grub_size_t size) | ||||
| { | ||||
|   int i; | ||||
|   grub_addr_t newbase; | ||||
| 
 | ||||
|   /* First try already used registers. */ | ||||
|   for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) | ||||
|     if (usage_win[i] && base_win[i] <= base  | ||||
| 	&& base_win[i] + sizes_win[i] > base + size) | ||||
|       { | ||||
| 	usage_win[i]++; | ||||
| 	return (void *)  | ||||
| 	  (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK)); | ||||
|       } | ||||
|   /* Map new register.  */ | ||||
|   newbase = base & ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK; | ||||
|   for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) | ||||
|     if (!usage_win[i] && newbase <= base  | ||||
| 	&& newbase + sizes_win[i] > base + size) | ||||
|       { | ||||
| 	usage_win[i]++; | ||||
| 	base_win[i] = newbase; | ||||
| 	write_bases (); | ||||
| 	return (void *)  | ||||
| 	  (addr_win[i] | (base & GRUB_MACHINE_PCI_WIN_OFFSET_MASK)); | ||||
|       } | ||||
|   grub_fatal ("Out of PCI windows."); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_pci_device_unmap_range (grub_pci_device_t dev __attribute__ ((unused)), | ||||
| 			     volatile void *mem __attribute__ ((unused)), | ||||
| 			     grub_size_t size __attribute__ ((unused))) | ||||
| { | ||||
|   int i; | ||||
|   for (i = 0; i < GRUB_MACHINE_PCI_NUM_WIN; i++) | ||||
|     if (usage_win[i] && addr_win[i]  | ||||
| 	== (((grub_addr_t) mem) & ~GRUB_MACHINE_PCI_WIN_OFFSET_MASK)) | ||||
|       { | ||||
| 	usage_win[i]--; | ||||
| 	return; | ||||
|       } | ||||
|   grub_fatal ("Tried to unmap not mapped region"); | ||||
| } | ||||
							
								
								
									
										380
									
								
								grub-core/bus/cs5536.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								grub-core/bus/cs5536.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,380 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/cs5536.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/time.h> | ||||
| #include <grub/ata.h> | ||||
| 
 | ||||
| int | ||||
| grub_cs5536_find (grub_pci_device_t *devp) | ||||
| { | ||||
|   int found = 0; | ||||
|   auto int NESTED_FUNC_ATTR hook (grub_pci_device_t dev, | ||||
| 				  grub_pci_id_t pciid); | ||||
| 
 | ||||
|   int NESTED_FUNC_ATTR hook (grub_pci_device_t dev, | ||||
| 			     grub_pci_id_t pciid) | ||||
|   { | ||||
|     if (pciid == GRUB_CS5536_PCIID) | ||||
|       { | ||||
| 	*devp = dev; | ||||
| 	found = 1; | ||||
| 	return 1; | ||||
|       } | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   grub_pci_iterate (hook); | ||||
| 
 | ||||
|   return found; | ||||
| } | ||||
| 
 | ||||
| grub_uint64_t | ||||
| grub_cs5536_read_msr (grub_pci_device_t dev, grub_uint32_t addr) | ||||
| { | ||||
|   grub_uint64_t ret = 0; | ||||
|   grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_ADDR), | ||||
| 		  addr); | ||||
|   ret = (grub_uint64_t) | ||||
|     grub_pci_read (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_DATA0)); | ||||
|   ret |= (((grub_uint64_t)  | ||||
| 	  grub_pci_read (grub_pci_make_address (dev, | ||||
| 						GRUB_CS5536_MSR_MAILBOX_DATA1))) | ||||
| 	  << 32); | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_cs5536_write_msr (grub_pci_device_t dev, grub_uint32_t addr, | ||||
| 		       grub_uint64_t val) | ||||
| { | ||||
|   grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_ADDR), | ||||
| 		  addr); | ||||
|   grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_DATA0), | ||||
| 		  val & 0xffffffff); | ||||
|   grub_pci_write (grub_pci_make_address (dev, GRUB_CS5536_MSR_MAILBOX_DATA1), | ||||
| 		  val >> 32); | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_cs5536_smbus_wait (grub_port_t smbbase) | ||||
| { | ||||
|   grub_uint64_t start = grub_get_time_ms (); | ||||
|   while (1) | ||||
|     { | ||||
|       grub_uint8_t status; | ||||
|       status = grub_inb (smbbase + GRUB_CS5536_SMB_REG_STATUS); | ||||
|       if (status & GRUB_CS5536_SMB_REG_STATUS_SDAST) | ||||
| 	return GRUB_ERR_NONE;	 | ||||
|       if (status & GRUB_CS5536_SMB_REG_STATUS_BER) | ||||
| 	return grub_error (GRUB_ERR_IO, "SM bus error"); | ||||
|       if (status & GRUB_CS5536_SMB_REG_STATUS_NACK) | ||||
| 	return grub_error (GRUB_ERR_IO, "NACK received"); | ||||
|       if (grub_get_time_ms () > start + 40) | ||||
| 	return grub_error (GRUB_ERR_IO, "SM stalled"); | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_cs5536_read_spd_byte (grub_port_t smbbase, grub_uint8_t dev, | ||||
| 			   grub_uint8_t addr, grub_uint8_t *res) | ||||
| { | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   /* Send START.  */ | ||||
|   grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1) | ||||
| 	     | GRUB_CS5536_SMB_REG_CTRL1_START, | ||||
| 	     smbbase + GRUB_CS5536_SMB_REG_CTRL1); | ||||
| 
 | ||||
|   /* Send device address.  */ | ||||
|   err = grub_cs5536_smbus_wait (smbbase);  | ||||
|   if (err)  | ||||
|     return err; | ||||
|   grub_outb (dev << 1, smbbase + GRUB_CS5536_SMB_REG_DATA); | ||||
| 
 | ||||
|   /* Send ACK.  */ | ||||
|   err = grub_cs5536_smbus_wait (smbbase); | ||||
|   if (err) | ||||
|     return err; | ||||
|   grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1) | ||||
| 	     | GRUB_CS5536_SMB_REG_CTRL1_ACK, | ||||
| 	     smbbase + GRUB_CS5536_SMB_REG_CTRL1); | ||||
| 
 | ||||
|   /* Send byte address.  */ | ||||
|   grub_outb (addr, smbbase + GRUB_CS5536_SMB_REG_DATA); | ||||
| 
 | ||||
|   /* Send START.  */ | ||||
|   err = grub_cs5536_smbus_wait (smbbase);  | ||||
|   if (err)  | ||||
|     return err; | ||||
|   grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1) | ||||
| 	     | GRUB_CS5536_SMB_REG_CTRL1_START, | ||||
| 	     smbbase + GRUB_CS5536_SMB_REG_CTRL1); | ||||
| 
 | ||||
|   /* Send device address.  */ | ||||
|   err = grub_cs5536_smbus_wait (smbbase); | ||||
|   if (err) | ||||
|     return err; | ||||
|   grub_outb ((dev << 1) | 1, smbbase + GRUB_CS5536_SMB_REG_DATA); | ||||
| 
 | ||||
|   /* Send STOP.  */ | ||||
|   err = grub_cs5536_smbus_wait (smbbase); | ||||
|   if (err) | ||||
|     return err; | ||||
|   grub_outb (grub_inb (smbbase + GRUB_CS5536_SMB_REG_CTRL1) | ||||
| 	     | GRUB_CS5536_SMB_REG_CTRL1_STOP, | ||||
| 	     smbbase + GRUB_CS5536_SMB_REG_CTRL1); | ||||
| 
 | ||||
|   err = grub_cs5536_smbus_wait (smbbase); | ||||
|   if (err)  | ||||
|     return err; | ||||
|   *res = grub_inb (smbbase + GRUB_CS5536_SMB_REG_DATA); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_cs5536_init_smbus (grub_pci_device_t dev, grub_uint16_t divisor, | ||||
| 			grub_port_t *smbbase) | ||||
| { | ||||
|   grub_uint64_t smbbar; | ||||
| 
 | ||||
|   smbbar = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_SMB_BAR); | ||||
| 
 | ||||
|   /* FIXME  */ | ||||
|   if (!(smbbar & GRUB_CS5536_LBAR_ENABLE)) | ||||
|     return grub_error(GRUB_ERR_IO, "SMB controller not enabled\n"); | ||||
|   *smbbase = (smbbar & GRUB_CS5536_LBAR_ADDR_MASK) + GRUB_MACHINE_PCI_IO_BASE; | ||||
| 
 | ||||
|   if (divisor < 8) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid divisor"); | ||||
| 
 | ||||
|   /* Disable SMB.  */ | ||||
|   grub_outb (0, *smbbase + GRUB_CS5536_SMB_REG_CTRL2); | ||||
| 
 | ||||
|   /* Disable interrupts.  */ | ||||
|   grub_outb (0, *smbbase + GRUB_CS5536_SMB_REG_CTRL1); | ||||
| 
 | ||||
|   /* Set as master.  */ | ||||
|   grub_outb (GRUB_CS5536_SMB_REG_ADDR_MASTER, | ||||
|   	     *smbbase + GRUB_CS5536_SMB_REG_ADDR); | ||||
| 
 | ||||
|   /* Launch.  */ | ||||
|   grub_outb (((divisor >> 7) & 0xff), *smbbase + GRUB_CS5536_SMB_REG_CTRL3); | ||||
|   grub_outb (((divisor << 1) & 0xfe) | GRUB_CS5536_SMB_REG_CTRL2_ENABLE, | ||||
| 	     *smbbase + GRUB_CS5536_SMB_REG_CTRL2); | ||||
|    | ||||
|   return GRUB_ERR_NONE;  | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_cs5536_read_spd (grub_port_t smbbase, grub_uint8_t dev, | ||||
| 		      struct grub_smbus_spd *res) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   grub_size_t size; | ||||
|   grub_uint8_t b; | ||||
|   grub_size_t ptr; | ||||
| 
 | ||||
|   err = grub_cs5536_read_spd_byte (smbbase, dev, 0, &b); | ||||
|   if (err) | ||||
|     return err; | ||||
|   if (b == 0) | ||||
|     return grub_error (GRUB_ERR_IO, "no SPD found"); | ||||
|   size = b; | ||||
|    | ||||
|   ((grub_uint8_t *) res)[0] = b; | ||||
|   for (ptr = 1; ptr < size; ptr++) | ||||
|     { | ||||
|       err = grub_cs5536_read_spd_byte (smbbase, dev, ptr, | ||||
| 				       &((grub_uint8_t *) res)[ptr]); | ||||
|       if (err) | ||||
| 	return err; | ||||
|     } | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| /* Dump of GPIO connections. FIXME: Remove useless and macroify.  */ | ||||
| static grub_uint32_t gpiodump[] = { | ||||
|   0xffff0000, 0x2ffdd002, 0xffff0000, 0xffff0000, | ||||
|   0x2fffd000, 0xffff0000, 0x1000efff, 0xefff1000, | ||||
|   0x3ffbc004, 0xffff0000, 0xffff0000, 0xffff0000, | ||||
|   0x3ffbc004, 0x3ffbc004, 0xffff0000, 0x00000000, | ||||
|   0xffff0000, 0xffff0000, 0x3ffbc004, 0x3f9bc064, | ||||
|   0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||||
|   0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||||
|   0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||||
|   0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, | ||||
|   0xffff0000, 0xffff0000, 0x0000ffff, 0xffff0000, | ||||
|   0xefff1000, 0xffff0000, 0xffff0000, 0xffff0000, | ||||
|   0xefff1000, 0xefff1000, 0xffff0000, 0x00000000, | ||||
|   0xffff0000, 0xffff0000, 0xefff1000, 0xffff0000, | ||||
|   0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||||
|   0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||||
|   0x00000000, 0x50000000, 0x00000000, 0x00000000, | ||||
| }; | ||||
| 
 | ||||
| static inline void | ||||
| set_io_space (grub_pci_device_t dev, int num, grub_uint16_t start, | ||||
| 	      grub_uint16_t len) | ||||
| { | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_REGIONS_START + num, | ||||
| 			 ((((grub_uint64_t) start + len - 4) | ||||
| 			   << GRUB_CS5536_MSR_GL_REGION_IO_TOP_SHIFT) | ||||
| 			  & GRUB_CS5536_MSR_GL_REGION_TOP_MASK) | ||||
| 			 | (((grub_uint64_t) start | ||||
| 			     << GRUB_CS5536_MSR_GL_REGION_IO_BASE_SHIFT) | ||||
| 			  & GRUB_CS5536_MSR_GL_REGION_BASE_MASK) | ||||
| 			 | GRUB_CS5536_MSR_GL_REGION_IO | ||||
| 			 | GRUB_CS5536_MSR_GL_REGION_ENABLE); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| set_iod (grub_pci_device_t dev, int num, int dest, int start, int mask) | ||||
| { | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_IOD_START + num, | ||||
| 			 ((grub_uint64_t) dest << GRUB_CS5536_IOD_DEST_SHIFT) | ||||
| 			 | (((grub_uint64_t) start & GRUB_CS5536_IOD_ADDR_MASK) | ||||
| 			    << GRUB_CS5536_IOD_BASE_SHIFT) | ||||
| 			 | ((mask & GRUB_CS5536_IOD_ADDR_MASK) | ||||
| 			    << GRUB_CS5536_IOD_MASK_SHIFT)); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| set_p2d (grub_pci_device_t dev, int num, int dest, grub_uint32_t start) | ||||
| { | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_P2D_START + num, | ||||
| 			 (((grub_uint64_t) dest) << GRUB_CS5536_P2D_DEST_SHIFT) | ||||
| 			 | ((grub_uint64_t) (start >> GRUB_CS5536_P2D_LOG_ALIGN) | ||||
| 			    << GRUB_CS5536_P2D_BASE_SHIFT) | ||||
| 			 | (((1 << (32 - GRUB_CS5536_P2D_LOG_ALIGN)) - 1) | ||||
| 			    << GRUB_CS5536_P2D_MASK_SHIFT)); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_cs5536_init_geode (grub_pci_device_t dev) | ||||
| { | ||||
|   int i; | ||||
| 
 | ||||
|   /* Make sure GPIO is where we expect it to be.  */ | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GPIO_BAR, | ||||
| 			 GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_GPIO); | ||||
| 
 | ||||
|   /* Setup GPIO.  */ | ||||
|   for (i = 0; i < (int) ARRAY_SIZE (gpiodump); i++) | ||||
|     ((volatile grub_uint32_t *) (GRUB_MACHINE_PCI_IO_BASE  | ||||
| 				 + GRUB_CS5536_LBAR_GPIO)) [i] = gpiodump[i]; | ||||
| 
 | ||||
|   /* Enable more BARs.  */ | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IRQ_MAP_BAR, | ||||
| 			 GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_IRQ_MAP); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_MFGPT_BAR, | ||||
| 			 GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_MFGPT); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_ACPI_BAR, | ||||
| 			 GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_ACPI); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_PM_BAR, | ||||
| 			 GRUB_CS5536_LBAR_TURN_ON | GRUB_CS5536_LBAR_PM); | ||||
| 
 | ||||
|   /* Setup DIVIL.  */ | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LEG_IO, | ||||
| 			 GRUB_CS5536_MSR_DIVIL_LEG_IO_MODE_X86 | ||||
| 			 | GRUB_CS5536_MSR_DIVIL_LEG_IO_F_REMAP | ||||
| 			 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE0 | ||||
| 			 | GRUB_CS5536_MSR_DIVIL_LEG_IO_RTC_ENABLE1); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_PRIMARY_MASK, | ||||
| 			 (~GRUB_CS5536_DIVIL_LPC_INTERRUPTS) & 0xffff); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_IRQ_MAPPER_LPC_MASK, | ||||
| 			 GRUB_CS5536_DIVIL_LPC_INTERRUPTS); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL, | ||||
| 			 GRUB_CS5536_MSR_DIVIL_LPC_SERIAL_IRQ_CONTROL_ENABLE); | ||||
| 
 | ||||
|   /* Initialise USB controller.  */ | ||||
|   /* FIXME: assign adresses dynamically.  */ | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_OHCI_BASE,  | ||||
| 			 GRUB_CS5536_MSR_USB_BASE_BUS_MASTER | ||||
| 			 | GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE | ||||
| 			 | 0x05024000); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE, | ||||
| 			 GRUB_CS5536_MSR_USB_BASE_BUS_MASTER | ||||
| 			 | GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE | ||||
| 			 | (0x20ULL << GRUB_CS5536_MSR_USB_EHCI_BASE_FLDJ_SHIFT) | ||||
| 			 | 0x05023000); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_CONTROLLER_BASE, | ||||
| 			 GRUB_CS5536_MSR_USB_BASE_BUS_MASTER | ||||
| 			 | GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE | 0x05020000); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_OPTION_CONTROLLER_BASE, | ||||
| 			 GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE | 0x05022000); | ||||
|   set_p2d (dev, 0, GRUB_CS5536_DESTINATION_USB, 0x05020000); | ||||
|   set_p2d (dev, 1, GRUB_CS5536_DESTINATION_USB, 0x05022000); | ||||
|   set_p2d (dev, 5, GRUB_CS5536_DESTINATION_USB, 0x05024000); | ||||
|   set_p2d (dev, 6, GRUB_CS5536_DESTINATION_USB, 0x05023000); | ||||
| 
 | ||||
|   { | ||||
|     volatile grub_uint32_t *oc; | ||||
|     oc = grub_pci_device_map_range (dev, 0x05022000, | ||||
| 				    GRUB_CS5536_USB_OPTION_REGS_SIZE); | ||||
| 
 | ||||
|     oc[GRUB_CS5536_USB_OPTION_REG_UOCMUX] = | ||||
|       (oc[GRUB_CS5536_USB_OPTION_REG_UOCMUX] | ||||
|        & ~GRUB_CS5536_USB_OPTION_REG_UOCMUX_PMUX_MASK) | ||||
|       | GRUB_CS5536_USB_OPTION_REG_UOCMUX_PMUX_HC; | ||||
|     grub_pci_device_unmap_range (dev, oc, GRUB_CS5536_USB_OPTION_REGS_SIZE); | ||||
|   } | ||||
| 
 | ||||
|   /* Setup IDE controller.  */ | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_IO_BAR, | ||||
| 			 GRUB_CS5536_LBAR_IDE | ||||
| 			 | GRUB_CS5536_MSR_IDE_IO_BAR_UNITS); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_CFG, | ||||
| 			 GRUB_CS5536_MSR_IDE_CFG_CHANNEL_ENABLE); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_TIMING, | ||||
| 			 (GRUB_CS5536_MSR_IDE_TIMING_PIO0 | ||||
| 			  << GRUB_CS5536_MSR_IDE_TIMING_DRIVE0_SHIFT) | ||||
| 			 | (GRUB_CS5536_MSR_IDE_TIMING_PIO0 | ||||
| 			    << GRUB_CS5536_MSR_IDE_TIMING_DRIVE1_SHIFT)); | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_IDE_CAS_TIMING, | ||||
| 			 (GRUB_CS5536_MSR_IDE_CAS_TIMING_CMD_PIO0 | ||||
| 			  << GRUB_CS5536_MSR_IDE_CAS_TIMING_CMD_SHIFT) | ||||
| 			 | (GRUB_CS5536_MSR_IDE_CAS_TIMING_PIO0 | ||||
| 			    << GRUB_CS5536_MSR_IDE_CAS_TIMING_DRIVE0_SHIFT) | ||||
| 			 | (GRUB_CS5536_MSR_IDE_CAS_TIMING_PIO0 | ||||
| 			    << GRUB_CS5536_MSR_IDE_CAS_TIMING_DRIVE1_SHIFT)); | ||||
| 
 | ||||
|   /* Setup Geodelink PCI.  */ | ||||
|   grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_GL_PCI_CTRL, | ||||
| 			 (4ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_OUT_THR_SHIFT) | ||||
| 			 | (4ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_IN_THR_SHIFT) | ||||
| 			 | (8ULL << GRUB_CS5536_MSR_GL_PCI_CTRL_LATENCY_SHIFT) | ||||
| 			 | GRUB_CS5536_MSR_GL_PCI_CTRL_IO_ENABLE | ||||
| 			 | GRUB_CS5536_MSR_GL_PCI_CTRL_MEMORY_ENABLE); | ||||
| 
 | ||||
|   /* Setup windows.  */ | ||||
|   set_io_space (dev, 0, GRUB_CS5536_LBAR_SMBUS, GRUB_CS5536_SMBUS_REGS_SIZE); | ||||
|   set_io_space (dev, 1, GRUB_CS5536_LBAR_GPIO, GRUB_CS5536_GPIO_REGS_SIZE); | ||||
|   set_io_space (dev, 2, GRUB_CS5536_LBAR_MFGPT, GRUB_CS5536_MFGPT_REGS_SIZE); | ||||
|   set_io_space (dev, 3, GRUB_CS5536_LBAR_IRQ_MAP, GRUB_CS5536_IRQ_MAP_REGS_SIZE); | ||||
|   set_io_space (dev, 4, GRUB_CS5536_LBAR_PM, GRUB_CS5536_PM_REGS_SIZE); | ||||
|   set_io_space (dev, 5, GRUB_CS5536_LBAR_ACPI, GRUB_CS5536_ACPI_REGS_SIZE); | ||||
|   set_iod (dev, 0, GRUB_CS5536_DESTINATION_IDE, GRUB_ATA_CH0_PORT1, 0xffff8); | ||||
|   set_iod (dev, 1, GRUB_CS5536_DESTINATION_ACC, GRUB_CS5536_LBAR_ACC, 0xfff80); | ||||
|   set_iod (dev, 2, GRUB_CS5536_DESTINATION_IDE, GRUB_CS5536_LBAR_IDE, 0xffff0); | ||||
| } | ||||
							
								
								
									
										77
									
								
								grub-core/bus/emu/pci.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								grub-core/bus/emu/pci.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| /* pci.c - Generic PCI interfaces.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/pci.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/emu/misc.h> | ||||
| #include <grub/util/misc.h> | ||||
| 
 | ||||
| grub_pci_address_t | ||||
| grub_pci_make_address (grub_pci_device_t dev, int reg) | ||||
| { | ||||
|   grub_pci_address_t ret; | ||||
|   ret.dev = dev; | ||||
|   ret.pos = reg; | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_pci_iterate (grub_pci_iteratefunc_t hook) | ||||
| { | ||||
|   struct pci_device_iterator *iter; | ||||
|   struct pci_slot_match slot; | ||||
|   struct pci_device *dev; | ||||
|   slot.domain = PCI_MATCH_ANY; | ||||
|   slot.bus = PCI_MATCH_ANY; | ||||
|   slot.dev = PCI_MATCH_ANY; | ||||
|   slot.func = PCI_MATCH_ANY; | ||||
|   iter = pci_slot_match_iterator_create (&slot); | ||||
|   while ((dev = pci_device_next (iter))) | ||||
|     hook (dev, dev->vendor_id | (dev->device_id << 16)); | ||||
|   pci_iterator_destroy (iter); | ||||
| } | ||||
| 
 | ||||
| void * | ||||
| grub_pci_device_map_range (grub_pci_device_t dev, grub_addr_t base, | ||||
| 			   grub_size_t size) | ||||
| { | ||||
|   void *addr; | ||||
|   int err; | ||||
|   err = pci_device_map_range (dev, base, size, PCI_DEV_MAP_FLAG_WRITABLE, &addr); | ||||
|   if (err) | ||||
|     grub_util_error ("mapping 0x%x failed (error %d)\n", base, err); | ||||
|   return addr; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_pci_device_unmap_range (grub_pci_device_t dev, void *mem, | ||||
| 			     grub_size_t size) | ||||
| { | ||||
|   pci_device_unmap_range (dev, mem, size); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_INIT (pci) | ||||
| { | ||||
|   pci_system_init (); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (pci) | ||||
| { | ||||
|   pci_system_cleanup (); | ||||
| } | ||||
							
								
								
									
										119
									
								
								grub-core/bus/pci.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								grub-core/bus/pci.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | |||
| /* pci.c - Generic PCI interfaces.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/mm.h> | ||||
| 
 | ||||
| /* FIXME: correctly support 64-bit architectures.  */ | ||||
| /* #if GRUB_TARGET_SIZEOF_VOID_P == 4 */ | ||||
| struct grub_pci_dma_chunk * | ||||
| grub_memalign_dma32 (grub_size_t align, grub_size_t size) | ||||
| { | ||||
|   return grub_memalign (align, size); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_dma_free (struct grub_pci_dma_chunk *ch) | ||||
| { | ||||
|   grub_free (ch); | ||||
| } | ||||
| /* #endif */ | ||||
| 
 | ||||
| #ifdef GRUB_MACHINE_MIPS_YEELOONG | ||||
| volatile void * | ||||
| grub_dma_get_virt (struct grub_pci_dma_chunk *ch) | ||||
| { | ||||
|   return (void *) ((((grub_uint32_t) ch) & 0x1fffffff) | 0xa0000000); | ||||
| } | ||||
| 
 | ||||
| grub_uint32_t | ||||
| grub_dma_get_phys (struct grub_pci_dma_chunk *ch) | ||||
| { | ||||
|   return (((grub_uint32_t) ch) & 0x1fffffff) | 0x80000000; | ||||
| } | ||||
| #else | ||||
| 
 | ||||
| volatile void * | ||||
| grub_dma_get_virt (struct grub_pci_dma_chunk *ch) | ||||
| { | ||||
|   return (void *) ch; | ||||
| } | ||||
| 
 | ||||
| grub_uint32_t | ||||
| grub_dma_get_phys (struct grub_pci_dma_chunk *ch) | ||||
| { | ||||
|   return (grub_uint32_t) (grub_addr_t) ch; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| grub_pci_address_t | ||||
| grub_pci_make_address (grub_pci_device_t dev, int reg) | ||||
| { | ||||
|   return (1 << 31) | (dev.bus << 16) | (dev.device << 11) | ||||
|     | (dev.function << 8) | reg; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_pci_iterate (grub_pci_iteratefunc_t hook) | ||||
| { | ||||
|   grub_pci_device_t dev; | ||||
|   grub_pci_address_t addr; | ||||
|   grub_pci_id_t id; | ||||
|   grub_uint32_t hdr; | ||||
| 
 | ||||
|   for (dev.bus = 0; dev.bus < GRUB_PCI_NUM_BUS; dev.bus++) | ||||
|     { | ||||
|       for (dev.device = 0; dev.device < GRUB_PCI_NUM_DEVICES; dev.device++) | ||||
| 	{ | ||||
| 	  for (dev.function = 0; dev.function < 8; dev.function++) | ||||
| 	    { | ||||
| 	      addr = grub_pci_make_address (dev, GRUB_PCI_REG_PCI_ID); | ||||
| 	      id = grub_pci_read (addr); | ||||
| 
 | ||||
| 	      /* Check if there is a device present.  */ | ||||
| 	      if (id >> 16 == 0xFFFF) | ||||
| 		continue; | ||||
| 
 | ||||
| #ifdef GRUB_MACHINE_MIPS_YEELOONG | ||||
| 	      /* Skip ghosts.  */ | ||||
| 	      if (id == GRUB_YEELOONG_OHCI_PCIID | ||||
| 		  && dev.function == GRUB_YEELOONG_OHCI_GHOST_FUNCTION) | ||||
| 		continue; | ||||
| 	      if (id == GRUB_YEELOONG_EHCI_PCIID | ||||
| 		  && dev.function == GRUB_YEELOONG_EHCI_GHOST_FUNCTION) | ||||
| 		continue; | ||||
| #endif | ||||
| 
 | ||||
| 	      if (hook (dev, id)) | ||||
| 		return; | ||||
| 
 | ||||
| 	      /* Probe only func = 0 if the device if not multifunction */ | ||||
| 	      if (dev.function == 0) | ||||
| 		{ | ||||
| 		  addr = grub_pci_make_address (dev, GRUB_PCI_REG_CACHELINE); | ||||
| 		  hdr = grub_pci_read (addr); | ||||
| 		  if (!(hdr & 0x800000)) | ||||
| 		    break; | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| } | ||||
							
								
								
									
										201
									
								
								grub-core/bus/usb/emu/usb.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								grub-core/bus/usb/emu/usb.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,201 @@ | |||
| /*  usb.c -- libusb USB support for GRUB.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <config.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <usb.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/dl.h> | ||||
| 
 | ||||
|  | ||||
| static struct grub_usb_controller_dev usb_controller = | ||||
| { | ||||
|   .name = "libusb" | ||||
| }; | ||||
| 
 | ||||
| static struct grub_usb_device *grub_usb_devs[128]; | ||||
| 
 | ||||
| struct usb_bus *busses; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_libusb_devices (void) | ||||
| 
 | ||||
| { | ||||
|   struct usb_bus *bus; | ||||
|   int last = 0; | ||||
| 
 | ||||
|   busses = usb_get_busses(); | ||||
| 
 | ||||
|   for (bus = busses; bus; bus = bus->next) | ||||
|     { | ||||
|       struct usb_device *usbdev; | ||||
|       struct grub_usb_device *dev; | ||||
| 
 | ||||
|       for (usbdev = bus->devices; usbdev; usbdev = usbdev->next) | ||||
| 	{ | ||||
| 	  struct usb_device_descriptor *desc = &usbdev->descriptor; | ||||
| 	  grub_err_t err; | ||||
| 
 | ||||
| 	  if (! desc->bcdUSB) | ||||
| 	    continue; | ||||
| 
 | ||||
| 	  dev = grub_malloc (sizeof (*dev)); | ||||
| 	  if (! dev) | ||||
| 	    return grub_errno; | ||||
| 
 | ||||
| 	  dev->data = usbdev; | ||||
| 
 | ||||
| 	  /* Fill in all descriptors.  */ | ||||
| 	  err = grub_usb_device_initialize (dev); | ||||
| 	  if (err) | ||||
| 	    { | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* Register the device.  */ | ||||
| 	  grub_usb_devs[last++] = dev; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_usb_poll_devices (void) | ||||
| { | ||||
|   /* TODO: recheck grub_usb_devs */ | ||||
| } | ||||
| 
 | ||||
|  | ||||
| int | ||||
| grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) | ||||
| { | ||||
|   int i; | ||||
| 
 | ||||
|   for (i = 0; i < 128; i++) | ||||
|     { | ||||
|       if (grub_usb_devs[i]) | ||||
| 	{ | ||||
| 	  if (hook (grub_usb_devs[i])) | ||||
| 	      return 1; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_root_hub (grub_usb_controller_t controller __attribute__((unused))) | ||||
| { | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_control_msg (grub_usb_device_t dev, grub_uint8_t reqtype, | ||||
| 		      grub_uint8_t request, grub_uint16_t value, | ||||
| 		      grub_uint16_t idx, grub_size_t size, char *data) | ||||
| { | ||||
|   usb_dev_handle *devh; | ||||
|   struct usb_device *d = dev->data; | ||||
| 
 | ||||
|   devh = usb_open (d); | ||||
|   if (usb_control_msg (devh, reqtype, request, | ||||
| 		       value, idx, data, size, 20) < 0) | ||||
|     { | ||||
|       usb_close (devh); | ||||
|       return GRUB_USB_ERR_STALL; | ||||
|     } | ||||
| 
 | ||||
|   usb_close (devh); | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_bulk_read (grub_usb_device_t dev, | ||||
| 		    int endpoint, grub_size_t size, char *data) | ||||
| { | ||||
|   usb_dev_handle *devh; | ||||
|   struct usb_device *d = dev->data; | ||||
| 
 | ||||
|   devh = usb_open (d); | ||||
|   if (usb_claim_interface (devh, 0) < 1) | ||||
|     { | ||||
|       usb_close (devh); | ||||
|       return GRUB_USB_ERR_STALL; | ||||
|     } | ||||
| 
 | ||||
|   if (usb_bulk_read (devh, endpoint, data, size, 20) < 1) | ||||
|     { | ||||
|       usb_close (devh); | ||||
|       return GRUB_USB_ERR_STALL; | ||||
|     } | ||||
| 
 | ||||
|   usb_release_interface (devh, 0); | ||||
|   usb_close (devh); | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_bulk_write (grub_usb_device_t dev, | ||||
| 		     int endpoint, grub_size_t size, char *data) | ||||
| { | ||||
|   usb_dev_handle *devh; | ||||
|   struct usb_device *d = dev->data; | ||||
| 
 | ||||
|   devh = usb_open (d); | ||||
|   if (usb_claim_interface (devh, 0) < 0) | ||||
|     goto fail; | ||||
| 
 | ||||
|   if (usb_bulk_write (devh, endpoint, data, size, 20) < 0) | ||||
|     goto fail; | ||||
| 
 | ||||
|   if (usb_release_interface (devh, 0) < 0) | ||||
|     goto fail; | ||||
| 
 | ||||
|   usb_close (devh); | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| 
 | ||||
|  fail: | ||||
|   usb_close (devh); | ||||
|   return GRUB_USB_ERR_STALL; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_INIT (libusb) | ||||
| { | ||||
|   usb_init(); | ||||
|   usb_find_busses(); | ||||
|   usb_find_devices(); | ||||
| 
 | ||||
|   if (grub_libusb_devices ()) | ||||
|     return; | ||||
| 
 | ||||
|   grub_usb_controller_dev_register (&usb_controller); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (libusb) | ||||
| { | ||||
|   return; | ||||
| } | ||||
							
								
								
									
										1421
									
								
								grub-core/bus/usb/ohci.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1421
									
								
								grub-core/bus/usb/ohci.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										125
									
								
								grub-core/bus/usb/serial/common.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								grub-core/bus/usb/serial/common.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,125 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/serial.h> | ||||
| #include <grub/usbserial.h> | ||||
| 
 | ||||
| void | ||||
| grub_usbserial_fini (struct grub_serial_port *port) | ||||
| { | ||||
|   port->usbdev->config[port->configno].interf[port->interfno].detach_hook = 0; | ||||
|   port->usbdev->config[port->configno].interf[port->interfno].attached = 0; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_usbserial_detach (grub_usb_device_t usbdev, int configno, int interfno) | ||||
| { | ||||
|   static struct grub_serial_port *port; | ||||
|   port = usbdev->config[configno].interf[interfno].detach_data; | ||||
| 
 | ||||
|   grub_serial_unregister (port); | ||||
| } | ||||
| 
 | ||||
| static int usbnum = 0; | ||||
| 
 | ||||
| int | ||||
| grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno, | ||||
| 		       struct grub_serial_driver *driver) | ||||
| { | ||||
|   struct grub_serial_port *port; | ||||
|   int j; | ||||
|   struct grub_usb_desc_if *interf; | ||||
| 
 | ||||
|   interf = usbdev->config[configno].interf[interfno].descif; | ||||
| 
 | ||||
|   port = grub_malloc (sizeof (*port)); | ||||
|   if (!port) | ||||
|     { | ||||
|       grub_print_error (); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   port->name = grub_xasprintf ("usb%d", usbnum++); | ||||
|   if (!port->name) | ||||
|     { | ||||
|       grub_free (port); | ||||
|       grub_print_error (); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   port->usbdev = usbdev; | ||||
|   port->driver = driver; | ||||
|   for (j = 0; j < interf->endpointcnt; j++) | ||||
|     { | ||||
|       struct grub_usb_desc_endp *endp; | ||||
|       endp = &usbdev->config[0].interf[interfno].descendp[j]; | ||||
| 
 | ||||
|       if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2) | ||||
| 	{ | ||||
| 	  /* Bulk IN endpoint.  */ | ||||
| 	  port->in_endp = endp; | ||||
| 	} | ||||
|       else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2) | ||||
| 	{ | ||||
| 	  /* Bulk OUT endpoint.  */ | ||||
| 	  port->out_endp = endp; | ||||
| 	} | ||||
|     } | ||||
|   if (!port->out_endp || !port->in_endp) | ||||
|     { | ||||
|       grub_free (port->name); | ||||
|       grub_free (port); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   port->configno = configno; | ||||
|   port->interfno = interfno; | ||||
| 
 | ||||
|   grub_serial_config_defaults (port); | ||||
|   grub_serial_register (port); | ||||
| 
 | ||||
|   port->usbdev->config[port->configno].interf[port->interfno].detach_hook | ||||
|     = grub_usbserial_detach; | ||||
|   port->usbdev->config[port->configno].interf[port->interfno].detach_data | ||||
|     = port; | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size) | ||||
| { | ||||
|   grub_usb_err_t err; | ||||
|   grub_size_t actual; | ||||
| 
 | ||||
|   if (port->bufstart < port->bufend) | ||||
|     return port->buf[port->bufstart++]; | ||||
| 
 | ||||
|   err = grub_usb_bulk_read_extended (port->usbdev, port->in_endp->endp_addr, | ||||
| 				     sizeof (port->buf), port->buf, 10, | ||||
| 				     &actual); | ||||
|   if (err != GRUB_USB_ERR_NONE) | ||||
|     return -1; | ||||
| 
 | ||||
|   port->bufstart = header_size; | ||||
|   port->bufend = actual; | ||||
|   if (port->bufstart >= port->bufend) | ||||
|     return -1; | ||||
| 
 | ||||
|   return port->buf[port->bufstart++]; | ||||
| } | ||||
							
								
								
									
										205
									
								
								grub-core/bus/usb/serial/ftdi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								grub-core/bus/usb/serial/ftdi.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,205 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/serial.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/usbserial.h> | ||||
| 
 | ||||
| enum | ||||
|   { | ||||
|     GRUB_FTDI_MODEM_CTRL = 0x01, | ||||
|     GRUB_FTDI_FLOW_CTRL = 0x02, | ||||
|     GRUB_FTDI_SPEED_CTRL = 0x03, | ||||
|     GRUB_FTDI_DATA_CTRL = 0x04 | ||||
|   }; | ||||
| 
 | ||||
| #define GRUB_FTDI_MODEM_CTRL_DTRRTS 3 | ||||
| #define GRUB_FTDI_FLOW_CTRL_DTRRTS 3 | ||||
| 
 | ||||
| /* Convert speed to divisor.  */ | ||||
| static grub_uint32_t | ||||
| get_divisor (unsigned int speed) | ||||
| { | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   /* The structure for speed vs. divisor.  */ | ||||
|   struct divisor | ||||
|   { | ||||
|     unsigned int speed; | ||||
|     grub_uint32_t div; | ||||
|   }; | ||||
| 
 | ||||
|   /* The table which lists common configurations.  */ | ||||
|   /* Computed with a division formula with 3MHz as base frequency. */ | ||||
|   static struct divisor divisor_tab[] = | ||||
|     { | ||||
|       { 2400,   0x04e2 }, | ||||
|       { 4800,   0x0271 }, | ||||
|       { 9600,   0x4138 }, | ||||
|       { 19200,  0x809c }, | ||||
|       { 38400,  0xc04e }, | ||||
|       { 57600,  0xc034 }, | ||||
|       { 115200, 0x001a } | ||||
|     }; | ||||
| 
 | ||||
|   /* Set the baud rate.  */ | ||||
|   for (i = 0; i < ARRAY_SIZE (divisor_tab); i++) | ||||
|     if (divisor_tab[i].speed == speed) | ||||
|       return divisor_tab[i].div; | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| real_config (struct grub_serial_port *port) | ||||
| { | ||||
|   grub_uint32_t divisor; | ||||
|   const grub_uint16_t parities[] = { | ||||
|     [GRUB_SERIAL_PARITY_NONE] = 0x0000, | ||||
|     [GRUB_SERIAL_PARITY_ODD] = 0x0100, | ||||
|     [GRUB_SERIAL_PARITY_EVEN] = 0x0200 | ||||
|   }; | ||||
|   const grub_uint16_t stop_bits[] = { | ||||
|     [GRUB_SERIAL_STOP_BITS_1] = 0x0000, | ||||
|     [GRUB_SERIAL_STOP_BITS_2] = 0x1000, | ||||
|   }; | ||||
| 
 | ||||
|   if (port->configured) | ||||
|     return; | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			GRUB_FTDI_MODEM_CTRL, | ||||
| 			GRUB_FTDI_MODEM_CTRL_DTRRTS, 0, 0, 0); | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			GRUB_FTDI_FLOW_CTRL, | ||||
| 			GRUB_FTDI_FLOW_CTRL_DTRRTS, 0, 0, 0); | ||||
| 
 | ||||
|   divisor = get_divisor (port->config.speed); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			GRUB_FTDI_SPEED_CTRL, | ||||
| 			divisor & 0xffff, divisor >> 16, 0, 0); | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			GRUB_FTDI_DATA_CTRL, | ||||
| 			parities[port->config.parity] | ||||
| 			| stop_bits[port->config.stop_bits] | ||||
| 			| port->config.word_len, 0, 0, 0); | ||||
| 
 | ||||
|   port->configured = 1; | ||||
| } | ||||
| 
 | ||||
| /* Fetch a key.  */ | ||||
| static int | ||||
| ftdi_hw_fetch (struct grub_serial_port *port) | ||||
| { | ||||
|   real_config (port); | ||||
| 
 | ||||
|   return grub_usbserial_fetch (port, 2); | ||||
| } | ||||
| 
 | ||||
| /* Put a character.  */ | ||||
| static void | ||||
| ftdi_hw_put (struct grub_serial_port *port, const int c) | ||||
| { | ||||
|   char cc = c; | ||||
| 
 | ||||
|   real_config (port); | ||||
| 
 | ||||
|   grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| ftdi_hw_configure (struct grub_serial_port *port, | ||||
| 			struct grub_serial_config *config) | ||||
| { | ||||
|   grub_uint16_t divisor; | ||||
| 
 | ||||
|   divisor = get_divisor (config->speed); | ||||
|   if (divisor == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed"); | ||||
| 
 | ||||
|   if (config->parity != GRUB_SERIAL_PARITY_NONE | ||||
|       && config->parity != GRUB_SERIAL_PARITY_ODD | ||||
|       && config->parity != GRUB_SERIAL_PARITY_EVEN) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity"); | ||||
| 
 | ||||
|   if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1 | ||||
|       && config->stop_bits != GRUB_SERIAL_STOP_BITS_2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits"); | ||||
| 
 | ||||
|   if (config->word_len < 5 || config->word_len > 8) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length"); | ||||
| 
 | ||||
|   port->config = *config; | ||||
|   port->configured = 0; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static struct grub_serial_driver grub_ftdi_driver = | ||||
|   { | ||||
|     .configure = ftdi_hw_configure, | ||||
|     .fetch = ftdi_hw_fetch, | ||||
|     .put = ftdi_hw_put, | ||||
|     .fini = grub_usbserial_fini | ||||
|   }; | ||||
| 
 | ||||
| static const struct  | ||||
| { | ||||
|   grub_uint16_t vendor, product; | ||||
| } products[] = | ||||
|   { | ||||
|     {0x0403, 0x6001} /* QEMU virtual USBserial.  */ | ||||
|   }; | ||||
| 
 | ||||
| static int | ||||
| grub_ftdi_attach (grub_usb_device_t usbdev, int configno, int interfno) | ||||
| { | ||||
|   unsigned j; | ||||
| 
 | ||||
|   for (j = 0; j < ARRAY_SIZE (products); j++) | ||||
|     if (usbdev->descdev.vendorid == products[j].vendor | ||||
| 	&& usbdev->descdev.prodid == products[j].product) | ||||
|       break; | ||||
|   if (j == ARRAY_SIZE (products)) | ||||
|     return 0; | ||||
| 
 | ||||
|   return grub_usbserial_attach (usbdev, configno, interfno, | ||||
| 				&grub_ftdi_driver); | ||||
| } | ||||
| 
 | ||||
| static struct grub_usb_attach_desc attach_hook = | ||||
| { | ||||
|   .class = 0xff, | ||||
|   .hook = grub_ftdi_attach | ||||
| }; | ||||
| 
 | ||||
| GRUB_MOD_INIT(usbserial_ftdi) | ||||
| { | ||||
|   grub_usb_register_attach_hook_class (&attach_hook); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(usbserial_ftdi) | ||||
| { | ||||
|   grub_serial_unregister_driver (&grub_ftdi_driver); | ||||
|   grub_usb_unregister_attach_hook_class (&attach_hook); | ||||
| } | ||||
							
								
								
									
										218
									
								
								grub-core/bus/usb/serial/pl2303.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								grub-core/bus/usb/serial/pl2303.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,218 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/serial.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/usbserial.h> | ||||
| 
 | ||||
| /* Convert speed to divisor.  */ | ||||
| static grub_uint32_t | ||||
| is_speed_supported (unsigned int speed) | ||||
| { | ||||
|   unsigned int i; | ||||
|   unsigned int supported[] = { 2400, 4800, 9600, 19200, 38400, 57600, 115200}; | ||||
| 
 | ||||
|   for (i = 0; i < ARRAY_SIZE (supported); i++) | ||||
|     if (supported[i] == speed) | ||||
|       return 1; | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| #define GRUB_PL2303_REQUEST_SET_CONFIG 0x20 | ||||
| #define GRUB_PL2303_STOP_BITS_1 0x0 | ||||
| #define GRUB_PL2303_STOP_BITS_2 0x2 | ||||
| 
 | ||||
| #define GRUB_PL2303_PARITY_NONE 0 | ||||
| #define GRUB_PL2303_PARITY_ODD  1 | ||||
| #define GRUB_PL2303_PARITY_EVEN 2 | ||||
| 
 | ||||
| struct grub_pl2303_config | ||||
| { | ||||
|   grub_uint32_t speed; | ||||
|   grub_uint8_t stop_bits; | ||||
|   grub_uint8_t parity; | ||||
|   grub_uint8_t word_len; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| static void | ||||
| real_config (struct grub_serial_port *port) | ||||
| { | ||||
|   struct grub_pl2303_config config_pl2303; | ||||
|   char xx; | ||||
| 
 | ||||
|   if (port->configured) | ||||
|     return; | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN, | ||||
| 			1, 0x8484, 0, 1, &xx); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 0x0404, 0, 0, 0); | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN, | ||||
| 			1, 0x8484, 0, 1, &xx); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN, | ||||
| 			1, 0x8383, 0, 1, &xx); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN, | ||||
| 			1, 0x8484, 0, 1, &xx); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 0x0404, 1, 0, 0); | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN, | ||||
| 			1, 0x8484, 0, 1, &xx); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_IN, | ||||
| 			1, 0x8383, 0, 1, &xx); | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 0, 1, 0, 0); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 1, 0, 0, 0); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 2, 0x44, 0, 0); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 8, 0, 0, 0); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 9, 0, 0, 0); | ||||
| 
 | ||||
|   if (port->config.stop_bits == GRUB_SERIAL_STOP_BITS_2) | ||||
|     config_pl2303.stop_bits = GRUB_PL2303_STOP_BITS_2; | ||||
|   else | ||||
|     config_pl2303.stop_bits = GRUB_PL2303_STOP_BITS_1; | ||||
| 
 | ||||
|   switch (port->config.parity) | ||||
|     { | ||||
|     case GRUB_SERIAL_PARITY_NONE: | ||||
|       config_pl2303.parity = GRUB_PL2303_PARITY_NONE; | ||||
|       break; | ||||
|     case GRUB_SERIAL_PARITY_ODD: | ||||
|       config_pl2303.parity = GRUB_PL2303_PARITY_ODD; | ||||
|       break; | ||||
|     case GRUB_SERIAL_PARITY_EVEN: | ||||
|       config_pl2303.parity = GRUB_PL2303_PARITY_EVEN; | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   config_pl2303.word_len = port->config.word_len; | ||||
|   config_pl2303.speed = port->config.speed; | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, | ||||
| 			GRUB_PL2303_REQUEST_SET_CONFIG, 0, 0, | ||||
| 			sizeof (config_pl2303), (char *) &config_pl2303); | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, | ||||
| 			0x22, 3, 0, 0, 0); | ||||
| 
 | ||||
|   grub_usb_control_msg (port->usbdev, GRUB_USB_REQTYPE_VENDOR_OUT, | ||||
| 			1, 0, 0x61, 0, 0); | ||||
|   port->configured = 1; | ||||
| } | ||||
| 
 | ||||
| /* Fetch a key.  */ | ||||
| static int | ||||
| pl2303_hw_fetch (struct grub_serial_port *port) | ||||
| { | ||||
|   real_config (port); | ||||
| 
 | ||||
|   return grub_usbserial_fetch (port, 0); | ||||
| } | ||||
| 
 | ||||
| /* Put a character.  */ | ||||
| static void | ||||
| pl2303_hw_put (struct grub_serial_port *port, const int c) | ||||
| { | ||||
|   char cc = c; | ||||
| 
 | ||||
|   real_config (port); | ||||
| 
 | ||||
|   grub_usb_bulk_write (port->usbdev, port->out_endp->endp_addr, 1, &cc); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| pl2303_hw_configure (struct grub_serial_port *port, | ||||
| 			struct grub_serial_config *config) | ||||
| { | ||||
|   if (!is_speed_supported (config->speed)) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed"); | ||||
| 
 | ||||
|   if (config->parity != GRUB_SERIAL_PARITY_NONE | ||||
|       && config->parity != GRUB_SERIAL_PARITY_ODD | ||||
|       && config->parity != GRUB_SERIAL_PARITY_EVEN) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported parity"); | ||||
| 
 | ||||
|   if (config->stop_bits != GRUB_SERIAL_STOP_BITS_1 | ||||
|       && config->stop_bits != GRUB_SERIAL_STOP_BITS_2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported stop bits"); | ||||
| 
 | ||||
|   if (config->word_len < 5 || config->word_len > 8) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unsupported word length"); | ||||
| 
 | ||||
|   port->config = *config; | ||||
|   port->configured = 0; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static struct grub_serial_driver grub_pl2303_driver = | ||||
|   { | ||||
|     .configure = pl2303_hw_configure, | ||||
|     .fetch = pl2303_hw_fetch, | ||||
|     .put = pl2303_hw_put, | ||||
|     .fini = grub_usbserial_fini | ||||
|   }; | ||||
| 
 | ||||
| static const struct  | ||||
| { | ||||
|   grub_uint16_t vendor, product; | ||||
| } products[] = | ||||
|   { | ||||
|     {0x067b, 0x2303} | ||||
|   }; | ||||
| 
 | ||||
| static int | ||||
| grub_pl2303_attach (grub_usb_device_t usbdev, int configno, int interfno) | ||||
| { | ||||
|   unsigned j; | ||||
| 
 | ||||
|   for (j = 0; j < ARRAY_SIZE (products); j++) | ||||
|     if (usbdev->descdev.vendorid == products[j].vendor | ||||
| 	&& usbdev->descdev.prodid == products[j].product) | ||||
|       break; | ||||
|   if (j == ARRAY_SIZE (products)) | ||||
|     return 0; | ||||
| 
 | ||||
|   return grub_usbserial_attach (usbdev, configno, interfno, | ||||
| 				&grub_pl2303_driver); | ||||
| } | ||||
| 
 | ||||
| static struct grub_usb_attach_desc attach_hook = | ||||
| { | ||||
|   .class = 0xff, | ||||
|   .hook = grub_pl2303_attach | ||||
| }; | ||||
| 
 | ||||
| GRUB_MOD_INIT(usbserial_pl2303) | ||||
| { | ||||
|   grub_usb_register_attach_hook_class (&attach_hook); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(usbserial_pl2303) | ||||
| { | ||||
|   grub_serial_unregister_driver (&grub_pl2303_driver); | ||||
|   grub_usb_unregister_attach_hook_class (&attach_hook); | ||||
| } | ||||
							
								
								
									
										731
									
								
								grub-core/bus/usb/uhci.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										731
									
								
								grub-core/bus/usb/uhci.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,731 @@ | |||
| /* uhci.c - UHCI Support.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/usbtrans.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/i386/io.h> | ||||
| #include <grub/time.h> | ||||
| 
 | ||||
| #define GRUB_UHCI_IOMASK	(0x7FF << 5) | ||||
| 
 | ||||
| typedef enum | ||||
|   { | ||||
|     GRUB_UHCI_REG_USBCMD = 0x00, | ||||
|     GRUB_UHCI_REG_FLBASEADD = 0x08, | ||||
|     GRUB_UHCI_REG_PORTSC1 = 0x10, | ||||
|     GRUB_UHCI_REG_PORTSC2 = 0x12 | ||||
|   } grub_uhci_reg_t; | ||||
| 
 | ||||
| #define GRUB_UHCI_LINK_TERMINATE	1 | ||||
| #define GRUB_UHCI_LINK_QUEUE_HEAD	2 | ||||
| 
 | ||||
| 
 | ||||
| /* UHCI Queue Head.  */ | ||||
| struct grub_uhci_qh | ||||
| { | ||||
|   /* Queue head link pointer which points to the next queue head.  */ | ||||
|   grub_uint32_t linkptr; | ||||
| 
 | ||||
|   /* Queue element link pointer which points to the first data object
 | ||||
|      within the queue.  */ | ||||
|   grub_uint32_t elinkptr; | ||||
| 
 | ||||
|   /* Queue heads are aligned on 16 bytes, pad so a queue head is 16
 | ||||
|      bytes so we can store many in a 4K page.  */ | ||||
|   grub_uint8_t pad[8]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| /* UHCI Transfer Descriptor.  */ | ||||
| struct grub_uhci_td | ||||
| { | ||||
|   /* Pointer to the next TD in the list.  */ | ||||
|   grub_uint32_t linkptr; | ||||
| 
 | ||||
|   /* Control and status bits.  */ | ||||
|   grub_uint32_t ctrl_status; | ||||
| 
 | ||||
|   /* All information required to transfer the Token packet.  */ | ||||
|   grub_uint32_t token; | ||||
| 
 | ||||
|   /* A pointer to the data buffer, UHCI requires this pointer to be 32
 | ||||
|      bits.  */ | ||||
|   grub_uint32_t buffer; | ||||
| 
 | ||||
|   /* Another linkptr that is not overwritten by the Host Controller.
 | ||||
|      This is GRUB specific.  */ | ||||
|   grub_uint32_t linkptr2; | ||||
| 
 | ||||
|   /* 3 additional 32 bits words reserved for the Host Controller Driver.  */ | ||||
|   grub_uint32_t data[3]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| typedef volatile struct grub_uhci_td *grub_uhci_td_t; | ||||
| typedef volatile struct grub_uhci_qh *grub_uhci_qh_t; | ||||
| 
 | ||||
| struct grub_uhci | ||||
| { | ||||
|   int iobase; | ||||
|   grub_uint32_t *framelist; | ||||
| 
 | ||||
|   /* 256 Queue Heads.  */ | ||||
|   grub_uhci_qh_t qh; | ||||
| 
 | ||||
|   /* 256 Transfer Descriptors.  */ | ||||
|   grub_uhci_td_t td; | ||||
| 
 | ||||
|   /* Free Transfer Descriptors.  */ | ||||
|   grub_uhci_td_t tdfree; | ||||
| 
 | ||||
|   struct grub_uhci *next; | ||||
| }; | ||||
| 
 | ||||
| static struct grub_uhci *uhci; | ||||
| 
 | ||||
| static grub_uint16_t | ||||
| grub_uhci_readreg16 (struct grub_uhci *u, grub_uhci_reg_t reg) | ||||
| { | ||||
|   return grub_inw (u->iobase + reg); | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| static grub_uint32_t | ||||
| grub_uhci_readreg32 (struct grub_uhci *u, grub_uhci_reg_t reg) | ||||
| { | ||||
|   return grub_inl (u->iobase + reg); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static void | ||||
| grub_uhci_writereg16 (struct grub_uhci *u, | ||||
| 		      grub_uhci_reg_t reg, grub_uint16_t val) | ||||
| { | ||||
|   grub_outw (val, u->iobase + reg); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_uhci_writereg32 (struct grub_uhci *u, | ||||
| 		    grub_uhci_reg_t reg, grub_uint32_t val) | ||||
| { | ||||
|   grub_outl (val, u->iobase + reg); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_uhci_portstatus (grub_usb_controller_t dev, | ||||
| 		      unsigned int port, unsigned int enable); | ||||
| 
 | ||||
| 
 | ||||
| /* Iterate over all PCI devices.  Determine if a device is an UHCI
 | ||||
|    controller.  If this is the case, initialize it.  */ | ||||
| static int NESTED_FUNC_ATTR | ||||
| grub_uhci_pci_iter (grub_pci_device_t dev, | ||||
| 		    grub_pci_id_t pciid __attribute__((unused))) | ||||
| { | ||||
|   grub_uint32_t class_code; | ||||
|   grub_uint32_t class; | ||||
|   grub_uint32_t subclass; | ||||
|   grub_uint32_t interf; | ||||
|   grub_uint32_t base; | ||||
|   grub_uint32_t fp; | ||||
|   grub_pci_address_t addr; | ||||
|   struct grub_uhci *u; | ||||
|   int i; | ||||
| 
 | ||||
|   addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); | ||||
|   class_code = grub_pci_read (addr) >> 8; | ||||
| 
 | ||||
|   interf = class_code & 0xFF; | ||||
|   subclass = (class_code >> 8) & 0xFF; | ||||
|   class = class_code >> 16; | ||||
| 
 | ||||
|   /* If this is not an UHCI controller, just return.  */ | ||||
|   if (class != 0x0c || subclass != 0x03 || interf != 0x00) | ||||
|     return 0; | ||||
| 
 | ||||
|   /* Determine IO base address.  */ | ||||
|   addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4); | ||||
|   base = grub_pci_read (addr); | ||||
|   /* Stop if there is no IO space base address defined.  */ | ||||
|   if (! (base & 1)) | ||||
|     return 0; | ||||
| 
 | ||||
|   /* Allocate memory for the controller and register it.  */ | ||||
|   u = grub_zalloc (sizeof (*u)); | ||||
|   if (! u) | ||||
|     return 1; | ||||
| 
 | ||||
|   u->iobase = base & GRUB_UHCI_IOMASK; | ||||
| 
 | ||||
|   /* Reserve a page for the frame list.  */ | ||||
|   u->framelist = grub_memalign (4096, 4096); | ||||
|   if (! u->framelist) | ||||
|     goto fail; | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n", | ||||
| 		class, subclass, interf, u->iobase, u->framelist); | ||||
| 
 | ||||
|   /* The framelist pointer of UHCI is only 32 bits, make sure this
 | ||||
|      code works on on 64 bits architectures.  */ | ||||
| #if GRUB_CPU_SIZEOF_VOID_P == 8 | ||||
|   if ((grub_uint64_t) u->framelist >> 32) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 		  "allocated frame list memory not <4GB"); | ||||
|       goto fail; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|   /* The QH pointer of UHCI is only 32 bits, make sure this
 | ||||
|      code works on on 64 bits architectures.  */ | ||||
|   u->qh = (grub_uhci_qh_t) grub_memalign (4096, 4096); | ||||
|   if (! u->qh) | ||||
|     goto fail; | ||||
| 
 | ||||
| #if GRUB_CPU_SIZEOF_VOID_P == 8 | ||||
|   if ((grub_uint64_t) u->qh >> 32) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated QH memory not <4GB"); | ||||
|       goto fail; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|   /* The TD pointer of UHCI is only 32 bits, make sure this
 | ||||
|      code works on on 64 bits architectures.  */ | ||||
|   u->td = (grub_uhci_td_t) grub_memalign (4096, 4096*2); | ||||
|   if (! u->td) | ||||
|     goto fail; | ||||
| 
 | ||||
| #if GRUB_CPU_SIZEOF_VOID_P == 8 | ||||
|   if ((grub_uint64_t) u->td >> 32) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated TD memory not <4GB"); | ||||
|       goto fail; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "QH=%p, TD=%p\n", | ||||
| 		u->qh, u->td); | ||||
| 
 | ||||
|   /* Link all Transfer Descriptors in a list of available Transfer
 | ||||
|      Descriptors.  */ | ||||
|   for (i = 0; i < 256; i++) | ||||
|     u->td[i].linkptr = (grub_uint32_t) (grub_addr_t) &u->td[i + 1]; | ||||
|   u->td[255 - 1].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.  */ | ||||
|   fp = (grub_uint32_t) (grub_addr_t) u->qh & (~15); | ||||
|   /* Mark this as a queue head.  */ | ||||
|   fp |= 2; | ||||
|   for (i = 0; i < 1024; i++) | ||||
|     u->framelist[i] = fp; | ||||
|   /* Program the framelist address into the UHCI controller.  */ | ||||
|   grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD, | ||||
| 			(grub_uint32_t) (grub_addr_t) u->framelist); | ||||
| 
 | ||||
|   /* Make the Queue Heads point to each other.  */ | ||||
|   for (i = 0; i < 256; i++) | ||||
|     { | ||||
|       /* Point to the next QH.  */ | ||||
|       u->qh[i].linkptr = (grub_uint32_t) (grub_addr_t) (&u->qh[i + 1]) & (~15); | ||||
| 
 | ||||
|       /* This is a QH.  */ | ||||
|       u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD; | ||||
| 
 | ||||
|       /* For the moment, do not point to a Transfer Descriptor.  These
 | ||||
| 	 are set at transfer time, so just terminate it.  */ | ||||
|       u->qh[i].elinkptr = 1; | ||||
|     } | ||||
| 
 | ||||
|   /* The last Queue Head should terminate.  256 are too many QHs so
 | ||||
|      just use 50.  */ | ||||
|   u->qh[50 - 1].linkptr = 1; | ||||
| 
 | ||||
|   /* Enable UHCI again.  */ | ||||
|   grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7)); | ||||
| 
 | ||||
|   /* UHCI is initialized and ready for transfers.  */ | ||||
|   grub_dprintf ("uhci", "UHCI initialized\n"); | ||||
| 
 | ||||
| 
 | ||||
| #if 0 | ||||
|   { | ||||
|     int i; | ||||
|     for (i = 0; i < 10; i++) | ||||
|       { | ||||
| 	grub_uint16_t frnum; | ||||
| 
 | ||||
| 	frnum = grub_uhci_readreg16 (u, 6); | ||||
| 	grub_dprintf ("uhci", "Framenum=%d\n", frnum); | ||||
| 	grub_millisleep (100); | ||||
|       } | ||||
|   } | ||||
| #endif | ||||
| 
 | ||||
|   /* Link to uhci now that initialisation is successful.  */ | ||||
|   u->next = uhci; | ||||
|   uhci = u; | ||||
| 
 | ||||
|   return 0; | ||||
| 
 | ||||
|  fail: | ||||
|   if (u) | ||||
|     { | ||||
|       grub_free ((void *) u->qh); | ||||
|       grub_free (u->framelist); | ||||
|     } | ||||
|   grub_free (u); | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_uhci_inithw (void) | ||||
| { | ||||
|   grub_pci_iterate (grub_uhci_pci_iter); | ||||
| } | ||||
| 
 | ||||
| static grub_uhci_td_t | ||||
| grub_alloc_td (struct grub_uhci *u) | ||||
| { | ||||
|   grub_uhci_td_t ret; | ||||
| 
 | ||||
|   /* Check if there is a Transfer Descriptor available.  */ | ||||
|   if (! u->tdfree) | ||||
|     return NULL; | ||||
| 
 | ||||
|   ret = u->tdfree; | ||||
|   u->tdfree = (grub_uhci_td_t) (grub_addr_t) u->tdfree->linkptr; | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_free_td (struct grub_uhci *u, grub_uhci_td_t td) | ||||
| { | ||||
|   td->linkptr = (grub_uint32_t) (grub_addr_t) u->tdfree; | ||||
|   u->tdfree = td; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td, | ||||
|                  grub_usb_transfer_t transfer, grub_size_t *actual) | ||||
| { | ||||
|   int i; /* Index of TD in transfer */ | ||||
| 
 | ||||
|   *actual = 0; | ||||
|    | ||||
|   /* Free the TDs in this queue and set last_trans.  */ | ||||
|   for (i=0; td; i++) | ||||
|     { | ||||
|       grub_uhci_td_t tdprev; | ||||
| 
 | ||||
|       /* Check state of TD and possibly set last_trans */ | ||||
|       if (transfer && (td->linkptr & 1)) | ||||
|         transfer->last_trans = i; | ||||
| 
 | ||||
|       *actual += (td->ctrl_status + 1) & 0x7ff; | ||||
|        | ||||
|       /* Unlink the queue.  */ | ||||
|       tdprev = td; | ||||
|       td = (grub_uhci_td_t) (grub_addr_t) td->linkptr2; | ||||
| 
 | ||||
|       /* Free the TD.  */ | ||||
|       grub_free_td (u, tdprev); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static grub_uhci_qh_t | ||||
| grub_alloc_qh (struct grub_uhci *u, | ||||
| 	       grub_transaction_type_t tr __attribute__((unused))) | ||||
| { | ||||
|   int i; | ||||
|   grub_uhci_qh_t qh; | ||||
| 
 | ||||
|   /* Look for a Queue Head for this transfer.  Skip the first QH if
 | ||||
|      this is a Interrupt Transfer.  */ | ||||
| #if 0 | ||||
|   if (tr == GRUB_USB_TRANSACTION_TYPE_INTERRUPT) | ||||
|     i = 0; | ||||
|   else | ||||
| #endif | ||||
|     i = 1; | ||||
| 
 | ||||
|   for (; i < 255; i++) | ||||
|     { | ||||
|       if (u->qh[i].elinkptr & 1) | ||||
| 	break; | ||||
|     } | ||||
|   qh = &u->qh[i]; | ||||
|   if (! (qh->elinkptr & 1)) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 		  "no free queue heads available"); | ||||
|       return NULL; | ||||
|     } | ||||
| 
 | ||||
|   return qh; | ||||
| } | ||||
| 
 | ||||
| static grub_uhci_td_t | ||||
| grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, | ||||
| 		       grub_transfer_type_t type, unsigned int addr, | ||||
| 		       unsigned int toggle, grub_size_t size, | ||||
| 		       grub_uint32_t data) | ||||
| { | ||||
|   grub_uhci_td_t td; | ||||
|   static const unsigned int tf[] = { 0x69, 0xE1, 0x2D }; | ||||
| 
 | ||||
|   /* XXX: Check if data is <4GB.  If it isn't, just copy stuff around.
 | ||||
|      This is only relevant for 64 bits architectures.  */ | ||||
| 
 | ||||
|   /* Grab a free Transfer Descriptor and initialize it.  */ | ||||
|   td = grub_alloc_td (u); | ||||
|   if (! td) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 		  "no transfer descriptors available for UHCI transfer"); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("uhci", | ||||
| 		"transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%lu data=0x%x td=%p\n", | ||||
| 		endp, type, addr, toggle, (unsigned long) size, data, td); | ||||
| 
 | ||||
|   /* Don't point to any TD, just terminate.  */ | ||||
|   td->linkptr = 1; | ||||
| 
 | ||||
|   /* Active!  Only retry a transfer 3 times.  */ | ||||
|   td->ctrl_status = (1 << 23) | (3 << 27); | ||||
| 
 | ||||
|   /* If zero bytes are transmitted, size is 0x7FF.  Otherwise size is
 | ||||
|      size-1.  */ | ||||
|   if (size == 0) | ||||
|     size = 0x7FF; | ||||
|   else | ||||
|     size = size - 1; | ||||
| 
 | ||||
|   /* Setup whatever is required for the token packet.  */ | ||||
|   td->token = ((size << 21) | (toggle << 19) | (endp << 15) | ||||
| 	       | (addr << 8) | tf[type]); | ||||
| 
 | ||||
|   td->buffer = data; | ||||
| 
 | ||||
|   return td; | ||||
| } | ||||
| 
 | ||||
| static grub_usb_err_t | ||||
| grub_uhci_transfer (grub_usb_controller_t dev, | ||||
| 		    grub_usb_transfer_t transfer, | ||||
| 		    int timeout, grub_size_t *actual) | ||||
| { | ||||
|   struct grub_uhci *u = (struct grub_uhci *) dev->data; | ||||
|   grub_uhci_qh_t qh; | ||||
|   grub_uhci_td_t td; | ||||
|   grub_uhci_td_t td_first = NULL; | ||||
|   grub_uhci_td_t td_prev = NULL; | ||||
|   grub_usb_err_t err = GRUB_USB_ERR_NONE; | ||||
|   int i; | ||||
|   grub_uint64_t endtime; | ||||
| 
 | ||||
|   *actual = 0; | ||||
| 
 | ||||
|   /* Allocate a queue head for the transfer queue.  */ | ||||
|   qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); | ||||
|   if (! qh) | ||||
|     return GRUB_USB_ERR_INTERNAL; | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase); | ||||
|    | ||||
|   for (i = 0; i < transfer->transcnt; i++) | ||||
|     { | ||||
|       grub_usb_transaction_t tr = &transfer->transactions[i]; | ||||
| 
 | ||||
|       td = grub_uhci_transaction (u, transfer->endpoint, tr->pid, | ||||
| 				  transfer->devaddr, tr->toggle, | ||||
| 				  tr->size, tr->data); | ||||
|       if (! td) | ||||
| 	{ | ||||
| 	  /* Terminate and free.  */ | ||||
| 	  td_prev->linkptr2 = 0; | ||||
| 	  td_prev->linkptr = 1; | ||||
| 
 | ||||
| 	  if (td_first) | ||||
| 	    grub_free_queue (u, td_first, NULL, actual); | ||||
| 
 | ||||
| 	  return GRUB_USB_ERR_INTERNAL; | ||||
| 	} | ||||
| 
 | ||||
|       if (! td_first) | ||||
| 	td_first = td; | ||||
|       else | ||||
| 	{ | ||||
| 	  td_prev->linkptr2 = (grub_uint32_t) (grub_addr_t) td; | ||||
| 	  td_prev->linkptr = (grub_uint32_t) (grub_addr_t) td; | ||||
| 	  td_prev->linkptr |= 4; | ||||
| 	} | ||||
|       td_prev = td; | ||||
|     } | ||||
|   td_prev->linkptr2 = 0; | ||||
|   td_prev->linkptr = 1; | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "setup transaction %d\n", transfer->type); | ||||
| 
 | ||||
|   /* Link it into the queue and terminate.  Now the transaction can
 | ||||
|      take place.  */ | ||||
|   qh->elinkptr = (grub_uint32_t) (grub_addr_t) td_first; | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "initiate transaction\n"); | ||||
| 
 | ||||
|   /* Wait until either the transaction completed or an error
 | ||||
|      occurred.  */ | ||||
|   endtime = grub_get_time_ms () + timeout; | ||||
|   for (;;) | ||||
|     { | ||||
|       grub_uhci_td_t errtd; | ||||
| 
 | ||||
|       errtd = (grub_uhci_td_t) (grub_addr_t) (qh->elinkptr & ~0x0f); | ||||
| 
 | ||||
|       grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", | ||||
| 		    errtd->ctrl_status, errtd->buffer & (~15), errtd); | ||||
| 
 | ||||
|       /* Check if the transaction completed.  */ | ||||
|       if (qh->elinkptr & 1) | ||||
| 	break; | ||||
| 
 | ||||
|       grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); | ||||
| 
 | ||||
|       /* Check if the endpoint is stalled.  */ | ||||
|       if (errtd->ctrl_status & (1 << 22)) | ||||
| 	err = GRUB_USB_ERR_STALL; | ||||
| 
 | ||||
|       /* Check if an error related to the data buffer occurred.  */ | ||||
|       if (errtd->ctrl_status & (1 << 21)) | ||||
| 	err = GRUB_USB_ERR_DATA; | ||||
| 
 | ||||
|       /* Check if a babble error occurred.  */ | ||||
|       if (errtd->ctrl_status & (1 << 20)) | ||||
| 	err = GRUB_USB_ERR_BABBLE; | ||||
| 
 | ||||
|       /* Check if a NAK occurred.  */ | ||||
|       if (errtd->ctrl_status & (1 << 19)) | ||||
| 	err = GRUB_USB_ERR_NAK; | ||||
| 
 | ||||
|       /* Check if a timeout occurred.  */ | ||||
|       if (errtd->ctrl_status & (1 << 18)) | ||||
| 	err = GRUB_USB_ERR_TIMEOUT; | ||||
| 
 | ||||
|       /* Check if a bitstuff error occurred.  */ | ||||
|       if (errtd->ctrl_status & (1 << 17)) | ||||
| 	err = GRUB_USB_ERR_BITSTUFF; | ||||
| 
 | ||||
|       if (err) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       /* Fall through, no errors occurred, so the QH might be
 | ||||
| 	 updated.  */ | ||||
|       grub_dprintf ("uhci", "transaction fallthrough\n"); | ||||
| 
 | ||||
|       if (grub_get_time_ms () > endtime) | ||||
| 	{ | ||||
| 	  err = GRUB_USB_ERR_STALL; | ||||
| 	  grub_dprintf ("uhci", "transaction timed out\n"); | ||||
| 	  goto fail; | ||||
| 	} | ||||
|       grub_cpu_idle (); | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "transaction complete\n"); | ||||
| 
 | ||||
|  fail: | ||||
| 
 | ||||
|   if (err != GRUB_USB_ERR_NONE) | ||||
|     grub_dprintf ("uhci", "transaction failed\n"); | ||||
| 
 | ||||
|   /* Place the QH back in the free list and deallocate the associated
 | ||||
|      TDs.  */ | ||||
|   qh->elinkptr = 1; | ||||
|   grub_free_queue (u, td_first, transfer, actual); | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_uhci_iterate (int (*hook) (grub_usb_controller_t dev)) | ||||
| { | ||||
|   struct grub_uhci *u; | ||||
|   struct grub_usb_controller dev; | ||||
| 
 | ||||
|   for (u = uhci; u; u = u->next) | ||||
|     { | ||||
|       dev.data = u; | ||||
|       if (hook (&dev)) | ||||
| 	return 1; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_uhci_portstatus (grub_usb_controller_t dev, | ||||
| 		      unsigned int port, unsigned int enable) | ||||
| { | ||||
|   struct grub_uhci *u = (struct grub_uhci *) dev->data; | ||||
|   int reg; | ||||
|   unsigned int status; | ||||
|   grub_uint64_t endtime; | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "portstatus, iobase:%08x\n", u->iobase); | ||||
|    | ||||
|   grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port); | ||||
| 
 | ||||
|   if (port == 0) | ||||
|     reg = GRUB_UHCI_REG_PORTSC1; | ||||
|   else if (port == 1) | ||||
|     reg = GRUB_UHCI_REG_PORTSC2; | ||||
|   else | ||||
|     return grub_error (GRUB_ERR_OUT_OF_RANGE, | ||||
| 		       "UHCI Root Hub port does not exist"); | ||||
| 
 | ||||
|   status = grub_uhci_readreg16 (u, reg); | ||||
|   grub_dprintf ("uhci", "detect=0x%02x\n", status); | ||||
| 
 | ||||
|   if (!enable) /* We don't need reset port */ | ||||
|     { | ||||
|       /* Disable the port.  */ | ||||
|       grub_uhci_writereg16 (u, reg, 0 << 2); | ||||
|       grub_dprintf ("uhci", "waiting for the port to be disabled\n"); | ||||
|       endtime = grub_get_time_ms () + 1000; | ||||
|       while ((grub_uhci_readreg16 (u, reg) & (1 << 2))) | ||||
|         if (grub_get_time_ms () > endtime) | ||||
|           return grub_error (GRUB_ERR_IO, "UHCI Timed out"); | ||||
| 
 | ||||
|       status = grub_uhci_readreg16 (u, reg); | ||||
|       grub_dprintf ("uhci", ">3detect=0x%02x\n", status); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|      | ||||
|   /* Reset the port.  */ | ||||
|   grub_uhci_writereg16 (u, reg, 1 << 9); | ||||
| 
 | ||||
|   /* Wait for the reset to complete.  XXX: How long exactly?  */ | ||||
|   grub_millisleep (50); /* For root hub should be nominaly 50ms */ | ||||
|   status = grub_uhci_readreg16 (u, reg); | ||||
|   grub_uhci_writereg16 (u, reg, status & ~(1 << 9)); | ||||
|   grub_dprintf ("uhci", "reset completed\n"); | ||||
|   grub_millisleep (10); | ||||
| 
 | ||||
|   /* Enable the port.  */ | ||||
|   grub_uhci_writereg16 (u, reg, 1 << 2); | ||||
|   grub_millisleep (10); | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "waiting for the port to be enabled\n"); | ||||
| 
 | ||||
|   endtime = grub_get_time_ms () + 1000; | ||||
|   while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2))) | ||||
|     if (grub_get_time_ms () > endtime) | ||||
|       return grub_error (GRUB_ERR_IO, "UHCI Timed out"); | ||||
| 
 | ||||
|   /* Reset bit Connect Status Change */ | ||||
|   grub_uhci_writereg16 (u, reg, status | (1 << 1)); | ||||
| 
 | ||||
|   /* Read final port status */ | ||||
|   status = grub_uhci_readreg16 (u, reg); | ||||
|   grub_dprintf ("uhci", ">3detect=0x%02x\n", status); | ||||
| 
 | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_usb_speed_t | ||||
| grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) | ||||
| { | ||||
|   struct grub_uhci *u = (struct grub_uhci *) dev->data; | ||||
|   int reg; | ||||
|   unsigned int status; | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "detect_dev, iobase:%08x\n", u->iobase); | ||||
|    | ||||
|   if (port == 0) | ||||
|     reg = GRUB_UHCI_REG_PORTSC1; | ||||
|   else if (port == 1) | ||||
|     reg = GRUB_UHCI_REG_PORTSC2; | ||||
|   else | ||||
|     return grub_error (GRUB_ERR_OUT_OF_RANGE, | ||||
| 		       "UHCI Root Hub port does not exist"); | ||||
| 
 | ||||
|   status = grub_uhci_readreg16 (u, reg); | ||||
| 
 | ||||
|   grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port); | ||||
| 
 | ||||
|   /* Connect Status Change bit - it detects change of connection */ | ||||
|   *changed = ((status & (1 << 1)) != 0); | ||||
|      | ||||
|   if (! (status & 1)) | ||||
|     return GRUB_USB_SPEED_NONE; | ||||
|   else if (status & (1 << 8)) | ||||
|     return GRUB_USB_SPEED_LOW; | ||||
|   else | ||||
|     return GRUB_USB_SPEED_FULL; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_uhci_hubports (grub_usb_controller_t dev __attribute__((unused))) | ||||
| { | ||||
|   /* The root hub has exactly two ports.  */ | ||||
|   return 2; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| static struct grub_usb_controller_dev usb_controller = | ||||
| { | ||||
|   .name = "uhci", | ||||
|   .iterate = grub_uhci_iterate, | ||||
|   .transfer = grub_uhci_transfer, | ||||
|   .hubports = grub_uhci_hubports, | ||||
|   .portstatus = grub_uhci_portstatus, | ||||
|   .detect_dev = grub_uhci_detect_dev | ||||
| }; | ||||
| 
 | ||||
| GRUB_MOD_INIT(uhci) | ||||
| { | ||||
|   grub_uhci_inithw (); | ||||
|   grub_usb_controller_dev_register (&usb_controller); | ||||
|   grub_dprintf ("uhci", "registered\n"); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(uhci) | ||||
| { | ||||
|   struct grub_uhci *u; | ||||
| 
 | ||||
|   /* Disable all UHCI controllers.  */ | ||||
|   for (u = uhci; u; u = u->next) | ||||
|     grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0); | ||||
| 
 | ||||
|   /* Unregister the controller.  */ | ||||
|   grub_usb_controller_dev_unregister (&usb_controller); | ||||
| } | ||||
							
								
								
									
										347
									
								
								grub-core/bus/usb/usb.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								grub-core/bus/usb/usb.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,347 @@ | |||
| /* usb.c - Generic USB interfaces.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/list.h> | ||||
| #include <grub/term.h> | ||||
| 
 | ||||
| static grub_usb_controller_dev_t grub_usb_list; | ||||
| struct grub_usb_attach_desc *attach_hooks; | ||||
| 
 | ||||
| void | ||||
| grub_usb_controller_dev_register (grub_usb_controller_dev_t usb) | ||||
| { | ||||
|   auto int iterate_hook (grub_usb_controller_t dev); | ||||
| 
 | ||||
|   /* Iterate over all controllers found by the driver.  */ | ||||
|   int iterate_hook (grub_usb_controller_t dev) | ||||
|     { | ||||
|       dev->dev = usb; | ||||
| 
 | ||||
|       /* Enable the ports of the USB Root Hub.  */ | ||||
|       grub_usb_root_hub (dev); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   usb->next = grub_usb_list; | ||||
|   grub_usb_list = usb; | ||||
| 
 | ||||
|   if (usb->iterate) | ||||
|     usb->iterate (iterate_hook); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb) | ||||
| { | ||||
|   grub_usb_controller_dev_t *p, q; | ||||
| 
 | ||||
|   for (p = &grub_usb_list, q = *p; q; p = &(q->next), q = q->next) | ||||
|     if (q == usb) | ||||
|       { | ||||
| 	*p = q->next; | ||||
| 	break; | ||||
|       } | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| int | ||||
| grub_usb_controller_iterate (int (*hook) (grub_usb_controller_t dev)) | ||||
| { | ||||
|   grub_usb_controller_dev_t p; | ||||
| 
 | ||||
|   auto int iterate_hook (grub_usb_controller_t dev); | ||||
| 
 | ||||
|   int iterate_hook (grub_usb_controller_t dev) | ||||
|     { | ||||
|       dev->dev = p; | ||||
|       if (hook (dev)) | ||||
| 	return 1; | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   /* Iterate over all controller drivers.  */ | ||||
|   for (p = grub_usb_list; p; p = p->next) | ||||
|     { | ||||
|       /* Iterate over the busses of the controllers.  XXX: Actually, a
 | ||||
| 	 hub driver should do this.  */ | ||||
|       if (p->iterate (iterate_hook)) | ||||
| 	return 1; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| grub_usb_err_t | ||||
| grub_usb_clear_halt (grub_usb_device_t dev, int endpoint) | ||||
| { | ||||
|   dev->toggle[endpoint] = 0; | ||||
|   return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
| 				     | GRUB_USB_REQTYPE_STANDARD | ||||
| 				     | GRUB_USB_REQTYPE_TARGET_ENDP), | ||||
| 			       GRUB_USB_REQ_CLEAR_FEATURE, | ||||
| 			       GRUB_USB_FEATURE_ENDP_HALT, | ||||
| 			       endpoint, 0, 0); | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_set_configuration (grub_usb_device_t dev, int configuration) | ||||
| { | ||||
|   grub_memset (dev->toggle, 0, sizeof (dev->toggle)); | ||||
| 
 | ||||
|   return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
| 				     | GRUB_USB_REQTYPE_STANDARD | ||||
| 				     | GRUB_USB_REQTYPE_TARGET_DEV), | ||||
| 			       GRUB_USB_REQ_SET_CONFIGURATION, configuration, | ||||
| 			       0, 0, NULL); | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_get_descriptor (grub_usb_device_t dev, | ||||
| 			 grub_uint8_t type, grub_uint8_t index, | ||||
| 			 grub_size_t size, char *data) | ||||
| { | ||||
|   return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | ||||
| 				     | GRUB_USB_REQTYPE_STANDARD | ||||
| 				     | GRUB_USB_REQTYPE_TARGET_DEV), | ||||
| 			       GRUB_USB_REQ_GET_DESCRIPTOR, | ||||
| 			       (type << 8) | index, | ||||
| 			       0, size, data); | ||||
| } | ||||
| 
 | ||||
| struct grub_usb_desc_endp * | ||||
| grub_usb_get_endpdescriptor (grub_usb_device_t usbdev, int addr) | ||||
| { | ||||
|   int i; | ||||
| 
 | ||||
|   for (i = 0; i < usbdev->config[0].descconf->numif; i++) | ||||
|     { | ||||
|       struct grub_usb_desc_if *interf; | ||||
|       int j; | ||||
| 
 | ||||
|       interf = usbdev->config[0].interf[i].descif; | ||||
| 
 | ||||
|       for (j = 0; j < interf->endpointcnt; j++) | ||||
| 	{ | ||||
| 	  struct grub_usb_desc_endp *endp; | ||||
| 	  endp = &usbdev->config[0].interf[i].descendp[j]; | ||||
| 
 | ||||
| 	  if (endp->endp_addr == addr) | ||||
| 	    return endp; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return NULL; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_device_initialize (grub_usb_device_t dev) | ||||
| { | ||||
|   struct grub_usb_desc_device *descdev; | ||||
|   struct grub_usb_desc_config config; | ||||
|   grub_usb_err_t err; | ||||
|   int i; | ||||
| 
 | ||||
|   /* First we have to read first 8 bytes only and determine
 | ||||
|    * max. size of packet */ | ||||
|   dev->descdev.maxsize0 = 0; /* invalidating, for safety only, can be removed if it is sure it is zero here */ | ||||
|   err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE, | ||||
|                                  0, 8, (char *) &dev->descdev); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   /* Now we have valid value in dev->descdev.maxsize0,
 | ||||
|    * so we can read whole device descriptor */ | ||||
|   err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE, | ||||
| 				 0, sizeof (struct grub_usb_desc_device), | ||||
| 				 (char *) &dev->descdev); | ||||
|   if (err) | ||||
|     return err; | ||||
|   descdev = &dev->descdev; | ||||
| 
 | ||||
|   for (i = 0; i < 8; i++) | ||||
|     dev->config[i].descconf = NULL; | ||||
| 
 | ||||
|   for (i = 0; i < descdev->configcnt; i++) | ||||
|     { | ||||
|       int pos; | ||||
|       int currif; | ||||
|       char *data; | ||||
| 
 | ||||
|       /* First just read the first 4 bytes of the configuration
 | ||||
| 	 descriptor, after that it is known how many bytes really have | ||||
| 	 to be read.  */ | ||||
|       err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_CONFIG, i, 4, | ||||
| 				     (char *) &config); | ||||
| 
 | ||||
|       data = grub_malloc (config.totallen); | ||||
|       if (! data) | ||||
| 	{ | ||||
| 	  err = GRUB_USB_ERR_INTERNAL; | ||||
| 	  goto fail; | ||||
| 	} | ||||
| 
 | ||||
|       dev->config[i].descconf = (struct grub_usb_desc_config *) data; | ||||
|       err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_CONFIG, i, | ||||
| 				     config.totallen, data); | ||||
|       if (err) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       /* Skip the configuration descriptor.  */ | ||||
|       pos = dev->config[i].descconf->length; | ||||
| 
 | ||||
|       /* Read all interfaces.  */ | ||||
|       for (currif = 0; currif < dev->config[i].descconf->numif; currif++) | ||||
| 	{ | ||||
| 	  while (pos < config.totallen | ||||
| 		 && ((struct grub_usb_desc *)&data[pos])->type | ||||
| 		 != GRUB_USB_DESCRIPTOR_INTERFACE) | ||||
| 	    pos += ((struct grub_usb_desc *)&data[pos])->length; | ||||
| 	  dev->config[i].interf[currif].descif | ||||
| 	    = (struct grub_usb_desc_if *) &data[pos]; | ||||
| 	  pos += dev->config[i].interf[currif].descif->length; | ||||
| 
 | ||||
| 	  while (pos < config.totallen | ||||
| 		 && ((struct grub_usb_desc *)&data[pos])->type | ||||
| 		 != GRUB_USB_DESCRIPTOR_ENDPOINT) | ||||
| 	    pos += ((struct grub_usb_desc *)&data[pos])->length; | ||||
| 
 | ||||
| 	  /* Point to the first endpoint.  */ | ||||
| 	  dev->config[i].interf[currif].descendp | ||||
| 	    = (struct grub_usb_desc_endp *) &data[pos]; | ||||
| 	  pos += (sizeof (struct grub_usb_desc_endp) | ||||
| 		  * dev->config[i].interf[currif].descif->endpointcnt); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| 
 | ||||
|  fail: | ||||
| 
 | ||||
|   for (i = 0; i < 8; i++) | ||||
|     grub_free (dev->config[i].descconf); | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| void grub_usb_device_attach (grub_usb_device_t dev) | ||||
| { | ||||
|   int i; | ||||
|    | ||||
|   /* XXX: Just check configuration 0 for now.  */ | ||||
|   for (i = 0; i < dev->config[0].descconf->numif; i++) | ||||
|     { | ||||
|       struct grub_usb_desc_if *interf; | ||||
|       struct grub_usb_attach_desc *desc; | ||||
| 
 | ||||
|       interf = dev->config[0].interf[i].descif; | ||||
| 
 | ||||
|       grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n", | ||||
| 		    i, interf->class, interf->subclass, interf->protocol); | ||||
| 
 | ||||
|       if (dev->config[0].interf[i].attached) | ||||
| 	continue; | ||||
| 
 | ||||
|       for (desc = attach_hooks; desc; desc = desc->next) | ||||
| 	if (interf->class == desc->class && desc->hook (dev, 0, i)) | ||||
| 	  dev->config[0].interf[i].attached = 1; | ||||
| 
 | ||||
|       if (dev->config[0].interf[i].attached) | ||||
| 	continue; | ||||
| 
 | ||||
|       switch (interf->class) | ||||
| 	{ | ||||
| 	case GRUB_USB_CLASS_MASS_STORAGE: | ||||
| 	  grub_dl_load ("usbms"); | ||||
| 	  break; | ||||
| 	case GRUB_USB_CLASS_HID: | ||||
| 	  grub_dl_load ("usb_keyboard"); | ||||
| 	  break; | ||||
| 	case 0xff: | ||||
| 	  /* FIXME: don't load useless modules.  */ | ||||
| 	  grub_dl_load ("usbserial_ftdi"); | ||||
| 	  grub_dl_load ("usbserial_pl2303"); | ||||
| 	  break; | ||||
| 	} | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc) | ||||
| { | ||||
|   auto int usb_iterate (grub_usb_device_t dev); | ||||
| 
 | ||||
|   int usb_iterate (grub_usb_device_t usbdev) | ||||
|     { | ||||
|       struct grub_usb_desc_device *descdev = &usbdev->descdev; | ||||
|       int i; | ||||
| 
 | ||||
|       if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0 | ||||
| 	  || descdev->configcnt == 0) | ||||
| 	return 0; | ||||
| 
 | ||||
|       /* XXX: Just check configuration 0 for now.  */ | ||||
|       for (i = 0; i < usbdev->config[0].descconf->numif; i++) | ||||
| 	{ | ||||
| 	  struct grub_usb_desc_if *interf; | ||||
| 
 | ||||
| 	  interf = usbdev->config[0].interf[i].descif; | ||||
| 
 | ||||
| 	  grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n", | ||||
| 	                i, interf->class, interf->subclass, interf->protocol); | ||||
| 
 | ||||
| 	  if (usbdev->config[0].interf[i].attached) | ||||
| 	    continue; | ||||
| 
 | ||||
| 	  if (interf->class != desc->class) | ||||
| 	    continue; | ||||
| 	  if (desc->hook (usbdev, 0, i)) | ||||
| 	    usbdev->config[0].interf[i].attached = 1; | ||||
| 	} | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   desc->next = attach_hooks; | ||||
|   attach_hooks = desc; | ||||
| 
 | ||||
|   grub_usb_iterate (usb_iterate); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc) | ||||
| { | ||||
|   grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc));   | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| GRUB_MOD_INIT(usb) | ||||
| { | ||||
|   grub_term_poll_usb = grub_usb_poll_devices; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(usb) | ||||
| { | ||||
|   grub_term_poll_usb = NULL; | ||||
| } | ||||
							
								
								
									
										521
									
								
								grub-core/bus/usb/usbhub.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								grub-core/bus/usb/usbhub.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,521 @@ | |||
| /* usb.c - USB Hub Support.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/time.h> | ||||
| 
 | ||||
| #define GRUB_USBHUB_MAX_DEVICES 128 | ||||
| 
 | ||||
| /* USB Supports 127 devices, with device 0 as special case.  */ | ||||
| static struct grub_usb_device *grub_usb_devs[GRUB_USBHUB_MAX_DEVICES]; | ||||
| 
 | ||||
| struct grub_usb_hub | ||||
| { | ||||
|   struct grub_usb_hub *next; | ||||
|   grub_usb_controller_t controller; | ||||
|   int nports; | ||||
|   struct grub_usb_device **devices; | ||||
|   grub_usb_device_t dev; | ||||
| }; | ||||
| 
 | ||||
| struct grub_usb_hub *hubs; | ||||
| 
 | ||||
| /* Add a device that currently has device number 0 and resides on
 | ||||
|    CONTROLLER, the Hub reported that the device speed is SPEED.  */ | ||||
| static grub_usb_device_t | ||||
| grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) | ||||
| { | ||||
|   grub_usb_device_t dev; | ||||
|   int i; | ||||
|   grub_usb_err_t err; | ||||
| 
 | ||||
|   dev = grub_zalloc (sizeof (struct grub_usb_device)); | ||||
|   if (! dev) | ||||
|     return NULL; | ||||
| 
 | ||||
|   dev->controller = *controller; | ||||
|   dev->speed = speed; | ||||
| 
 | ||||
|   err = grub_usb_device_initialize (dev); | ||||
|   if (err) | ||||
|     { | ||||
|       grub_free (dev); | ||||
|       return NULL; | ||||
|     } | ||||
| 
 | ||||
|   /* Assign a new address to the device.  */ | ||||
|   for (i = 1; i < GRUB_USBHUB_MAX_DEVICES; i++) | ||||
|     { | ||||
|       if (! grub_usb_devs[i]) | ||||
| 	break; | ||||
|     } | ||||
|   if (i == GRUB_USBHUB_MAX_DEVICES) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_IO, "can't assign address to USB device"); | ||||
|       for (i = 0; i < 8; i++) | ||||
|         grub_free (dev->config[i].descconf); | ||||
|       grub_free (dev); | ||||
|       return NULL; | ||||
|     } | ||||
| 
 | ||||
|   err = grub_usb_control_msg (dev, | ||||
| 			      (GRUB_USB_REQTYPE_OUT | ||||
| 			       | GRUB_USB_REQTYPE_STANDARD | ||||
| 			       | GRUB_USB_REQTYPE_TARGET_DEV), | ||||
| 			      GRUB_USB_REQ_SET_ADDRESS, | ||||
| 			      i, 0, 0, NULL); | ||||
|   if (err) | ||||
|     { | ||||
|       for (i = 0; i < 8; i++) | ||||
|         grub_free (dev->config[i].descconf); | ||||
|       grub_free (dev); | ||||
|       return NULL; | ||||
|     } | ||||
| 
 | ||||
|   dev->addr = i; | ||||
|   dev->initialized = 1; | ||||
|   grub_usb_devs[i] = dev; | ||||
| 
 | ||||
|   /* Wait "recovery interval", spec. says 2ms */ | ||||
|   grub_millisleep (2); | ||||
|    | ||||
|   grub_usb_device_attach (dev); | ||||
|    | ||||
|   return dev; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| static grub_usb_err_t | ||||
| grub_usb_add_hub (grub_usb_device_t dev) | ||||
| { | ||||
|   struct grub_usb_usb_hubdesc hubdesc; | ||||
|   grub_err_t err; | ||||
|   int i; | ||||
|   grub_uint64_t timeout; | ||||
|   grub_usb_device_t next_dev; | ||||
|   grub_usb_device_t *attached_devices; | ||||
|    | ||||
|   err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | ||||
| 	  		            | GRUB_USB_REQTYPE_CLASS | ||||
| 			            | GRUB_USB_REQTYPE_TARGET_DEV), | ||||
|                               GRUB_USB_REQ_GET_DESCRIPTOR, | ||||
| 			      (GRUB_USB_DESCRIPTOR_HUB << 8) | 0, | ||||
| 			      0, sizeof (hubdesc), (char *) &hubdesc); | ||||
|   if (err) | ||||
|     return err; | ||||
|   grub_dprintf ("usb", "Hub descriptor:\n\t\t len:%d, typ:0x%02x, cnt:%d, char:0x%02x, pwg:%d, curr:%d\n", | ||||
|                 hubdesc.length, hubdesc.type, hubdesc.portcnt, | ||||
|                 hubdesc.characteristics, hubdesc.pwdgood, | ||||
|                 hubdesc.current); | ||||
| 
 | ||||
|   /* Activate the first configuration. Hubs should have only one conf. */ | ||||
|   grub_dprintf ("usb", "Hub set configuration\n"); | ||||
|   grub_usb_set_configuration (dev, 1); | ||||
| 
 | ||||
|   attached_devices = grub_zalloc (hubdesc.portcnt | ||||
| 				  * sizeof (attached_devices[0])); | ||||
|   if (!attached_devices) | ||||
|     return GRUB_USB_ERR_INTERNAL; | ||||
|   dev->children = attached_devices; | ||||
|   dev->nports = hubdesc.portcnt; | ||||
| 
 | ||||
|   /* Power on all Hub ports.  */ | ||||
|   for (i = 1; i <= hubdesc.portcnt; i++) | ||||
|     { | ||||
|       grub_dprintf ("usb", "Power on - port %d\n", i); | ||||
|       /* Power on the port and wait for possible device connect */ | ||||
|       err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
| 					| GRUB_USB_REQTYPE_CLASS | ||||
| 					| GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				  GRUB_USB_REQ_SET_FEATURE, | ||||
| 				  GRUB_USB_HUB_FEATURE_PORT_POWER, | ||||
| 				  i, 0, NULL); | ||||
|       /* Just ignore the device if some error happened */ | ||||
|       if (err) | ||||
| 	continue; | ||||
|     } | ||||
|   /* Wait for port power-on */ | ||||
|   if (hubdesc.pwdgood >= 50) | ||||
|     grub_millisleep (hubdesc.pwdgood * 2); | ||||
|   else | ||||
|     grub_millisleep (100); | ||||
|      | ||||
|   /* Iterate over the Hub ports.  */ | ||||
|   for (i = 1; i <= hubdesc.portcnt; i++) | ||||
|     { | ||||
|       grub_uint32_t status; | ||||
| 
 | ||||
|       /* Get the port status.  */ | ||||
|       err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | ||||
| 					| GRUB_USB_REQTYPE_CLASS | ||||
| 					| GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				  GRUB_USB_REQ_GET_STATUS, | ||||
| 				  0, i, sizeof (status), (char *) &status); | ||||
|       /* Just ignore the device if the Hub does not report the
 | ||||
| 	 status.  */ | ||||
|       if (err) | ||||
| 	continue; | ||||
|       grub_dprintf ("usb", "Hub port %d status: 0x%02x\n", i, status); | ||||
| 
 | ||||
|       /* If connected, reset and enable the port.  */ | ||||
|       if (status & GRUB_USB_HUB_STATUS_CONNECTED) | ||||
| 	{ | ||||
| 	  grub_usb_speed_t speed; | ||||
| 
 | ||||
| 	  /* Determine the device speed.  */ | ||||
| 	  if (status & GRUB_USB_HUB_STATUS_LOWSPEED) | ||||
| 	    speed = GRUB_USB_SPEED_LOW; | ||||
| 	  else | ||||
| 	    { | ||||
| 	      if (status & GRUB_USB_HUB_STATUS_HIGHSPEED) | ||||
| 		speed = GRUB_USB_SPEED_HIGH; | ||||
| 	      else | ||||
| 		speed = GRUB_USB_SPEED_FULL; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* A device is actually connected to this port.
 | ||||
| 	   * Now do reset of port. */ | ||||
|           grub_dprintf ("usb", "Reset hub port - port %d\n", i); | ||||
| 	  err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
| 					    | GRUB_USB_REQTYPE_CLASS | ||||
| 					    | GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				      GRUB_USB_REQ_SET_FEATURE, | ||||
| 				      GRUB_USB_HUB_FEATURE_PORT_RESET, | ||||
| 				      i, 0, 0); | ||||
| 	  /* If the Hub does not cooperate for this port, just skip
 | ||||
| 	     the port.  */ | ||||
| 	  if (err) | ||||
| 	    continue; | ||||
| 
 | ||||
|           /* Wait for reset procedure done */ | ||||
|           timeout = grub_get_time_ms () + 1000; | ||||
|           do | ||||
|             { | ||||
|               /* Get the port status.  */ | ||||
|               err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | ||||
| 	   	 			        | GRUB_USB_REQTYPE_CLASS | ||||
| 					        | GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				          GRUB_USB_REQ_GET_STATUS, | ||||
| 				          0, i, sizeof (status), (char *) &status); | ||||
|             } | ||||
|           while (!err && | ||||
|                  !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) && | ||||
|                  (grub_get_time_ms() < timeout) ); | ||||
|           if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) ) | ||||
|             continue; | ||||
| 
 | ||||
|           /* Wait a recovery time after reset, spec. says 10ms */ | ||||
|           grub_millisleep (10); | ||||
|     | ||||
|           /* Do reset of connection change bit */ | ||||
|           err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
|                                             | GRUB_USB_REQTYPE_CLASS | ||||
|                                             | GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
|                                       GRUB_USB_REQ_CLEAR_FEATURE, | ||||
| 				      GRUB_USB_HUB_FEATURE_C_CONNECTED, | ||||
| 				      i, 0, 0); | ||||
|           /* Just ignore the device if the Hub reports some error */ | ||||
|           if (err) | ||||
| 	     continue; | ||||
|           grub_dprintf ("usb", "Hub port - cleared connection change\n"); | ||||
| 
 | ||||
| 	  /* Add the device and assign a device address to it.  */ | ||||
|           grub_dprintf ("usb", "Call hub_add_dev - port %d\n", i); | ||||
| 	  next_dev = grub_usb_hub_add_dev (&dev->controller, speed); | ||||
|           if (! next_dev) | ||||
|             continue; | ||||
| 
 | ||||
| 	  attached_devices[i - 1] = next_dev; | ||||
| 
 | ||||
|           /* If the device is a Hub, scan it for more devices.  */ | ||||
|           if (next_dev->descdev.class == 0x09) | ||||
|             grub_usb_add_hub (next_dev); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| attach_root_port (struct grub_usb_hub *hub, int portno, | ||||
| 		  grub_usb_speed_t speed) | ||||
| { | ||||
|   grub_usb_device_t dev; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   /* Disable the port. XXX: Why? */ | ||||
|   err = hub->controller->dev->portstatus (hub->controller, portno, 0); | ||||
|   if (err) | ||||
|     return; | ||||
| 
 | ||||
|   /* Enable the port.  */ | ||||
|   err = hub->controller->dev->portstatus (hub->controller, portno, 1); | ||||
|   if (err) | ||||
|     return; | ||||
| 
 | ||||
|   /* Enable the port and create a device.  */ | ||||
|   dev = grub_usb_hub_add_dev (hub->controller, speed); | ||||
|   if (! dev) | ||||
|     return; | ||||
| 
 | ||||
|   hub->devices[portno] = dev; | ||||
| 
 | ||||
|   /* If the device is a Hub, scan it for more devices.  */ | ||||
|   if (dev->descdev.class == 0x09) | ||||
|     grub_usb_add_hub (dev); | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_root_hub (grub_usb_controller_t controller) | ||||
| { | ||||
|   int i; | ||||
|   struct grub_usb_hub *hub; | ||||
|   int changed=0; | ||||
| 
 | ||||
|   hub = grub_malloc (sizeof (*hub)); | ||||
|   if (!hub) | ||||
|     return GRUB_USB_ERR_INTERNAL; | ||||
| 
 | ||||
|   hub->next = hubs; | ||||
|   hubs = hub; | ||||
|   hub->controller = grub_malloc (sizeof (*controller)); | ||||
|   if (!hub->controller) | ||||
|     { | ||||
|       grub_free (hub); | ||||
|       return GRUB_USB_ERR_INTERNAL; | ||||
|     } | ||||
| 
 | ||||
|   grub_memcpy (hub->controller, controller, sizeof (*controller)); | ||||
|   hub->dev = 0; | ||||
| 
 | ||||
|   /* Query the number of ports the root Hub has.  */ | ||||
|   hub->nports = controller->dev->hubports (controller); | ||||
|   hub->devices = grub_zalloc (sizeof (hub->devices[0]) * hub->nports); | ||||
|   if (!hub->devices) | ||||
|     { | ||||
|       grub_free (hub->controller); | ||||
|       grub_free (hub); | ||||
|       return GRUB_USB_ERR_INTERNAL; | ||||
|     } | ||||
| 
 | ||||
|   for (i = 0; i < hub->nports; i++) | ||||
|     { | ||||
|       grub_usb_speed_t speed; | ||||
|       speed = controller->dev->detect_dev (hub->controller, i, | ||||
| 					   &changed); | ||||
| 
 | ||||
|       if (speed != GRUB_USB_SPEED_NONE) | ||||
| 	attach_root_port (hub, i, speed); | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void detach_device (grub_usb_device_t dev); | ||||
| 
 | ||||
| static void | ||||
| detach_device (grub_usb_device_t dev) | ||||
| { | ||||
|   unsigned i; | ||||
|   int k; | ||||
|   if (!dev) | ||||
|     return; | ||||
|   if (dev->descdev.class == GRUB_USB_CLASS_HUB) | ||||
|     { | ||||
|       for (i = 0; i < dev->nports; i++) | ||||
| 	detach_device (dev->children[i]); | ||||
|       grub_free (dev->children); | ||||
|     } | ||||
|   for (i = 0; i < ARRAY_SIZE (dev->config); i++) | ||||
|     if (dev->config[i].descconf) | ||||
|       for (k = 0; k < dev->config[i].descconf->numif; k++) | ||||
| 	{ | ||||
| 	  struct grub_usb_interface *inter = &dev->config[i].interf[k]; | ||||
| 	  if (inter && inter->detach_hook) | ||||
| 	    inter->detach_hook (dev, i, k); | ||||
| 	} | ||||
|   grub_usb_devs[dev->addr] = 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| poll_nonroot_hub (grub_usb_device_t dev) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   unsigned i; | ||||
|   grub_uint64_t timeout; | ||||
|   grub_usb_device_t next_dev; | ||||
|   grub_usb_device_t *attached_devices = dev->children; | ||||
|        | ||||
|   /* Iterate over the Hub ports.  */ | ||||
|   for (i = 1; i <= dev->nports; i++) | ||||
|     { | ||||
|       grub_uint32_t status; | ||||
| 
 | ||||
|       /* Get the port status.  */ | ||||
|       err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | ||||
| 					| GRUB_USB_REQTYPE_CLASS | ||||
| 					| GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				  GRUB_USB_REQ_GET_STATUS, | ||||
| 				  0, i, sizeof (status), (char *) &status); | ||||
|       /* Just ignore the device if the Hub does not report the
 | ||||
| 	 status.  */ | ||||
|       if (err) | ||||
| 	continue; | ||||
| 
 | ||||
|       if (status & GRUB_USB_HUB_STATUS_C_CONNECTED) | ||||
| 	{ | ||||
| 	  detach_device (attached_devices[i-1]); | ||||
| 	  attached_devices[i - 1] = NULL; | ||||
| 	} | ||||
|       	     | ||||
|       /* Connected and status of connection changed ? */ | ||||
|       if ((status & GRUB_USB_HUB_STATUS_CONNECTED) | ||||
|           && (status & GRUB_USB_HUB_STATUS_C_CONNECTED)) | ||||
| 	{ | ||||
| 	  grub_usb_speed_t speed; | ||||
| 
 | ||||
| 	  /* Determine the device speed.  */ | ||||
| 	  if (status & GRUB_USB_HUB_STATUS_LOWSPEED) | ||||
| 	    speed = GRUB_USB_SPEED_LOW; | ||||
| 	  else | ||||
| 	    { | ||||
| 	      if (status & GRUB_USB_HUB_STATUS_HIGHSPEED) | ||||
| 		speed = GRUB_USB_SPEED_HIGH; | ||||
| 	      else | ||||
| 		speed = GRUB_USB_SPEED_FULL; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* A device is actually connected to this port.
 | ||||
| 	   * Now do reset of port. */ | ||||
| 	  err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
| 					    | GRUB_USB_REQTYPE_CLASS | ||||
| 					    | GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				      GRUB_USB_REQ_SET_FEATURE, | ||||
| 				      GRUB_USB_HUB_FEATURE_PORT_RESET, | ||||
| 				      i, 0, 0); | ||||
| 	  /* If the Hub does not cooperate for this port, just skip
 | ||||
| 	     the port.  */ | ||||
| 	  if (err) | ||||
| 	    continue; | ||||
| 
 | ||||
|           /* Wait for reset procedure done */ | ||||
|           timeout = grub_get_time_ms () + 1000; | ||||
|           do | ||||
|             { | ||||
|               /* Get the port status.  */ | ||||
|               err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | ||||
| 	   	 			        | GRUB_USB_REQTYPE_CLASS | ||||
| 					        | GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
| 				          GRUB_USB_REQ_GET_STATUS, | ||||
| 				          0, i, sizeof (status), (char *) &status); | ||||
|             } | ||||
|           while (!err && | ||||
|                  !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) && | ||||
|                  (grub_get_time_ms() < timeout) ); | ||||
|           if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) ) | ||||
|             continue; | ||||
| 
 | ||||
|           /* Wait a recovery time after reset, spec. says 10ms */ | ||||
|           grub_millisleep (10); | ||||
| 
 | ||||
|           /* Do reset of connection change bit */ | ||||
|           err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | ||||
|                                             | GRUB_USB_REQTYPE_CLASS | ||||
|                                             | GRUB_USB_REQTYPE_TARGET_OTHER), | ||||
|                                       GRUB_USB_REQ_CLEAR_FEATURE, | ||||
| 				      GRUB_USB_HUB_FEATURE_C_CONNECTED, | ||||
| 				      i, 0, 0); | ||||
|           /* Just ignore the device if the Hub reports some error */ | ||||
|           if (err) | ||||
| 	     continue; | ||||
| 
 | ||||
| 	  /* Add the device and assign a device address to it.  */ | ||||
| 	  next_dev = grub_usb_hub_add_dev (&dev->controller, speed); | ||||
|           if (! next_dev) | ||||
|             continue; | ||||
| 
 | ||||
| 	  attached_devices[i - 1] = next_dev; | ||||
| 
 | ||||
|           /* If the device is a Hub, scan it for more devices.  */ | ||||
|           if (next_dev->descdev.class == 0x09) | ||||
|             grub_usb_add_hub (next_dev); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_usb_poll_devices (void) | ||||
| { | ||||
|   struct grub_usb_hub *hub; | ||||
|   int i; | ||||
| 
 | ||||
|   for (hub = hubs; hub; hub = hub->next) | ||||
|     { | ||||
|       /* Do we have to recheck number of ports?  */ | ||||
|       /* No, it should be never changed, it should be constant. */ | ||||
|       for (i = 0; i < hub->nports; i++) | ||||
| 	{ | ||||
| 	  grub_usb_speed_t speed; | ||||
| 	  int changed = 0; | ||||
| 
 | ||||
| 	  speed = hub->controller->dev->detect_dev (hub->controller, i, | ||||
| 	                                            &changed); | ||||
| 
 | ||||
| 	  if (changed) | ||||
| 	    { | ||||
| 	      detach_device (hub->devices[i]); | ||||
| 	      hub->devices[i] = NULL; | ||||
| 	      if (speed != GRUB_USB_SPEED_NONE) | ||||
|                 attach_root_port (hub, i, speed); | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   /* We should check changes of non-root hubs too. */ | ||||
|   for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) | ||||
|     { | ||||
|       grub_usb_device_t dev = grub_usb_devs[i]; | ||||
| 
 | ||||
|       if (dev && dev->descdev.class == 0x09) | ||||
| 	poll_nonroot_hub (dev); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int | ||||
| grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) | ||||
| { | ||||
|   int i; | ||||
| 
 | ||||
|   for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) | ||||
|     { | ||||
|       if (grub_usb_devs[i]) | ||||
| 	{ | ||||
| 	  if (hook (grub_usb_devs[i])) | ||||
| 	      return 1; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										308
									
								
								grub-core/bus/usb/usbtrans.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								grub-core/bus/usb/usbtrans.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,308 @@ | |||
| /* usbtrans.c - USB Transfers and Transactions.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/usbtrans.h> | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_control_msg (grub_usb_device_t dev, | ||||
| 		      grub_uint8_t reqtype, | ||||
| 		      grub_uint8_t request, | ||||
| 		      grub_uint16_t value, | ||||
| 		      grub_uint16_t index, | ||||
| 		      grub_size_t size0, char *data_in) | ||||
| { | ||||
|   int i; | ||||
|   grub_usb_transfer_t transfer; | ||||
|   int datablocks; | ||||
|   volatile struct grub_usb_packet_setup *setupdata; | ||||
|   grub_uint32_t setupdata_addr; | ||||
|   grub_usb_err_t err; | ||||
|   unsigned int max; | ||||
|   struct grub_pci_dma_chunk *data_chunk, *setupdata_chunk; | ||||
|   volatile char *data; | ||||
|   grub_uint32_t data_addr; | ||||
|   grub_size_t size = size0; | ||||
|   grub_size_t actual; | ||||
| 
 | ||||
|   /* FIXME: avoid allocation any kind of buffer in a first place.  */ | ||||
|   data_chunk = grub_memalign_dma32 (128, size ? : 16); | ||||
|   if (!data_chunk) | ||||
|     return GRUB_USB_ERR_INTERNAL; | ||||
|   data = grub_dma_get_virt (data_chunk); | ||||
|   data_addr = grub_dma_get_phys (data_chunk); | ||||
|   grub_memcpy ((char *) data, data_in, size); | ||||
| 
 | ||||
|   grub_dprintf ("usb", | ||||
| 		"control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%lu\n", | ||||
| 		reqtype, request,  value, index, (unsigned long)size); | ||||
| 
 | ||||
|   /* Create a transfer.  */ | ||||
|   transfer = grub_malloc (sizeof (*transfer)); | ||||
|   if (! transfer) | ||||
|     { | ||||
|       grub_dma_free (data_chunk); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   setupdata_chunk = grub_memalign_dma32 (32, sizeof (*setupdata)); | ||||
|   if (! setupdata_chunk) | ||||
|     { | ||||
|       grub_free (transfer); | ||||
|       grub_dma_free (data_chunk); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   setupdata = grub_dma_get_virt (setupdata_chunk); | ||||
|   setupdata_addr = grub_dma_get_phys (setupdata_chunk); | ||||
| 
 | ||||
|   /* Determine the maximum packet size.  */ | ||||
|   if (dev->descdev.maxsize0) | ||||
|     max = dev->descdev.maxsize0; | ||||
|   else | ||||
|     max = 64; | ||||
| 
 | ||||
|   grub_dprintf ("usb", "control: transfer = %p, dev = %p\n", transfer, dev); | ||||
| 
 | ||||
|   datablocks = (size + max - 1) / max; | ||||
| 
 | ||||
|   /* XXX: Discriminate between different types of control
 | ||||
|      messages.  */ | ||||
|   transfer->transcnt = datablocks + 2; | ||||
|   transfer->size = size; /* XXX ? */ | ||||
|   transfer->endpoint = 0; | ||||
|   transfer->devaddr = dev->addr; | ||||
|   transfer->type = GRUB_USB_TRANSACTION_TYPE_CONTROL; | ||||
|   transfer->max = max; | ||||
|   transfer->dev = dev; | ||||
| 
 | ||||
|   /* Allocate an array of transfer data structures.  */ | ||||
|   transfer->transactions = grub_malloc (transfer->transcnt | ||||
| 					* sizeof (struct grub_usb_transfer)); | ||||
|   if (! transfer->transactions) | ||||
|     { | ||||
|       grub_free (transfer); | ||||
|       grub_dma_free (setupdata_chunk); | ||||
|       grub_dma_free (data_chunk); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   /* Build a Setup packet.  XXX: Endianness.  */ | ||||
|   setupdata->reqtype = reqtype; | ||||
|   setupdata->request = request; | ||||
|   setupdata->value = value; | ||||
|   setupdata->index = index; | ||||
|   setupdata->length = size; | ||||
|   transfer->transactions[0].size = sizeof (*setupdata); | ||||
|   transfer->transactions[0].pid = GRUB_USB_TRANSFER_TYPE_SETUP; | ||||
|   transfer->transactions[0].data = setupdata_addr; | ||||
|   transfer->transactions[0].toggle = 0; | ||||
| 
 | ||||
|   /* Now the data...  XXX: Is this the right way to transfer control
 | ||||
|      transfers?  */ | ||||
|   for (i = 0; i < datablocks; i++) | ||||
|     { | ||||
|       grub_usb_transaction_t tr = &transfer->transactions[i + 1]; | ||||
| 
 | ||||
|       tr->size = (size > max) ? max : size; | ||||
|       /* Use the right most bit as the data toggle.  Simple and
 | ||||
| 	 effective.  */ | ||||
|       tr->toggle = !(i & 1); | ||||
|       if (reqtype & 128) | ||||
| 	tr->pid = GRUB_USB_TRANSFER_TYPE_IN; | ||||
|       else | ||||
| 	tr->pid = GRUB_USB_TRANSFER_TYPE_OUT; | ||||
|       tr->data = data_addr + i * max; | ||||
|       tr->preceding = i * max; | ||||
|       size -= max; | ||||
|     } | ||||
| 
 | ||||
|   /* End with an empty OUT transaction.  */ | ||||
|   transfer->transactions[datablocks + 1].size = 0; | ||||
|   transfer->transactions[datablocks + 1].data = 0; | ||||
|   if ((reqtype & 128) && datablocks) | ||||
|     transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT; | ||||
|   else | ||||
|     transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_IN; | ||||
| 
 | ||||
|   transfer->transactions[datablocks + 1].toggle = 1; | ||||
| 
 | ||||
|   err = dev->controller.dev->transfer (&dev->controller, transfer, | ||||
| 				       1000, &actual); | ||||
|   grub_dprintf ("usb", "control: err=%d\n", err); | ||||
| 
 | ||||
|   grub_free (transfer->transactions); | ||||
|    | ||||
|   grub_free (transfer); | ||||
|   grub_dma_free (data_chunk); | ||||
|   grub_dma_free (setupdata_chunk); | ||||
| 
 | ||||
|   grub_memcpy (data_in, (char *) data, size0); | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static grub_usb_err_t | ||||
| grub_usb_bulk_readwrite (grub_usb_device_t dev, | ||||
| 			 int endpoint, grub_size_t size0, char *data_in, | ||||
| 			 grub_transfer_type_t type, int timeout, | ||||
| 			 grub_size_t *actual) | ||||
| { | ||||
|   int i; | ||||
|   grub_usb_transfer_t transfer; | ||||
|   int datablocks; | ||||
|   unsigned int max; | ||||
|   grub_usb_err_t err; | ||||
|   int toggle = dev->toggle[endpoint]; | ||||
|   volatile char *data; | ||||
|   grub_uint32_t data_addr; | ||||
|   struct grub_pci_dma_chunk *data_chunk; | ||||
|   grub_size_t size = size0; | ||||
| 
 | ||||
|   grub_dprintf ("usb", "bulk: size=0x%02lx type=%d\n", (unsigned long) size, | ||||
| 		type); | ||||
| 
 | ||||
|   /* FIXME: avoid allocation any kind of buffer in a first place.  */ | ||||
|   data_chunk = grub_memalign_dma32 (128, size); | ||||
|   if (!data_chunk) | ||||
|     return GRUB_USB_ERR_INTERNAL; | ||||
|   data = grub_dma_get_virt (data_chunk); | ||||
|   data_addr = grub_dma_get_phys (data_chunk); | ||||
|   if (type == GRUB_USB_TRANSFER_TYPE_OUT) | ||||
|     grub_memcpy ((char *) data, data_in, size); | ||||
| 
 | ||||
|   /* Use the maximum packet size given in the endpoint descriptor.  */ | ||||
|   if (dev->initialized) | ||||
|     { | ||||
|       struct grub_usb_desc_endp *endpdesc; | ||||
|       endpdesc = grub_usb_get_endpdescriptor (dev, 0); | ||||
| 
 | ||||
|       if (endpdesc) | ||||
| 	max = endpdesc->maxpacket; | ||||
|       else | ||||
| 	max = 64; | ||||
|     } | ||||
|   else | ||||
|     max = 64; | ||||
| 
 | ||||
|   /* Create a transfer.  */ | ||||
|   transfer = grub_malloc (sizeof (struct grub_usb_transfer)); | ||||
|   if (! transfer) | ||||
|     { | ||||
|       grub_dma_free (data_chunk); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   datablocks = ((size + max - 1) / max); | ||||
|   transfer->transcnt = datablocks; | ||||
|   transfer->size = size - 1; | ||||
|   transfer->endpoint = endpoint & 15; | ||||
|   transfer->devaddr = dev->addr; | ||||
|   transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK; | ||||
|   transfer->max = max; | ||||
|   transfer->dev = dev; | ||||
|   transfer->last_trans = -1; /* Reset index of last processed transaction (TD) */ | ||||
| 
 | ||||
|   /* Allocate an array of transfer data structures.  */ | ||||
|   transfer->transactions = grub_malloc (transfer->transcnt | ||||
| 					* sizeof (struct grub_usb_transfer)); | ||||
|   if (! transfer->transactions) | ||||
|     { | ||||
|       grub_free (transfer); | ||||
|       grub_dma_free (data_chunk); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   /* Set up all transfers.  */ | ||||
|   for (i = 0; i < datablocks; i++) | ||||
|     { | ||||
|       grub_usb_transaction_t tr = &transfer->transactions[i]; | ||||
| 
 | ||||
|       tr->size = (size > max) ? max : size; | ||||
|       /* XXX: Use the right most bit as the data toggle.  Simple and
 | ||||
| 	 effective.  */ | ||||
|       tr->toggle = toggle; | ||||
|       toggle = toggle ? 0 : 1; | ||||
|       tr->pid = type; | ||||
|       tr->data = data_addr + i * max; | ||||
|       tr->preceding = i * max; | ||||
|       size -= tr->size; | ||||
|     } | ||||
| 
 | ||||
|   err = dev->controller.dev->transfer (&dev->controller, transfer, timeout, | ||||
| 				       actual); | ||||
|   /* We must remember proper toggle value even if some transactions
 | ||||
|    * were not processed - correct value should be inversion of last | ||||
|    * processed transaction (TD). */ | ||||
|   if (transfer->last_trans >= 0) | ||||
|     toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1; | ||||
|   else | ||||
|     toggle = dev->toggle[endpoint]; /* Nothing done, take original */ | ||||
|   grub_dprintf ("usb", "bulk: err=%d, toggle=%d\n", err, toggle); | ||||
|   dev->toggle[endpoint] = toggle; | ||||
| 
 | ||||
|   grub_free (transfer->transactions); | ||||
|   grub_free (transfer); | ||||
|   grub_dma_free (data_chunk); | ||||
| 
 | ||||
|   if (type == GRUB_USB_TRANSFER_TYPE_IN) | ||||
|     grub_memcpy (data_in, (char *) data, size0); | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_bulk_write (grub_usb_device_t dev, | ||||
| 		     int endpoint, grub_size_t size, char *data) | ||||
| { | ||||
|   grub_size_t actual; | ||||
|   grub_usb_err_t err; | ||||
| 
 | ||||
|   err = grub_usb_bulk_readwrite (dev, endpoint, size, data, | ||||
| 				 GRUB_USB_TRANSFER_TYPE_OUT, 1000, &actual); | ||||
|   if (!err && actual != size) | ||||
|     err = GRUB_USB_ERR_DATA; | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_bulk_read (grub_usb_device_t dev, | ||||
| 		    int endpoint, grub_size_t size, char *data) | ||||
| { | ||||
|   grub_size_t actual; | ||||
|   grub_usb_err_t err; | ||||
|   err = grub_usb_bulk_readwrite (dev, endpoint, size, data, | ||||
| 				 GRUB_USB_TRANSFER_TYPE_IN, 1000, &actual); | ||||
|   if (!err && actual != size) | ||||
|     err = GRUB_USB_ERR_DATA; | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| grub_usb_err_t | ||||
| grub_usb_bulk_read_extended (grub_usb_device_t dev, | ||||
| 			     int endpoint, grub_size_t size, char *data, | ||||
| 			     int timeout, grub_size_t *actual) | ||||
| { | ||||
|   return grub_usb_bulk_readwrite (dev, endpoint, size, data, | ||||
| 				  GRUB_USB_TRANSFER_TYPE_IN, timeout, actual); | ||||
| } | ||||
							
								
								
									
										776
									
								
								grub-core/commands/acpi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										776
									
								
								grub-core/commands/acpi.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,776 @@ | |||
| /* acpi.c - modify acpi tables. */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/gzio.h> | ||||
| #include <grub/acpi.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/machine/memory.h> | ||||
| #include <grub/memory.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| #ifdef GRUB_MACHINE_EFI | ||||
| #include <grub/efi/efi.h> | ||||
| #include <grub/efi/api.h> | ||||
| #endif | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = { | ||||
|   {"exclude", 'x', 0, | ||||
|    N_("Don't load host tables specified by comma-separated list."), | ||||
|    0, ARG_TYPE_STRING}, | ||||
|   {"load-only", 'n', 0, | ||||
|    N_("Load only tables specified by comma-separated list."), 0, ARG_TYPE_STRING}, | ||||
|   {"v1", '1', 0, N_("Expose v1 tables."), 0, ARG_TYPE_NONE}, | ||||
|   {"v2", '2', 0, N_("Expose v2 and v3 tables."), 0, ARG_TYPE_NONE}, | ||||
|   {"oemid", 'o', 0, N_("Set OEMID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING}, | ||||
|   {"oemtable", 't', 0, | ||||
|    N_("Set OEMTABLE ID of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING}, | ||||
|   {"oemtablerev", 'r', 0, | ||||
|    N_("Set OEMTABLE revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT}, | ||||
|   {"oemtablecreator", 'c', 0, | ||||
|    N_("Set creator field of RSDP, XSDT and RSDT."), 0, ARG_TYPE_STRING}, | ||||
|   {"oemtablecreatorrev", 'd', 0, | ||||
|    N_("Set creator revision of RSDP, XSDT and RSDT."), 0, ARG_TYPE_INT}, | ||||
|   {"no-ebda", 'e', 0, N_("Don't update EBDA. May fix failures or hangs on some." | ||||
|    " BIOSes but makes it ineffective with OS not receiving RSDP from GRUB."), | ||||
|    0, ARG_TYPE_NONE}, | ||||
|   {0, 0, 0, 0, 0, 0} | ||||
| }; | ||||
| 
 | ||||
| /* Simple checksum by summing all bytes. Used by ACPI and SMBIOS. */ | ||||
| grub_uint8_t | ||||
| grub_byte_checksum (void *base, grub_size_t size) | ||||
| { | ||||
|   grub_uint8_t *ptr; | ||||
|   grub_uint8_t ret = 0; | ||||
|   for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size; | ||||
|        ptr++) | ||||
|     ret += *ptr; | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| /* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise.
 | ||||
|    rev2 contains the revision of ACPIv2+ to generate or 0 if none. */ | ||||
| static int rev1, rev2; | ||||
| /* OEMID of RSDP, RSDT and XSDT. */ | ||||
| static char root_oemid[6]; | ||||
| /* OEMTABLE of the same tables. */ | ||||
| static char root_oemtable[8]; | ||||
| /* OEMREVISION of the same tables. */ | ||||
| static grub_uint32_t root_oemrev; | ||||
| /* CreatorID of the same tables. */ | ||||
| static char root_creator_id[4]; | ||||
| /* CreatorRevision of the same tables. */ | ||||
| static grub_uint32_t root_creator_rev; | ||||
| static struct grub_acpi_rsdp_v10 *rsdpv1_new = 0; | ||||
| static struct grub_acpi_rsdp_v20 *rsdpv2_new = 0; | ||||
| static char *playground = 0, *playground_ptr = 0; | ||||
| static int playground_size = 0; | ||||
| 
 | ||||
| /* Linked list of ACPI tables. */ | ||||
| struct efiemu_acpi_table | ||||
| { | ||||
|   void *addr; | ||||
|   grub_size_t size; | ||||
|   struct efiemu_acpi_table *next; | ||||
| }; | ||||
| static struct efiemu_acpi_table *acpi_tables = 0; | ||||
| 
 | ||||
| /* DSDT isn't in RSDT. So treat it specially. */ | ||||
| static void *table_dsdt = 0; | ||||
| /* Pointer to recreated RSDT. */ | ||||
| static void *rsdt_addr = 0; | ||||
| 
 | ||||
| /* Allocation handles for different tables. */ | ||||
| static grub_size_t dsdt_size = 0; | ||||
| 
 | ||||
| /* Address of original FACS. */ | ||||
| static grub_uint32_t facs_addr = 0; | ||||
| 
 | ||||
| struct grub_acpi_rsdp_v20 * | ||||
| grub_acpi_get_rsdpv2 (void) | ||||
| { | ||||
|   if (rsdpv2_new) | ||||
|     return rsdpv2_new; | ||||
|   if (rsdpv1_new) | ||||
|     return 0; | ||||
|   return grub_machine_acpi_get_rsdpv2 (); | ||||
| } | ||||
| 
 | ||||
| struct grub_acpi_rsdp_v10 * | ||||
| grub_acpi_get_rsdpv1 (void) | ||||
| { | ||||
|   if (rsdpv1_new) | ||||
|     return rsdpv1_new; | ||||
|   if (rsdpv2_new) | ||||
|     return 0; | ||||
|   return grub_machine_acpi_get_rsdpv1 (); | ||||
| } | ||||
| 
 | ||||
| static inline int | ||||
| iszero (grub_uint8_t *reg, int size) | ||||
| { | ||||
|   int i; | ||||
|   for (i = 0; i < size; i++) | ||||
|     if (reg[i]) | ||||
|       return 0; | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_acpi_create_ebda (void) | ||||
| { | ||||
|   int ebda_kb_len; | ||||
|   int ebda_len; | ||||
|   int mmapregion = 0; | ||||
|   grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0; | ||||
|   grub_uint64_t highestlow = 0; | ||||
|   grub_uint8_t *targetebda, *target; | ||||
|   struct grub_acpi_rsdp_v10 *v1; | ||||
|   struct grub_acpi_rsdp_v20 *v2; | ||||
|   auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, | ||||
| 				       grub_uint32_t); | ||||
|   int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size, | ||||
| 				  grub_uint32_t type) | ||||
|   { | ||||
|     grub_uint64_t end = start + size; | ||||
|     if (type != GRUB_MACHINE_MEMORY_AVAILABLE) | ||||
|       return 0; | ||||
|     if (end > 0x100000) | ||||
|       end = 0x100000; | ||||
|     if (end > start + ebda_len | ||||
| 	&& highestlow < ((end - ebda_len) & (~0xf)) ) | ||||
|       highestlow = (end - ebda_len) & (~0xf); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   ebda = (grub_uint8_t *) UINT_TO_PTR ((*((grub_uint16_t *)0x40e)) << 4); | ||||
|   ebda_kb_len = *(grub_uint16_t *) ebda; | ||||
|   if (! ebda || ebda_kb_len > 16) | ||||
|     ebda_kb_len = 0; | ||||
|   ebda_len = (ebda_kb_len + 1) << 10; | ||||
| 
 | ||||
|   /* FIXME: use low-memory mm allocation once it's available. */ | ||||
|   grub_mmap_iterate (find_hook); | ||||
|   targetebda = (grub_uint8_t *) UINT_TO_PTR (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, | ||||
| 				   GRUB_MACHINE_MEMORY_RESERVED); | ||||
|   if (! mmapregion) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* XXX: EBDA is unstandardized, so this implementation is heuristical. */ | ||||
|   if (ebda_kb_len) | ||||
|     grub_memcpy (targetebda, ebda, 0x400); | ||||
|   else | ||||
|     grub_memset (targetebda, 0, 0x400); | ||||
|   *((grub_uint16_t *) targetebda) = ebda_kb_len + 1; | ||||
|   target = targetebda; | ||||
| 
 | ||||
|   v1 = grub_acpi_get_rsdpv1 (); | ||||
|   v2 = grub_acpi_get_rsdpv2 (); | ||||
|   if (v2 && v2->length > 40) | ||||
|     v2 = 0; | ||||
| 
 | ||||
|   /* First try to replace already existing rsdp. */ | ||||
|   if (v2) | ||||
|     { | ||||
|       grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n"); | ||||
|       for (; target < targetebda + 0x400 - v2->length; target += 0x10) | ||||
| 	if (grub_memcmp (target, "RSD PTR ", 8) == 0 | ||||
| 	    && grub_byte_checksum (target, | ||||
| 				   sizeof (struct grub_acpi_rsdp_v10)) == 0 | ||||
| 	    && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0 | ||||
| 	    && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length) | ||||
| 	  { | ||||
| 	    grub_memcpy (target, v2, v2->length); | ||||
| 	    grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target); | ||||
| 	    v2inebda = target; | ||||
| 	    target += v2->length; | ||||
| 	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1); | ||||
| 	    v2 = 0; | ||||
| 	    break; | ||||
| 	  } | ||||
|     } | ||||
| 
 | ||||
|   if (v1) | ||||
|     { | ||||
|       grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n"); | ||||
|       for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10); | ||||
| 	   target += 0x10) | ||||
| 	if (grub_memcmp (target, "RSD PTR ", 8) == 0 | ||||
| 	    && grub_byte_checksum (target, | ||||
| 				   sizeof (struct grub_acpi_rsdp_v10)) == 0) | ||||
| 	  { | ||||
| 	    grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10)); | ||||
| 	    grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target); | ||||
| 	    v1inebda = target; | ||||
| 	    target += sizeof (struct grub_acpi_rsdp_v10); | ||||
| 	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1); | ||||
| 	    v1 = 0; | ||||
| 	    break; | ||||
| 	  } | ||||
|     } | ||||
| 
 | ||||
|   target = targetebda + 0x100; | ||||
| 
 | ||||
|   /* Try contiguous zeros. */ | ||||
|   if (v2) | ||||
|     { | ||||
|       grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n"); | ||||
|       for (; target < targetebda + 0x400 - v2->length; target += 0x10) | ||||
| 	if (iszero (target, v2->length)) | ||||
| 	  { | ||||
| 	    grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target); | ||||
| 	    grub_memcpy (target, v2, v2->length); | ||||
| 	    v2inebda = target; | ||||
| 	    target += v2->length; | ||||
| 	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1); | ||||
| 	    v2 = 0; | ||||
| 	    break; | ||||
| 	  } | ||||
|     } | ||||
| 
 | ||||
|   if (v1) | ||||
|     { | ||||
|       grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n"); | ||||
|       for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10); | ||||
| 	   target += 0x10) | ||||
| 	if (iszero (target, sizeof (struct grub_acpi_rsdp_v10))) | ||||
| 	  { | ||||
| 	    grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target); | ||||
| 	    grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10)); | ||||
| 	    v1inebda = target; | ||||
| 	    target += sizeof (struct grub_acpi_rsdp_v10); | ||||
| 	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1); | ||||
| 	    v1 = 0; | ||||
| 	    break; | ||||
| 	  } | ||||
|     } | ||||
| 
 | ||||
|   if (v1 || v2) | ||||
|     { | ||||
|       grub_mmap_unregister (mmapregion); | ||||
|       return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 			 "couldn't find suitable spot in EBDA"); | ||||
|     } | ||||
| 
 | ||||
|   /* Remove any other RSDT. */ | ||||
|   for (target = targetebda; | ||||
|        target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10); | ||||
|        target += 0x10) | ||||
|     if (grub_memcmp (target, "RSD PTR ", 8) == 0 | ||||
| 	&& grub_byte_checksum (target, | ||||
| 			       sizeof (struct grub_acpi_rsdp_v10)) == 0 | ||||
| 	&& target != v1inebda && target != v2inebda) | ||||
|       *target = 0; | ||||
| 
 | ||||
|   grub_dprintf ("acpi", "Switching EBDA\n"); | ||||
|   (*((grub_uint16_t *) 0x40e)) = ((long)targetebda) >> 4; | ||||
|   grub_dprintf ("acpi", "EBDA switched\n"); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| /* Create tables common to ACPIv1 and ACPIv2+ */ | ||||
| static void | ||||
| setup_common_tables (void) | ||||
| { | ||||
|   struct efiemu_acpi_table *cur; | ||||
|   struct grub_acpi_table_header *rsdt; | ||||
|   grub_uint32_t *rsdt_entry; | ||||
|   int numoftables; | ||||
| 
 | ||||
|   /* Treat DSDT. */ | ||||
|   grub_memcpy (playground_ptr, table_dsdt, dsdt_size); | ||||
|   grub_free (table_dsdt); | ||||
|   table_dsdt = playground_ptr; | ||||
|   playground_ptr += dsdt_size; | ||||
| 
 | ||||
|   /* Treat other tables. */ | ||||
|   for (cur = acpi_tables; cur; cur = cur->next) | ||||
|     { | ||||
|       struct grub_acpi_fadt *fadt; | ||||
| 
 | ||||
|       grub_memcpy (playground_ptr, cur->addr, cur->size); | ||||
|       grub_free (cur->addr); | ||||
|       cur->addr = playground_ptr; | ||||
|       playground_ptr += cur->size; | ||||
| 
 | ||||
|       /* If it's FADT correct DSDT and FACS addresses. */ | ||||
|       fadt = (struct grub_acpi_fadt *) cur->addr; | ||||
|       if (grub_memcmp (fadt->hdr.signature, "FACP", | ||||
| 		       sizeof (fadt->hdr.signature)) == 0) | ||||
| 	{ | ||||
| 	  fadt->dsdt_addr = PTR_TO_UINT32 (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->facs_xaddr = facs_addr; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* Recompute checksum. */ | ||||
| 	  fadt->hdr.checksum = 0; | ||||
| 	  fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   /* Fill RSDT entries. */ | ||||
|   numoftables = 0; | ||||
|   for (cur = acpi_tables; cur; cur = cur->next) | ||||
|     numoftables++; | ||||
| 
 | ||||
|   rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr; | ||||
|   playground_ptr += sizeof (struct grub_acpi_table_header) + 4 * numoftables; | ||||
| 
 | ||||
|   rsdt_entry = (grub_uint32_t *) (rsdt + 1); | ||||
| 
 | ||||
|   /* Fill RSDT header. */ | ||||
|   grub_memcpy (&(rsdt->signature), "RSDT", 4); | ||||
|   rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables; | ||||
|   rsdt->revision = 1; | ||||
|   grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid)); | ||||
|   grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable)); | ||||
|   rsdt->oemrev = root_oemrev; | ||||
|   grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id)); | ||||
|   rsdt->creator_rev = root_creator_rev; | ||||
| 
 | ||||
|   for (cur = acpi_tables; cur; cur = cur->next) | ||||
|     *(rsdt_entry++) = PTR_TO_UINT32 (cur->addr); | ||||
| 
 | ||||
|   /* Recompute checksum. */ | ||||
|   rsdt->checksum = 0; | ||||
|   rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length); | ||||
| } | ||||
| 
 | ||||
| /* Regenerate ACPIv1 RSDP */ | ||||
| static void | ||||
| setv1table (void) | ||||
| { | ||||
|   /* Create RSDP. */ | ||||
|   rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr; | ||||
|   playground_ptr += sizeof (struct grub_acpi_rsdp_v10); | ||||
|   grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", | ||||
| 	       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->checksum = 0; | ||||
|   rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new, | ||||
| 						  sizeof (*rsdpv1_new)); | ||||
|   grub_dprintf ("acpi", "Generated ACPIv1 tables\n"); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| setv2table (void) | ||||
| { | ||||
|   struct grub_acpi_table_header *xsdt; | ||||
|   struct efiemu_acpi_table *cur; | ||||
|   grub_uint64_t *xsdt_entry; | ||||
|   int numoftables; | ||||
| 
 | ||||
|   numoftables = 0; | ||||
|   for (cur = acpi_tables; cur; cur = cur->next) | ||||
|     numoftables++; | ||||
| 
 | ||||
|   /* Create XSDT. */ | ||||
|   xsdt = (struct grub_acpi_table_header *) playground_ptr; | ||||
|   playground_ptr += sizeof (struct grub_acpi_table_header) + 8 * numoftables; | ||||
| 
 | ||||
|   xsdt_entry = (grub_uint64_t *)(xsdt + 1); | ||||
|   for (cur = acpi_tables; cur; cur = cur->next) | ||||
|     *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr); | ||||
|   grub_memcpy (&(xsdt->signature), "XSDT", 4); | ||||
|   xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables; | ||||
|   xsdt->revision = 1; | ||||
|   grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid)); | ||||
|   grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable)); | ||||
|   xsdt->oemrev = root_oemrev; | ||||
|   grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id)); | ||||
|   xsdt->creator_rev = root_creator_rev; | ||||
|   xsdt->checksum = 0; | ||||
|   xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length); | ||||
| 
 | ||||
|   /* Create RSDPv2. */ | ||||
|   rsdpv2_new = (struct grub_acpi_rsdp_v20 *) playground_ptr; | ||||
|   playground_ptr += sizeof (struct grub_acpi_rsdp_v20); | ||||
|   grub_memcpy (&(rsdpv2_new->rsdpv1.signature), "RSD PTR ", | ||||
| 	       sizeof (rsdpv2_new->rsdpv1.signature)); | ||||
|   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.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->checksum = 0; | ||||
|   rsdpv2_new->checksum = 1 + ~grub_byte_checksum (rsdpv2_new, | ||||
| 						  rsdpv2_new->length); | ||||
|   grub_dprintf ("acpi", "Generated ACPIv2 tables\n"); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| free_tables (void) | ||||
| { | ||||
|   struct efiemu_acpi_table *cur, *t; | ||||
|   if (table_dsdt) | ||||
|     grub_free (table_dsdt); | ||||
|   for (cur = acpi_tables; cur;) | ||||
|     { | ||||
|       t = cur; | ||||
|       grub_free (cur->addr); | ||||
|       cur = cur->next; | ||||
|       grub_free (t); | ||||
|     } | ||||
|   acpi_tables = 0; | ||||
|   table_dsdt = 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_acpi (struct grub_extcmd *cmd, | ||||
| 		      int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   struct grub_acpi_rsdp_v10 *rsdp; | ||||
|   struct efiemu_acpi_table *cur, *t; | ||||
|   grub_err_t err; | ||||
|   int i, mmapregion; | ||||
|   int numoftables; | ||||
| 
 | ||||
|   /* Default values if no RSDP is found. */ | ||||
|   rev1 = 1; | ||||
|   rev2 = 3; | ||||
| 
 | ||||
|   facs_addr = 0; | ||||
|   playground = playground_ptr = 0; | ||||
|   playground_size = 0; | ||||
| 
 | ||||
|   rsdp = (struct grub_acpi_rsdp_v10 *) grub_machine_acpi_get_rsdpv2 (); | ||||
| 
 | ||||
|   if (! rsdp) | ||||
|     rsdp = grub_machine_acpi_get_rsdpv1 (); | ||||
| 
 | ||||
|   if (rsdp) | ||||
|     { | ||||
|       grub_uint32_t *entry_ptr; | ||||
|       char *exclude = 0; | ||||
|       char *load_only = 0; | ||||
|       char *ptr; | ||||
|       /* RSDT consists of header and an array of 32-bit pointers. */ | ||||
|       struct grub_acpi_table_header *rsdt; | ||||
| 
 | ||||
|       exclude = state[0].set ? grub_strdup (state[0].arg) : 0; | ||||
|       if (exclude) | ||||
| 	{ | ||||
| 	  for (ptr = exclude; *ptr; ptr++) | ||||
| 	    *ptr = grub_tolower (*ptr); | ||||
| 	} | ||||
| 
 | ||||
|       load_only = state[1].set ? grub_strdup (state[1].arg) : 0; | ||||
|       if (load_only) | ||||
| 	{ | ||||
| 	  for (ptr = load_only; *ptr; ptr++) | ||||
| 	    *ptr = grub_tolower (*ptr); | ||||
| 	} | ||||
| 
 | ||||
|       /* 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); | ||||
|       /* Load host tables. */ | ||||
|       for (entry_ptr = (grub_uint32_t *) (rsdt + 1); | ||||
| 	   entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt) | ||||
| 					  + rsdt->length); | ||||
| 	   entry_ptr++) | ||||
| 	{ | ||||
| 	  char signature[5]; | ||||
| 	  struct efiemu_acpi_table *table; | ||||
| 	  struct grub_acpi_table_header *curtable | ||||
| 	    = (struct grub_acpi_table_header *) UINT_TO_PTR (*entry_ptr); | ||||
| 	  signature[4] = 0; | ||||
| 	  for (i = 0; i < 4;i++) | ||||
| 	    signature[i] = grub_tolower (curtable->signature[i]); | ||||
| 
 | ||||
| 	  /* If it's FADT it contains addresses of DSDT and FACS. */ | ||||
| 	  if (grub_strcmp (signature, "facp") == 0) | ||||
| 	    { | ||||
| 	      struct grub_acpi_table_header *dsdt; | ||||
| 	      struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable; | ||||
| 
 | ||||
| 	      /* Set root header variables to the same values
 | ||||
| 		 as FACP by default. */ | ||||
| 	      grub_memcpy (&root_oemid, &(fadt->hdr.oemid), | ||||
| 			   sizeof (root_oemid)); | ||||
| 	      grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable), | ||||
| 			   sizeof (root_oemtable)); | ||||
| 	      root_oemrev = fadt->hdr.oemrev; | ||||
| 	      grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id), | ||||
| 			   sizeof (root_creator_id)); | ||||
| 	      root_creator_rev = fadt->hdr.creator_rev; | ||||
| 
 | ||||
| 	      /* Load DSDT if not excluded. */ | ||||
| 	      dsdt = (struct grub_acpi_table_header *) | ||||
| 		UINT_TO_PTR (fadt->dsdt_addr); | ||||
| 	      if (dsdt && (! exclude || ! grub_strword (exclude, "dsdt")) | ||||
| 		  && (! load_only || grub_strword (load_only, "dsdt")) | ||||
| 		  && dsdt->length >= sizeof (*dsdt)) | ||||
| 		{ | ||||
| 		  dsdt_size = dsdt->length; | ||||
| 		  table_dsdt = grub_malloc (dsdt->length); | ||||
| 		  if (! table_dsdt) | ||||
| 		    { | ||||
| 		      free_tables (); | ||||
| 		      grub_free (exclude); | ||||
| 		      grub_free (load_only); | ||||
| 		      return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 					 "couldn't allocate table"); | ||||
| 		    } | ||||
| 		  grub_memcpy (table_dsdt, dsdt, dsdt->length); | ||||
| 		} | ||||
| 
 | ||||
| 	      /* Save FACS address. FACS shouldn't be overridden. */ | ||||
| 	      facs_addr = fadt->facs_addr; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* Skip excluded tables. */ | ||||
| 	  if (exclude && grub_strword (exclude, signature)) | ||||
| 	    continue; | ||||
| 	  if (load_only && ! grub_strword (load_only, signature)) | ||||
| 	    continue; | ||||
| 
 | ||||
| 	  /* Sanity check. */ | ||||
| 	  if (curtable->length < sizeof (*curtable)) | ||||
| 	    continue; | ||||
| 
 | ||||
| 	  table = (struct efiemu_acpi_table *) grub_malloc | ||||
| 	    (sizeof (struct efiemu_acpi_table)); | ||||
| 	  if (! table) | ||||
| 	    { | ||||
| 	      free_tables (); | ||||
| 	      grub_free (exclude); | ||||
| 	      grub_free (load_only); | ||||
| 	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 				 "couldn't allocate table structure"); | ||||
| 	    } | ||||
| 	  table->size = curtable->length; | ||||
| 	  table->addr = grub_malloc (table->size); | ||||
| 	  playground_size += table->size; | ||||
| 	  if (! table->addr) | ||||
| 	    { | ||||
| 	      free_tables (); | ||||
| 	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 				 "couldn't allocate table"); | ||||
| 	    } | ||||
| 	  table->next = acpi_tables; | ||||
| 	  acpi_tables = table; | ||||
| 	  grub_memcpy (table->addr, curtable, table->size); | ||||
| 	} | ||||
|       grub_free (exclude); | ||||
|       grub_free (load_only); | ||||
|     } | ||||
| 
 | ||||
|   /* Does user specify versions to generate? */ | ||||
|   if (state[2].set || state[3].set) | ||||
|     { | ||||
|       rev1 = state[2].set; | ||||
|       if (state[3].set) | ||||
| 	rev2 = rev2 ? : 2; | ||||
|       else | ||||
| 	rev2 = 0; | ||||
|     } | ||||
| 
 | ||||
|   /* Does user override root header information? */ | ||||
|   if (state[4].set) | ||||
|     grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid)); | ||||
|   if (state[5].set) | ||||
|     grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable)); | ||||
|   if (state[6].set) | ||||
|     root_oemrev = grub_strtoul (state[6].arg, 0, 0); | ||||
|   if (state[7].set) | ||||
|     grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id)); | ||||
|   if (state[8].set) | ||||
|     root_creator_rev = grub_strtoul (state[8].arg, 0, 0); | ||||
| 
 | ||||
|   /* Load user tables */ | ||||
|   for (i = 0; i < argc; i++) | ||||
|     { | ||||
|       grub_file_t file; | ||||
|       grub_size_t size; | ||||
|       char *buf; | ||||
| 
 | ||||
|       file = grub_gzfile_open (args[i], 1); | ||||
|       if (! file) | ||||
| 	{ | ||||
| 	  free_tables (); | ||||
| 	  return grub_error (GRUB_ERR_BAD_OS, "couldn't open file %s", args[i]); | ||||
| 	} | ||||
| 
 | ||||
|       size = grub_file_size (file); | ||||
|       if (size < sizeof (struct grub_acpi_table_header)) | ||||
| 	{ | ||||
| 	  grub_file_close (file); | ||||
| 	  free_tables (); | ||||
| 	  return grub_error (GRUB_ERR_BAD_OS, "file %s is too small", args[i]); | ||||
| 	} | ||||
| 
 | ||||
|       buf = (char *) grub_malloc (size); | ||||
|       if (! buf) | ||||
| 	{ | ||||
| 	  grub_file_close (file); | ||||
| 	  free_tables (); | ||||
| 	  return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 			     "couldn't read file %s", args[i]); | ||||
| 	} | ||||
| 
 | ||||
|       if (grub_file_read (file, buf, size) != (int) size) | ||||
| 	{ | ||||
| 	  grub_file_close (file); | ||||
| 	  free_tables (); | ||||
| 	  return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]); | ||||
| 	} | ||||
|       grub_file_close (file); | ||||
| 
 | ||||
|       if (grub_memcmp (((struct grub_acpi_table_header *) buf)->signature, | ||||
| 		       "DSDT", 4) == 0) | ||||
| 	{ | ||||
| 	  grub_free (table_dsdt); | ||||
| 	  table_dsdt = buf; | ||||
| 	  dsdt_size = size; | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  struct efiemu_acpi_table *table; | ||||
| 	  table = (struct efiemu_acpi_table *) grub_malloc | ||||
| 	    (sizeof (struct efiemu_acpi_table)); | ||||
| 	  if (! table) | ||||
| 	    { | ||||
| 	      free_tables (); | ||||
| 	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 				 "couldn't allocate table structure"); | ||||
| 	    } | ||||
| 
 | ||||
| 	  table->size = size; | ||||
| 	  table->addr = buf; | ||||
| 	  playground_size += table->size; | ||||
| 
 | ||||
| 	  table->next = acpi_tables; | ||||
| 	  acpi_tables = table; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   numoftables = 0; | ||||
|   for (cur = acpi_tables; cur; cur = cur->next) | ||||
|     numoftables++; | ||||
| 
 | ||||
|   /* DSDT. */ | ||||
|   playground_size += dsdt_size; | ||||
|   /* RSDT. */ | ||||
|   playground_size += sizeof (struct grub_acpi_table_header) + 4 * numoftables; | ||||
|   /* RSDPv1. */ | ||||
|   playground_size += sizeof (struct grub_acpi_rsdp_v10); | ||||
|   /* XSDT. */ | ||||
|   playground_size += sizeof (struct grub_acpi_table_header) + 8 * numoftables; | ||||
|   /* RSDPv2. */ | ||||
|   playground_size += sizeof (struct grub_acpi_rsdp_v20); | ||||
| 
 | ||||
|   playground = playground_ptr | ||||
|     = grub_mmap_malign_and_register (1, playground_size, &mmapregion, | ||||
| 				     GRUB_MACHINE_MEMORY_ACPI, 0); | ||||
| 
 | ||||
|   if (! playground) | ||||
|     { | ||||
|       free_tables (); | ||||
|       return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 			 "couldn't allocate space for ACPI tables"); | ||||
|     } | ||||
| 
 | ||||
|   setup_common_tables (); | ||||
| 
 | ||||
|   /* Request space for RSDPv1. */ | ||||
|   if (rev1) | ||||
|     setv1table (); | ||||
| 
 | ||||
|   /* Request space for RSDPv2+ and XSDT. */ | ||||
|   if (rev2) | ||||
|     setv2table (); | ||||
| 
 | ||||
|   for (cur = acpi_tables; cur;) | ||||
|     { | ||||
|       t = cur; | ||||
|       cur = cur->next; | ||||
|       grub_free (t); | ||||
|     } | ||||
|   acpi_tables = 0; | ||||
| 
 | ||||
|   if (! state[9].set && (err = grub_acpi_create_ebda ())) | ||||
|     { | ||||
|       rsdpv1_new = 0; | ||||
|       rsdpv2_new = 0; | ||||
|       grub_mmap_free_and_unregister (mmapregion); | ||||
|       return err; | ||||
|     } | ||||
| 
 | ||||
| #ifdef GRUB_MACHINE_EFI | ||||
|   { | ||||
|     struct grub_efi_guid acpi = GRUB_EFI_ACPI_TABLE_GUID; | ||||
|     struct grub_efi_guid acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID; | ||||
| 
 | ||||
|     grub_efi_system_table->boot_services->install_configuration_table | ||||
|       (&acpi20, grub_acpi_get_rsdpv2 ()); | ||||
|     grub_efi_system_table->boot_services->install_configuration_table | ||||
|       (&acpi, grub_acpi_get_rsdpv1 ()); | ||||
|   } | ||||
| #endif | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(acpi) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[-1|-2] [--exclude=TABLE1,TABLE2|" | ||||
| 			      "--load-only=table1,table2] FILE1" | ||||
| 			      " [FILE2] [...]"), | ||||
| 			      N_("Load host ACPI tables and tables " | ||||
| 			      "specified by arguments."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(acpi) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										119
									
								
								grub-core/commands/blocklist.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								grub-core/commands/blocklist.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | |||
| /* blocklist.c - print the block list of a file */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		    int argc, char **args) | ||||
| { | ||||
|   grub_file_t file; | ||||
|   char buf[GRUB_DISK_SECTOR_SIZE]; | ||||
|   unsigned long start_sector = 0; | ||||
|   unsigned num_sectors = 0; | ||||
|   int num_entries = 0; | ||||
|   grub_disk_addr_t part_start = 0; | ||||
|   auto void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset, | ||||
| 			    unsigned length); | ||||
|   auto void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num, | ||||
| 			     unsigned offset, unsigned length); | ||||
| 
 | ||||
|   void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset, | ||||
| 		       unsigned length) | ||||
|     { | ||||
|       if (num_sectors > 0) | ||||
| 	{ | ||||
| 	  if (start_sector + num_sectors == sector | ||||
| 	      && offset == 0 && length == GRUB_DISK_SECTOR_SIZE) | ||||
| 	    { | ||||
| 	      num_sectors++; | ||||
| 	      return; | ||||
| 	    } | ||||
| 
 | ||||
| 	  print_blocklist (start_sector, num_sectors, 0, 0); | ||||
| 	  num_sectors = 0; | ||||
| 	} | ||||
| 
 | ||||
|       if (offset == 0 && length == GRUB_DISK_SECTOR_SIZE) | ||||
| 	{ | ||||
| 	  start_sector = sector; | ||||
| 	  num_sectors++; | ||||
| 	} | ||||
|       else | ||||
| 	print_blocklist (sector, 0, offset, length); | ||||
|     } | ||||
| 
 | ||||
|   void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num, | ||||
| 			unsigned offset, unsigned length) | ||||
|     { | ||||
|       if (num_entries++) | ||||
| 	grub_printf (","); | ||||
| 
 | ||||
|       grub_printf ("%llu", (unsigned long long) (sector - part_start)); | ||||
|       if (num > 0) | ||||
| 	grub_printf ("+%u", num); | ||||
|       if (offset != 0 || length != 0) | ||||
| 	grub_printf ("[%u-%u]", offset, offset + length); | ||||
|     } | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); | ||||
| 
 | ||||
|   file = grub_file_open (args[0]); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (! file->device->disk) | ||||
|     return grub_error (GRUB_ERR_BAD_DEVICE, | ||||
| 		       "this command is available only for disk devices"); | ||||
| 
 | ||||
|   part_start = grub_partition_get_start (file->device->disk->partition); | ||||
| 
 | ||||
|   file->read_hook = read_blocklist; | ||||
| 
 | ||||
|   while (grub_file_read (file, buf, sizeof (buf)) > 0) | ||||
|     ; | ||||
| 
 | ||||
|   if (num_sectors > 0) | ||||
|     print_blocklist (start_sector, num_sectors, 0, 0); | ||||
| 
 | ||||
|   grub_file_close (file); | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(blocklist) | ||||
| { | ||||
|   cmd = grub_register_command ("blocklist", grub_cmd_blocklist, | ||||
| 			       N_("FILE"), N_("Print a block list.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(blocklist) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										196
									
								
								grub-core/commands/boot.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								grub-core/commands/boot.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,196 @@ | |||
| /* boot.c - command to boot an operating system */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2002,2003,2004,2005,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/normal.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/loader.h> | ||||
| #include <grub/kernel.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
|   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; | ||||
| }; | ||||
| 
 | ||||
| static int grub_loader_loaded; | ||||
| static struct grub_preboot_t *preboots_head = 0, | ||||
|   *preboots_tail = 0; | ||||
| 
 | ||||
| int | ||||
| grub_loader_is_loaded (void) | ||||
| { | ||||
|   return grub_loader_loaded; | ||||
| } | ||||
| 
 | ||||
| /* Register a preboot hook. */ | ||||
| void * | ||||
| 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; | ||||
| 
 | ||||
|   if (! preboot_func && ! preboot_rest_func) | ||||
|     return 0; | ||||
| 
 | ||||
|   new_preboot = (struct grub_preboot_t *) | ||||
|     grub_malloc (sizeof (struct grub_preboot_t)); | ||||
|   if (! new_preboot) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_OUT_OF_MEMORY, "hook not added"); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   new_preboot->preboot_func = preboot_func; | ||||
|   new_preboot->preboot_rest_func = preboot_rest_func; | ||||
|   new_preboot->prio = prio; | ||||
| 
 | ||||
|   for (cur = preboots_head; cur && cur->prio > prio; cur = cur->next); | ||||
| 
 | ||||
|   if (cur) | ||||
|     { | ||||
|       new_preboot->next = cur; | ||||
|       new_preboot->prev = cur->prev; | ||||
|       cur->prev = new_preboot; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       new_preboot->next = 0; | ||||
|       new_preboot->prev = preboots_tail; | ||||
|       preboots_tail = new_preboot; | ||||
|     } | ||||
|   if (new_preboot->prev) | ||||
|     new_preboot->prev->next = new_preboot; | ||||
|   else | ||||
|     preboots_head = new_preboot; | ||||
| 
 | ||||
|   return new_preboot; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_loader_unregister_preboot_hook (void *hnd) | ||||
| { | ||||
|   struct grub_preboot_t *preb = hnd; | ||||
| 
 | ||||
|   if (preb->next) | ||||
|     preb->next->prev = preb->prev; | ||||
|   else | ||||
|     preboots_tail = preb->prev; | ||||
|   if (preb->prev) | ||||
|     preb->prev->next = preb->next; | ||||
|   else | ||||
|     preboots_head = preb->next; | ||||
| 
 | ||||
|   grub_free (preb); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_loader_set (grub_err_t (*boot) (void), | ||||
| 		 grub_err_t (*unload) (void), | ||||
| 		 int noreturn) | ||||
| { | ||||
|   if (grub_loader_loaded && grub_loader_unload_func) | ||||
|     grub_loader_unload_func (); | ||||
| 
 | ||||
|   grub_loader_boot_func = boot; | ||||
|   grub_loader_unload_func = unload; | ||||
|   grub_loader_noreturn = noreturn; | ||||
| 
 | ||||
|   grub_loader_loaded = 1; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_loader_unset(void) | ||||
| { | ||||
|   if (grub_loader_loaded && grub_loader_unload_func) | ||||
|     grub_loader_unload_func (); | ||||
| 
 | ||||
|   grub_loader_boot_func = 0; | ||||
|   grub_loader_unload_func = 0; | ||||
| 
 | ||||
|   grub_loader_loaded = 0; | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_loader_boot (void) | ||||
| { | ||||
|   grub_err_t err = GRUB_ERR_NONE; | ||||
|   struct grub_preboot_t *cur; | ||||
| 
 | ||||
|   if (! grub_loader_loaded) | ||||
|     return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel"); | ||||
| 
 | ||||
|   if (grub_loader_noreturn) | ||||
|     grub_machine_fini (); | ||||
| 
 | ||||
|   for (cur = preboots_head; cur; cur = cur->next) | ||||
|     { | ||||
|       err = cur->preboot_func (grub_loader_noreturn); | ||||
|       if (err) | ||||
| 	{ | ||||
| 	  for (cur = cur->prev; cur; cur = cur->prev) | ||||
| 	    cur->preboot_rest_func (); | ||||
| 	  return err; | ||||
| 	} | ||||
|     } | ||||
|   err = (grub_loader_boot_func) (); | ||||
| 
 | ||||
|   for (cur = preboots_tail; cur; cur = cur->prev) | ||||
|     if (! err) | ||||
|       err = cur->preboot_rest_func (); | ||||
|     else | ||||
|       cur->preboot_rest_func (); | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| /* boot */ | ||||
| static grub_err_t | ||||
| grub_cmd_boot (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		    int argc __attribute__ ((unused)), | ||||
| 		    char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   return grub_loader_boot (); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| static grub_command_t cmd_boot; | ||||
| 
 | ||||
| GRUB_MOD_INIT(boot) | ||||
| { | ||||
|   cmd_boot = | ||||
|     grub_register_command ("boot", grub_cmd_boot, | ||||
| 			   0, N_("Boot an operating system.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(boot) | ||||
| { | ||||
|   grub_unregister_command (cmd_boot); | ||||
| } | ||||
							
								
								
									
										103
									
								
								grub-core/commands/cat.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								grub-core/commands/cat.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | |||
| /* cat.c - command to show the contents of a file  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2003,2005,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/gzio.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"dos", -1, 0, N_("Accept DOS-style CR/NL line endings."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   int dos = 0; | ||||
|   grub_file_t file; | ||||
|   char buf[GRUB_DISK_SECTOR_SIZE]; | ||||
|   grub_ssize_t size; | ||||
|   int key = 0; | ||||
| 
 | ||||
|   if (state[0].set) | ||||
|     dos = 1; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); | ||||
| 
 | ||||
|   file = grub_gzfile_open (args[0], 1); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   while ((size = grub_file_read (file, buf, sizeof (buf))) > 0 | ||||
| 	 && key != GRUB_TERM_ESC) | ||||
|     { | ||||
|       int i; | ||||
| 
 | ||||
|       for (i = 0; i < size; i++) | ||||
| 	{ | ||||
| 	  unsigned char c = buf[i]; | ||||
| 
 | ||||
| 	  if ((grub_isprint (c) || grub_isspace (c)) && c != '\r') | ||||
| 	    grub_printf ("%c", c); | ||||
| 	  else if (dos && c == '\r' && i + 1 < size && buf[i + 1] == '\n') | ||||
| 	    { | ||||
| 	      grub_printf ("\n"); | ||||
| 	      i++; | ||||
| 	    } | ||||
| 	  else | ||||
| 	    { | ||||
| 	      grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); | ||||
| 	      grub_printf ("<%x>", (int) c); | ||||
| 	      grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       while (grub_checkkey () >= 0 && | ||||
| 	     (key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != GRUB_TERM_ESC) | ||||
| 	; | ||||
|     } | ||||
| 
 | ||||
|   grub_xputs ("\n"); | ||||
|   grub_refresh (); | ||||
|   grub_file_close (file); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(cat) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("cat", grub_cmd_cat, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("FILE"), N_("Show the contents of a file."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(cat) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										119
									
								
								grub-core/commands/cmp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								grub-core/commands/cmp.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | |||
| /* cmd.c - command to cmp an operating system */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2003,2005,2006,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/gzio.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| #define BUFFER_SIZE 512 | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), | ||||
| 	      int argc, char **args) | ||||
| { | ||||
|   grub_ssize_t rd1, rd2; | ||||
|   grub_off_t pos; | ||||
|   grub_file_t file1 = 0; | ||||
|   grub_file_t file2 = 0; | ||||
|   char *buf1 = 0; | ||||
|   char *buf2 = 0; | ||||
| 
 | ||||
|   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]); | ||||
| 
 | ||||
|   file1 = grub_gzfile_open (args[0], 1); | ||||
|   file2 = grub_gzfile_open (args[1], 1); | ||||
|   if (! file1 || ! file2) | ||||
|     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]); | ||||
|   else | ||||
|     { | ||||
|       pos = 0; | ||||
| 
 | ||||
|       buf1 = grub_malloc (BUFFER_SIZE); | ||||
|       buf2 = grub_malloc (BUFFER_SIZE); | ||||
| 
 | ||||
|       if (! buf1 || ! buf2) | ||||
|         goto cleanup; | ||||
| 
 | ||||
|       do | ||||
| 	{ | ||||
| 	  int i; | ||||
| 
 | ||||
| 	  rd1 = grub_file_read (file1, buf1, BUFFER_SIZE); | ||||
| 	  rd2 = grub_file_read (file2, buf2, BUFFER_SIZE); | ||||
| 
 | ||||
| 	  if (rd1 != rd2) | ||||
| 	    goto cleanup; | ||||
| 
 | ||||
| 	  for (i = 0; i < rd2; i++) | ||||
| 	    { | ||||
| 	      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]); | ||||
| 		  goto cleanup; | ||||
| 		} | ||||
| 	    } | ||||
| 	  pos += BUFFER_SIZE; | ||||
| 
 | ||||
| 	} | ||||
|       while (rd2); | ||||
| 
 | ||||
|       grub_printf ("The files are identical.\n"); | ||||
|     } | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|   if (buf1) | ||||
|     grub_free (buf1); | ||||
|   if (buf2) | ||||
|     grub_free (buf2); | ||||
|   if (file1) | ||||
|     grub_file_close (file1); | ||||
|   if (file2) | ||||
|     grub_file_close (file2); | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(cmp) | ||||
| { | ||||
|   cmd = grub_register_command ("cmp", grub_cmd_cmp, | ||||
| 			       N_("FILE1 FILE2"), N_("Compare two files.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(cmp) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										75
									
								
								grub-core/commands/configfile.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								grub-core/commands/configfile.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | |||
| /* configfile.c - command to manually load config file  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2006,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_source (grub_command_t cmd, int argc, char **args) | ||||
| { | ||||
|   int new_env; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); | ||||
| 
 | ||||
|   new_env = (cmd->name[0] == 'c'); | ||||
| 
 | ||||
|   if (new_env) | ||||
|     { | ||||
|       grub_cls (); | ||||
|       grub_env_context_open (1); | ||||
|     } | ||||
| 
 | ||||
|   grub_normal_execute (args[0], 1, ! new_env); | ||||
| 
 | ||||
|   if (new_env) | ||||
|     grub_env_context_close (); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_configfile, cmd_source, cmd_dot; | ||||
|  | ||||
| GRUB_MOD_INIT(configfile) | ||||
| { | ||||
|   cmd_configfile = | ||||
|     grub_register_command ("configfile", grub_cmd_source, | ||||
| 			   N_("FILE"), N_("Load another config file.")); | ||||
|   cmd_source = | ||||
|     grub_register_command ("source", grub_cmd_source, | ||||
| 			   N_("FILE"), | ||||
| 			   N_("Load another config file without changing context.") | ||||
| 			   ); | ||||
|   cmd_dot = | ||||
|     grub_register_command (".", grub_cmd_source, | ||||
| 			   N_("FILE"), | ||||
| 			   N_("Load another config file without changing context.") | ||||
| 			   ); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(configfile) | ||||
| { | ||||
|   grub_unregister_command (cmd_configfile); | ||||
|   grub_unregister_command (cmd_source); | ||||
|   grub_unregister_command (cmd_dot); | ||||
| } | ||||
							
								
								
									
										71
									
								
								grub-core/commands/crc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								grub-core/commands/crc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| /* crc.c - command to calculate the crc32 checksum of a file  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/lib/crc.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)), | ||||
| 	      int argc, char **args) | ||||
| 
 | ||||
| { | ||||
|   grub_file_t file; | ||||
|   char buf[GRUB_DISK_SECTOR_SIZE]; | ||||
|   grub_ssize_t size; | ||||
|   grub_uint32_t crc; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); | ||||
| 
 | ||||
|   file = grub_file_open (args[0]); | ||||
|   if (! file) | ||||
|     return 0; | ||||
| 
 | ||||
|   crc = 0; | ||||
|   while ((size = grub_file_read (file, buf, sizeof (buf))) > 0) | ||||
|     crc = grub_getcrc32 (crc, buf, size); | ||||
| 
 | ||||
|   if (grub_errno) | ||||
|     goto fail; | ||||
| 
 | ||||
|   grub_printf ("%08x\n", crc); | ||||
| 
 | ||||
|  fail: | ||||
|   grub_file_close (file); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(crc) | ||||
| { | ||||
|   cmd = grub_register_command ("crc", grub_cmd_crc, | ||||
| 			       N_("FILE"), | ||||
| 			       N_("Calculate the crc32 checksum of a file.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(crc) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										146
									
								
								grub-core/commands/date.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								grub-core/commands/date.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,146 @@ | |||
| /* date.c - command to display/set current datetime.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/datetime.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| #define GRUB_DATETIME_SET_YEAR		1 | ||||
| #define GRUB_DATETIME_SET_MONTH		2 | ||||
| #define GRUB_DATETIME_SET_DAY		4 | ||||
| #define GRUB_DATETIME_SET_HOUR		8 | ||||
| #define GRUB_DATETIME_SET_MINUTE	16 | ||||
| #define GRUB_DATETIME_SET_SECOND	32 | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_date (grub_command_t cmd __attribute__ ((unused)), | ||||
|                int argc, char **args) | ||||
| { | ||||
|   struct grub_datetime datetime; | ||||
|   int limit[6][2] = {{1980, 2079}, {1, 12}, {1, 31}, {0, 23}, {0, 59}, {0, 59}}; | ||||
|   int value[6], mask; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     { | ||||
|       if (grub_get_datetime (&datetime)) | ||||
|         return grub_errno; | ||||
| 
 | ||||
|       grub_printf ("%d-%02d-%02d %02d:%02d:%02d %s\n", | ||||
|                    datetime.year, datetime.month, datetime.day, | ||||
|                    datetime.hour, datetime.minute, datetime.second, | ||||
|                    grub_get_weekday_name (&datetime)); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   grub_memset (&value, 0, sizeof (value)); | ||||
|   mask = 0; | ||||
| 
 | ||||
|   for (; argc; argc--, args++) | ||||
|     { | ||||
|       char *p, c; | ||||
|       int m1, ofs, n, cur_mask; | ||||
| 
 | ||||
|       p = args[0]; | ||||
|       m1 = grub_strtoul (p, &p, 10); | ||||
| 
 | ||||
|       c = *p; | ||||
|       if (c == '-') | ||||
|         ofs = 0; | ||||
|       else if (c == ':') | ||||
|         ofs = 3; | ||||
|       else | ||||
|         goto fail; | ||||
| 
 | ||||
|       value[ofs] = m1; | ||||
|       cur_mask = (1 << ofs); | ||||
|       mask &= ~(cur_mask * (1 + 2 + 4)); | ||||
| 
 | ||||
|       for (n = 1; (n < 3) && (*p); n++) | ||||
|         { | ||||
|           if (*p != c) | ||||
|             goto fail; | ||||
| 
 | ||||
|           value[ofs + n] = grub_strtoul (p + 1, &p, 10); | ||||
|           cur_mask |= (1 << (ofs + n)); | ||||
|         } | ||||
| 
 | ||||
|       if (*p) | ||||
|         goto fail; | ||||
| 
 | ||||
|       if ((ofs == 0) && (n == 2)) | ||||
|         { | ||||
|           value[ofs + 2] = value[ofs + 1]; | ||||
|           value[ofs + 1] = value[ofs]; | ||||
|           ofs++; | ||||
|           cur_mask <<= 1; | ||||
|         } | ||||
| 
 | ||||
|       for (; n; n--, ofs++) | ||||
|         if ((value [ofs] < limit[ofs][0]) || | ||||
|             (value [ofs] > limit[ofs][1])) | ||||
|           goto fail; | ||||
| 
 | ||||
|       mask |= cur_mask; | ||||
|     } | ||||
| 
 | ||||
|   if (grub_get_datetime (&datetime)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (mask & GRUB_DATETIME_SET_YEAR) | ||||
|     datetime.year = value[0]; | ||||
| 
 | ||||
|   if (mask & GRUB_DATETIME_SET_MONTH) | ||||
|     datetime.month = value[1]; | ||||
| 
 | ||||
|   if (mask & GRUB_DATETIME_SET_DAY) | ||||
|     datetime.day = value[2]; | ||||
| 
 | ||||
|   if (mask & GRUB_DATETIME_SET_HOUR) | ||||
|     datetime.hour = value[3]; | ||||
| 
 | ||||
|   if (mask & GRUB_DATETIME_SET_MINUTE) | ||||
|     datetime.minute = value[4]; | ||||
| 
 | ||||
|   if (mask & GRUB_DATETIME_SET_SECOND) | ||||
|     datetime.second = value[5]; | ||||
| 
 | ||||
|   return grub_set_datetime (&datetime); | ||||
| 
 | ||||
| fail: | ||||
|   return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid datetime"); | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(date) | ||||
| { | ||||
|   cmd = | ||||
|     grub_register_command ("date", grub_cmd_date, | ||||
| 			   N_("[[year-]month-day] [hour:minute[:second]]"), | ||||
| 			   N_("Command to display/set current datetime.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(date) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										124
									
								
								grub-core/commands/echo.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								grub-core/commands/echo.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,124 @@ | |||
| /* echo.c - Command to display a line of text  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {0, 'n', 0, N_("Do not output the trailing newline."), 0, 0}, | ||||
|     {0, 'e', 0, N_("Enable interpretation of backslash escapes."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_echo (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   int newline = 1; | ||||
|   int i; | ||||
| 
 | ||||
|   /* Check if `-n' was used.  */ | ||||
|   if (state[0].set) | ||||
|     newline = 0; | ||||
| 
 | ||||
|   for (i = 0; i < argc; i++) | ||||
|     { | ||||
|       char *arg = *args; | ||||
|       args++; | ||||
| 
 | ||||
|       while (*arg) | ||||
| 	{ | ||||
| 	  /* In case `-e' is used, parse backslashes.  */ | ||||
| 	  if (*arg == '\\' && state[1].set) | ||||
| 	    { | ||||
| 	      arg++; | ||||
| 	      if (*arg == '\0') | ||||
| 		break; | ||||
| 
 | ||||
| 	      switch (*arg) | ||||
| 		{ | ||||
| 		case '\\': | ||||
| 		  grub_printf ("\\"); | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 'a': | ||||
| 		  grub_printf ("\a"); | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 'c': | ||||
| 		  newline = 0; | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 'f': | ||||
| 		  grub_printf ("\f"); | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 'n': | ||||
| 		  grub_printf ("\n"); | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 'r': | ||||
| 		  grub_printf ("\r"); | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 't': | ||||
| 		  grub_printf ("\t"); | ||||
| 		  break; | ||||
| 
 | ||||
| 		case 'v': | ||||
| 		  grub_printf ("\v"); | ||||
| 		  break; | ||||
| 		} | ||||
| 	      arg++; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* This was not an escaped character, or escaping is not
 | ||||
| 	     enabled.  */ | ||||
| 	  grub_printf ("%c", *arg); | ||||
| 	  arg++; | ||||
| 	} | ||||
| 
 | ||||
|       /* If another argument follows, insert a space.  */ | ||||
|       if (i != argc - 1) | ||||
| 	grub_printf (" " ); | ||||
|     } | ||||
| 
 | ||||
|   if (newline) | ||||
|     grub_printf ("\n"); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(echo) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("echo", grub_cmd_echo, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[-e|-n] STRING"), N_("Display a line of text."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(echo) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										59
									
								
								grub-core/commands/efi/acpi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								grub-core/commands/efi/acpi.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| /* acpi.c - get acpi tables. */ | ||||
| /*
 | ||||
|  *  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/acpi.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/efi/efi.h> | ||||
| #include <grub/efi/api.h> | ||||
| 
 | ||||
| struct grub_acpi_rsdp_v10 * | ||||
| grub_machine_acpi_get_rsdpv1 (void) | ||||
| { | ||||
|   unsigned i; | ||||
|   static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; | ||||
| 
 | ||||
|   for (i = 0; i < grub_efi_system_table->num_table_entries; i++) | ||||
|     { | ||||
|       grub_efi_guid_t *guid = | ||||
| 	&grub_efi_system_table->configuration_table[i].vendor_guid; | ||||
| 
 | ||||
|       if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t))) | ||||
| 	return (struct grub_acpi_rsdp_v10 *) | ||||
| 	  grub_efi_system_table->configuration_table[i].vendor_table; | ||||
|     } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| struct grub_acpi_rsdp_v20 * | ||||
| grub_machine_acpi_get_rsdpv2 (void) | ||||
| { | ||||
|   unsigned i; | ||||
|   static grub_efi_guid_t acpi20_guid = GRUB_EFI_ACPI_20_TABLE_GUID; | ||||
| 
 | ||||
|   for (i = 0; i < grub_efi_system_table->num_table_entries; i++) | ||||
|     { | ||||
|       grub_efi_guid_t *guid = | ||||
| 	&grub_efi_system_table->configuration_table[i].vendor_guid; | ||||
| 
 | ||||
|       if (! grub_memcmp (guid, &acpi20_guid, sizeof (grub_efi_guid_t))) | ||||
| 	return (struct grub_acpi_rsdp_v20 *) | ||||
| 	  grub_efi_system_table->configuration_table[i].vendor_table; | ||||
|     } | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										110
									
								
								grub-core/commands/efi/fixvideo.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								grub-core/commands/efi/fixvideo.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | |||
| /* fixvideo.c - fix video problem in efi */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static struct grub_video_patch | ||||
| { | ||||
|   const char *name; | ||||
|   grub_uint32_t pci_id; | ||||
|   grub_uint32_t mmio_bar; | ||||
|   grub_uint32_t mmio_reg; | ||||
|   grub_uint32_t mmio_old; | ||||
| } video_patches[] = | ||||
|   { | ||||
|     {"Intel 945GM", 0x27a28086, 0, 0x71184, 0x1000000}, /* DSPBBASE  */ | ||||
|     {"Intel 965GM", 0x2a028086, 0, 0x7119C, 0x1000000}, /* DSPBSURF  */ | ||||
|     {0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static int NESTED_FUNC_ATTR | ||||
| scan_card (grub_pci_device_t dev, grub_pci_id_t pciid) | ||||
| { | ||||
|   grub_pci_address_t addr; | ||||
| 
 | ||||
|   addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); | ||||
|   if (grub_pci_read_byte (addr + 3) == 0x3) | ||||
|     { | ||||
|       struct grub_video_patch *p = video_patches; | ||||
| 
 | ||||
|       while (p->name) | ||||
| 	{ | ||||
| 	  if (p->pci_id == pciid) | ||||
| 	    { | ||||
| 	      grub_target_addr_t base; | ||||
| 
 | ||||
| 	      grub_printf ("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); | ||||
| 	      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"); | ||||
| 		  else | ||||
| 		    { | ||||
| 		      *((volatile grub_uint32_t *) base) = 0; | ||||
| 		      if (*((volatile grub_uint32_t *) base)) | ||||
| 			grub_printf ("Set MMIO fails\n"); | ||||
| 		    } | ||||
| 		} | ||||
| 
 | ||||
| 	      return 1; | ||||
| 	    } | ||||
| 	  p++; | ||||
| 	} | ||||
| 
 | ||||
|       grub_printf ("Unknown graphic card: %x\n", pciid); | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_fixvideo (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		   int argc __attribute__ ((unused)), | ||||
| 		   char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   grub_pci_iterate (scan_card); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_fixvideo; | ||||
| 
 | ||||
| GRUB_MOD_INIT(fixvideo) | ||||
| { | ||||
|   cmd_fixvideo = grub_register_command ("fix_video", grub_cmd_fixvideo, | ||||
| 					0, N_("Fix video problem.")); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(fixvideo) | ||||
| { | ||||
|   grub_unregister_command (cmd_fixvideo); | ||||
| } | ||||
							
								
								
									
										218
									
								
								grub-core/commands/efi/loadbios.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								grub-core/commands/efi/loadbios.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,218 @@ | |||
| /* loadbios.c - command to load a bios dump  */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/efi/efi.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; | ||||
| static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; | ||||
| static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID; | ||||
| 
 | ||||
| #define EBDA_SEG_ADDR	0x40e | ||||
| #define LOW_MEM_ADDR	0x413 | ||||
| #define FAKE_EBDA_SEG	0x9fc0 | ||||
| 
 | ||||
| #define BLANK_MEM	0xffffffff | ||||
| #define VBIOS_ADDR	0xc0000 | ||||
| #define SBIOS_ADDR	0xf0000 | ||||
| 
 | ||||
| static int | ||||
| enable_rom_area (void) | ||||
| { | ||||
|   grub_pci_address_t addr; | ||||
|   grub_uint32_t *rom_ptr; | ||||
|   grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0}; | ||||
| 
 | ||||
|   rom_ptr = (grub_uint32_t *) VBIOS_ADDR; | ||||
|   if (*rom_ptr != BLANK_MEM) | ||||
|     { | ||||
|       grub_printf ("ROM image is present.\n"); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   /* FIXME: should be macroified.  */ | ||||
|   addr = grub_pci_make_address (dev, 144); | ||||
|   grub_pci_write_byte (addr++, 0x30); | ||||
|   grub_pci_write_byte (addr++, 0x33); | ||||
|   grub_pci_write_byte (addr++, 0x33); | ||||
|   grub_pci_write_byte (addr++, 0x33); | ||||
|   grub_pci_write_byte (addr++, 0x33); | ||||
|   grub_pci_write_byte (addr++, 0x33); | ||||
|   grub_pci_write_byte (addr++, 0x33); | ||||
|   grub_pci_write_byte (addr, 0); | ||||
| 
 | ||||
|   *rom_ptr = 0; | ||||
|   if (*rom_ptr != 0) | ||||
|     { | ||||
|       grub_printf ("Can\'t enable ROM area.\n"); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| lock_rom_area (void) | ||||
| { | ||||
|   grub_pci_address_t addr; | ||||
|   grub_pci_device_t dev = { .bus = 0, .device = 0, .function = 0}; | ||||
| 
 | ||||
|   /* FIXME: should be macroified.  */ | ||||
|   addr = grub_pci_make_address (dev, 144); | ||||
|   grub_pci_write_byte (addr++, 0x10); | ||||
|   grub_pci_write_byte (addr++, 0x11); | ||||
|   grub_pci_write_byte (addr++, 0x11); | ||||
|   grub_pci_write_byte (addr++, 0x11); | ||||
|   grub_pci_write_byte (addr, 0x11); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| fake_bios_data (int use_rom) | ||||
| { | ||||
|   unsigned i; | ||||
|   void *acpi, *smbios; | ||||
|   grub_uint16_t *ebda_seg_ptr, *low_mem_ptr; | ||||
| 
 | ||||
|   ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR; | ||||
|   low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR; | ||||
|   if ((*ebda_seg_ptr) || (*low_mem_ptr)) | ||||
|     return; | ||||
| 
 | ||||
|   acpi = 0; | ||||
|   smbios = 0; | ||||
|   for (i = 0; i < grub_efi_system_table->num_table_entries; i++) | ||||
|     { | ||||
|       grub_efi_guid_t *guid = | ||||
| 	&grub_efi_system_table->configuration_table[i].vendor_guid; | ||||
| 
 | ||||
|       if (! grub_memcmp (guid, &acpi2_guid, sizeof (grub_efi_guid_t))) | ||||
| 	{ | ||||
| 	  acpi = grub_efi_system_table->configuration_table[i].vendor_table; | ||||
| 	  grub_dprintf ("efi", "ACPI2: %p\n", acpi); | ||||
| 	} | ||||
|       else if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t))) | ||||
| 	{ | ||||
| 	  void *t; | ||||
| 
 | ||||
| 	  t = grub_efi_system_table->configuration_table[i].vendor_table; | ||||
| 	  if (! acpi) | ||||
| 	    acpi = t; | ||||
| 	  grub_dprintf ("efi", "ACPI: %p\n", t); | ||||
| 	} | ||||
|       else if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_guid_t))) | ||||
| 	{ | ||||
| 	  smbios = grub_efi_system_table->configuration_table[i].vendor_table; | ||||
| 	  grub_dprintf ("efi", "SMBIOS: %p\n", smbios); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   *ebda_seg_ptr = FAKE_EBDA_SEG; | ||||
|   *low_mem_ptr = (FAKE_EBDA_SEG >> 6); | ||||
| 
 | ||||
|   *((grub_uint16_t *) (FAKE_EBDA_SEG << 4)) = 640 - *low_mem_ptr; | ||||
| 
 | ||||
|   if (acpi) | ||||
|     grub_memcpy ((char *) ((FAKE_EBDA_SEG << 4) + 16), acpi, 1024 - 16); | ||||
| 
 | ||||
|   if ((use_rom) && (smbios)) | ||||
|     grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios + 16, 16); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_fakebios (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		   int argc __attribute__ ((unused)), | ||||
| 		   char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   if (enable_rom_area ()) | ||||
|     { | ||||
|       fake_bios_data (1); | ||||
|       lock_rom_area (); | ||||
|     } | ||||
|   else | ||||
|     fake_bios_data (0); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		   int argc, char *argv[]) | ||||
| { | ||||
|   grub_file_t file; | ||||
|   int size; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no ROM image specified"); | ||||
| 
 | ||||
|   if (argc > 1) | ||||
|     { | ||||
|       file = grub_file_open (argv[1]); | ||||
|       if (! file) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       if (file->size != 4) | ||||
| 	grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid int10 dump size"); | ||||
|       else | ||||
| 	grub_file_read (file, (void *) 0x40, 4); | ||||
| 
 | ||||
|       grub_file_close (file); | ||||
|       if (grub_errno) | ||||
| 	return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   file = grub_file_open (argv[0]); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   size = file->size; | ||||
|   if ((size < 0x10000) || (size > 0x40000)) | ||||
|     grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid bios dump size"); | ||||
|   else if (enable_rom_area ()) | ||||
|     { | ||||
|       grub_file_read (file, (void *) VBIOS_ADDR, size); | ||||
|       fake_bios_data (size <= 0x40000); | ||||
|       lock_rom_area (); | ||||
|     } | ||||
| 
 | ||||
|   grub_file_close (file); | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_fakebios, cmd_loadbios; | ||||
| 
 | ||||
| GRUB_MOD_INIT(loadbios) | ||||
| { | ||||
|   cmd_fakebios = grub_register_command ("fakebios", grub_cmd_fakebios, | ||||
| 					0, N_("Fake BIOS.")); | ||||
| 
 | ||||
|   cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, | ||||
| 					"BIOS_DUMP [INT10_DUMP]", | ||||
| 					N_("Load BIOS dump.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(loadbios) | ||||
| { | ||||
|   grub_unregister_command (cmd_fakebios); | ||||
|   grub_unregister_command (cmd_loadbios); | ||||
| } | ||||
							
								
								
									
										96
									
								
								grub-core/commands/extcmd.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								grub-core/commands/extcmd.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| /* extcmd.c - support extended command */ | ||||
| /*
 | ||||
|  *  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/mm.h> | ||||
| #include <grub/list.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_extcmd_dispatcher (struct grub_command *cmd, | ||||
| 			int argc, char **args) | ||||
| { | ||||
|   int new_argc; | ||||
|   char **new_args; | ||||
|   struct grub_arg_option *parser; | ||||
|   struct grub_arg_list *state; | ||||
|   int maxargs = 0; | ||||
|   grub_err_t ret; | ||||
|   grub_extcmd_t ext; | ||||
| 
 | ||||
|   ext = cmd->data; | ||||
|   parser = (struct grub_arg_option *) ext->options; | ||||
|   while (parser && (parser++)->doc) | ||||
|     maxargs++; | ||||
| 
 | ||||
|   /* Set up the option state.  */ | ||||
|   state = grub_zalloc (sizeof (struct grub_arg_list) * maxargs); | ||||
| 
 | ||||
|   if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) | ||||
|     { | ||||
|       ext->state = state; | ||||
|       ret = (ext->func) (ext, new_argc, new_args); | ||||
|       grub_free (new_args); | ||||
|     } | ||||
|   else | ||||
|     ret = grub_errno; | ||||
| 
 | ||||
|   grub_free (state); | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| grub_extcmd_t | ||||
| grub_register_extcmd (const char *name, grub_extcmd_func_t func, | ||||
| 		      unsigned flags, const char *summary, | ||||
| 		      const char *description, | ||||
| 		      const struct grub_arg_option *parser) | ||||
| { | ||||
|   grub_extcmd_t ext; | ||||
|   grub_command_t cmd; | ||||
| 
 | ||||
|   ext = (grub_extcmd_t) grub_malloc (sizeof (*ext)); | ||||
|   if (! ext) | ||||
|     return 0; | ||||
| 
 | ||||
|   cmd = grub_register_command_prio (name, grub_extcmd_dispatcher, | ||||
| 				    summary, description, 1); | ||||
|   if (! cmd) | ||||
|     { | ||||
|       grub_free (ext); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   cmd->flags = (flags | GRUB_COMMAND_FLAG_EXTCMD); | ||||
|   cmd->data = ext; | ||||
| 
 | ||||
|   ext->cmd = cmd; | ||||
|   ext->func = func; | ||||
|   ext->options = parser; | ||||
|   ext->data = 0; | ||||
| 
 | ||||
|   return ext; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_unregister_extcmd (grub_extcmd_t ext) | ||||
| { | ||||
|   grub_unregister_command (ext->cmd); | ||||
|   grub_free (ext); | ||||
| } | ||||
							
								
								
									
										256
									
								
								grub-core/commands/gptsync.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								grub-core/commands/gptsync.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,256 @@ | |||
| /* gptsync.c - fill the mbr based on gpt entries  */ | ||||
| /* XXX: I don't know what to do if sector size isn't 512 bytes */ | ||||
| /*
 | ||||
|  *  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/command.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/msdos_partition.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/fs.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| /* Convert a LBA address to a CHS address in the INT 13 format.  */ | ||||
| /* Taken from grub1. */ | ||||
| /* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63.
 | ||||
|    Is it a problem? | ||||
| */ | ||||
| static void | ||||
| lba_to_chs (int lba, grub_uint8_t *cl, grub_uint8_t *ch, | ||||
| 	    grub_uint8_t *dh) | ||||
| { | ||||
|   int cylinder, head, sector; | ||||
|   int sectors = 63, heads = 255, cylinders = 1024; | ||||
| 
 | ||||
|   sector = lba % sectors + 1; | ||||
|   head = (lba / sectors) % heads; | ||||
|   cylinder = lba / (sectors * heads); | ||||
| 
 | ||||
|   if (cylinder >= cylinders) | ||||
|     { | ||||
|       *cl = *ch = *dh = 0xff; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   *cl = sector | ((cylinder & 0x300) >> 2); | ||||
|   *ch = cylinder & 0xFF; | ||||
|   *dh = head; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		  int argc, char **args) | ||||
| { | ||||
|   grub_device_t dev; | ||||
|   struct grub_msdos_partition_mbr mbr; | ||||
|   struct grub_partition *partition; | ||||
|   grub_disk_addr_t first_sector; | ||||
|   int numactive = 0; | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); | ||||
|   if (argc > 4) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be " | ||||
| 		       "in hybrid MBR"); | ||||
| 
 | ||||
|   if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')') | ||||
|     { | ||||
|       args[0][grub_strlen (args[0]) - 1] = 0; | ||||
|       dev = grub_device_open (args[0] + 1); | ||||
|       args[0][grub_strlen (args[0])] = ')'; | ||||
|     } | ||||
|   else | ||||
|     dev = grub_device_open (args[0]); | ||||
| 
 | ||||
|   if (! dev) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (! dev->disk) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk"); | ||||
|     } | ||||
| 
 | ||||
|   /* Read the protective MBR.  */ | ||||
|   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr)) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if it is valid.  */ | ||||
|   if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE)) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); | ||||
|     } | ||||
| 
 | ||||
|   /* Make sure the MBR is a protective MBR and not a normal MBR.  */ | ||||
|   if (mbr.entries[0].type != GRUB_PC_PARTITION_TYPE_GPT_DISK) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found"); | ||||
|     } | ||||
| 
 | ||||
|   int i; | ||||
|   first_sector = dev->disk->total_sectors; | ||||
|   for (i = 1; i < argc; i++) | ||||
|     { | ||||
|       char *separator, csep = 0; | ||||
|       grub_uint8_t type; | ||||
|       separator = grub_strchr (args[i], '+'); | ||||
|       if (! separator) | ||||
| 	separator = grub_strchr (args[i], '-'); | ||||
|       if (separator) | ||||
| 	{ | ||||
| 	  csep = *separator; | ||||
| 	  *separator = 0; | ||||
| 	} | ||||
|       partition = grub_partition_probe (dev->disk, args[i]); | ||||
|       if (separator) | ||||
| 	*separator = csep; | ||||
|       if (! partition) | ||||
| 	{ | ||||
| 	  grub_device_close (dev); | ||||
| 	  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such partition"); | ||||
| 	} | ||||
| 
 | ||||
|       if (partition->start + partition->len > 0xffffffff) | ||||
| 	{ | ||||
| 	  grub_device_close (dev); | ||||
| 	  return grub_error (GRUB_ERR_OUT_OF_RANGE, | ||||
| 			     "only partitions residing in the first 2TB " | ||||
| 			     "can be present in hybrid MBR"); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
|       if (first_sector > partition->start) | ||||
| 	first_sector = partition->start; | ||||
| 
 | ||||
|       if (separator && *(separator + 1)) | ||||
| 	type = grub_strtoul (separator + 1, 0, 0); | ||||
|       else | ||||
| 	{ | ||||
| 	  grub_fs_t fs = 0; | ||||
| 	  dev->disk->partition = partition; | ||||
| 	  fs = grub_fs_probe (dev); | ||||
| 
 | ||||
| 	  /* Unknown filesystem isn't fatal. */ | ||||
| 	  if (grub_errno == GRUB_ERR_UNKNOWN_FS) | ||||
| 	    { | ||||
| 	      fs = 0; | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (fs && grub_strcmp (fs->name, "ntfs") == 0) | ||||
| 	    type = GRUB_PC_PARTITION_TYPE_NTFS; | ||||
| 	  else if (fs && grub_strcmp (fs->name, "fat") == 0) | ||||
| 	    /* FIXME: detect FAT16. */ | ||||
| 	    type = GRUB_PC_PARTITION_TYPE_FAT32_LBA; | ||||
| 	  else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0 | ||||
| 			  || grub_strcmp (fs->name, "hfs") == 0)) | ||||
| 	    type = GRUB_PC_PARTITION_TYPE_HFS; | ||||
| 	  else | ||||
| 	    /* FIXME: detect more types. */ | ||||
| 	    type = GRUB_PC_PARTITION_TYPE_EXT2FS; | ||||
| 
 | ||||
| 	  dev->disk->partition = 0; | ||||
| 	} | ||||
| 
 | ||||
|       mbr.entries[i].flag = (csep == '+') ? 0x80 : 0; | ||||
|       if (csep == '+') | ||||
| 	{ | ||||
| 	  numactive++; | ||||
| 	  if (numactive == 2) | ||||
| 	    { | ||||
| 	      grub_device_close (dev); | ||||
| 	      return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 				 "only one partition can be active"); | ||||
| 	    } | ||||
| 	} | ||||
|       mbr.entries[i].type = type; | ||||
|       mbr.entries[i].start = grub_cpu_to_le32 (partition->start); | ||||
|       lba_to_chs (partition->start, | ||||
| 		  &(mbr.entries[i].start_sector), | ||||
| 		  &(mbr.entries[i].start_cylinder), | ||||
| 		  &(mbr.entries[i].start_head)); | ||||
|       lba_to_chs (partition->start + partition->len - 1, | ||||
| 		  &(mbr.entries[i].end_sector), | ||||
| 		  &(mbr.entries[i].end_cylinder), | ||||
| 		  &(mbr.entries[i].end_head)); | ||||
|       mbr.entries[i].length = grub_cpu_to_le32 (partition->len); | ||||
|       grub_free (partition); | ||||
|     } | ||||
|   for (; i < 4; i++) | ||||
|     grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i])); | ||||
| 
 | ||||
|   /* The protective partition. */ | ||||
|   if (first_sector > 0xffffffff) | ||||
|     first_sector = 0xffffffff; | ||||
|   else | ||||
|     first_sector--; | ||||
|   mbr.entries[0].flag = 0; | ||||
|   mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK; | ||||
|   mbr.entries[0].start = grub_cpu_to_le32 (1); | ||||
|   lba_to_chs (1, | ||||
| 	      &(mbr.entries[0].start_sector), | ||||
| 	      &(mbr.entries[0].start_cylinder), | ||||
| 	      &(mbr.entries[0].start_head)); | ||||
|   lba_to_chs (first_sector, | ||||
| 	      &(mbr.entries[0].end_sector), | ||||
| 	      &(mbr.entries[0].end_cylinder), | ||||
| 	      &(mbr.entries[0].end_head)); | ||||
|   mbr.entries[0].length = grub_cpu_to_le32 (first_sector); | ||||
| 
 | ||||
|   mbr.signature = grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE); | ||||
| 
 | ||||
|   if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr)) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   grub_printf ("New MBR is written to '%s'\n", args[0]); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(gptsync) | ||||
| { | ||||
|   (void) mod;			/* To stop warning. */ | ||||
|   cmd = grub_register_command ("gptsync", grub_cmd_gptsync, | ||||
| 			       N_("DEVICE [PARTITION[+/-[TYPE]]] ..."), | ||||
| 			       N_("Fill hybrid MBR of GPT drive DEVICE. " | ||||
| 			       "Specified partitions will be a part " | ||||
| 			       "of hybrid MBR. Up to 3 partitions are " | ||||
| 			       "allowed. TYPE is an MBR type. " | ||||
| 			       "+ means that partition is active. " | ||||
| 			       "Only one partition can be active.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(gptsync) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										46
									
								
								grub-core/commands/halt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								grub-core/commands/halt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| /* halt.c - command to halt the computer.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| 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; | ||||
|  | ||||
| GRUB_MOD_INIT(halt) | ||||
| { | ||||
|   cmd = grub_register_command ("halt", grub_cmd_halt, | ||||
| 			       0, N_("Halts the computer.  This command does"  | ||||
| 			       " not work on all firmware implementations.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(halt) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										101
									
								
								grub-core/commands/handler.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								grub-core/commands/handler.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,101 @@ | |||
| /* handler.c - commands to list or select handlers */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/handler.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_handler (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		  int argc, char **args) | ||||
| { | ||||
|   void *curr_item = 0; | ||||
|   grub_handler_class_t head; | ||||
| 
 | ||||
|   auto int list_item (grub_named_list_t item); | ||||
|   int list_item (grub_named_list_t item) | ||||
|     { | ||||
|       if (item == curr_item) | ||||
| 	grub_putchar ('*'); | ||||
| 
 | ||||
|       grub_printf ("%s\n", item->name); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   head = grub_handler_class_list; | ||||
|   if (argc == 0) | ||||
|     { | ||||
|       grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_item); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       char *class_name; | ||||
|       grub_handler_class_t class; | ||||
| 
 | ||||
|       class_name = args[0]; | ||||
|       argc--; | ||||
|       args++; | ||||
| 
 | ||||
|       class = grub_named_list_find (GRUB_AS_NAMED_LIST (head), class_name); | ||||
|       if (! class) | ||||
| 	return grub_error (GRUB_ERR_FILE_NOT_FOUND, "class not found"); | ||||
| 
 | ||||
|       if (argc == 0) | ||||
| 	{ | ||||
| 	  curr_item = class->cur_handler; | ||||
| 	  grub_list_iterate (GRUB_AS_LIST (class->handler_list), | ||||
| 			     (grub_list_hook_t) list_item); | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  grub_handler_t handler; | ||||
| 
 | ||||
| 	  handler = | ||||
| 	    grub_named_list_find (GRUB_AS_NAMED_LIST (class->handler_list), | ||||
| 				  args[0]); | ||||
| 
 | ||||
| 	  if (! handler) | ||||
| 	    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "handler not found"); | ||||
| 
 | ||||
| 	  grub_handler_set_current (class, handler); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_handler; | ||||
| 
 | ||||
| GRUB_MOD_INIT(handler) | ||||
| { | ||||
|   cmd_handler = | ||||
|     grub_register_command ("handler", grub_cmd_handler, | ||||
| 			   N_("[class [handler]]"), | ||||
| 			   N_("List or select a handler.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(handler) | ||||
| { | ||||
|   grub_unregister_command (cmd_handler); | ||||
| } | ||||
							
								
								
									
										277
									
								
								grub-core/commands/hashsum.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								grub-core/commands/hashsum.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,277 @@ | |||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/crypto.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = { | ||||
|   {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING}, | ||||
|   {"check", 'c', 0, N_("Check hash list file."), N_("FILE"), ARG_TYPE_STRING}, | ||||
|   {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"), | ||||
|    ARG_TYPE_STRING}, | ||||
|   {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0}, | ||||
|   {0, 0, 0, 0, 0, 0} | ||||
| }; | ||||
| 
 | ||||
| struct { const char *name; const char *hashname; } aliases[] =  | ||||
|   { | ||||
|     {"sha256sum", "sha256"}, | ||||
|     {"sha512sum", "sha512"}, | ||||
|     {"md5sum", "md5"}, | ||||
|   }; | ||||
| 
 | ||||
| static inline int | ||||
| hextoval (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 -1; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result) | ||||
| { | ||||
|   grub_uint8_t context[hash->contextsize]; | ||||
|   grub_uint8_t readbuf[4096]; | ||||
| 
 | ||||
|   grub_memset (context, 0, sizeof (context)); | ||||
|   hash->init (context); | ||||
|   while (1) | ||||
|     { | ||||
|       grub_ssize_t r; | ||||
|       r = grub_file_read (file, readbuf, sizeof (readbuf)); | ||||
|       if (r < 0) | ||||
| 	return grub_errno; | ||||
|       if (r == 0) | ||||
| 	break; | ||||
|       hash->write (context, readbuf, r); | ||||
|     } | ||||
|   hash->final (context); | ||||
|   grub_memcpy (result, hash->read (context), hash->mdlen); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| check_list (const gcry_md_spec_t *hash, const char *hashfilename, | ||||
| 	    const char *prefix, int keep) | ||||
| { | ||||
|   grub_file_t hashlist, file; | ||||
|   char *buf = NULL; | ||||
|   grub_uint8_t expected[hash->mdlen]; | ||||
|   grub_uint8_t actual[hash->mdlen]; | ||||
|   grub_err_t err; | ||||
|   unsigned i; | ||||
|   unsigned unread = 0, mismatch = 0; | ||||
| 
 | ||||
|   hashlist = grub_file_open (hashfilename); | ||||
|   if (!hashlist) | ||||
|     return grub_errno; | ||||
|    | ||||
|   while (grub_free (buf), (buf = grub_file_getline (hashlist))) | ||||
|     { | ||||
|       const char *p = buf; | ||||
|       for (i = 0; i < hash->mdlen; i++) | ||||
| 	{ | ||||
| 	  int high, low; | ||||
| 	  high = hextoval (*p++); | ||||
| 	  low = hextoval (*p++); | ||||
| 	  if (high < 0 || low < 0) | ||||
| 	    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); | ||||
| 	  expected[i] = (high << 4) | low; | ||||
| 	} | ||||
|       if (*p++ != ' ' || *p++ != ' ') | ||||
| 	return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); | ||||
|       if (prefix) | ||||
| 	{ | ||||
| 	  char *filename; | ||||
| 	   | ||||
| 	  filename = grub_xasprintf ("%s/%s", prefix, p); | ||||
| 	  if (!filename) | ||||
| 	    return grub_errno; | ||||
| 	  file = grub_file_open (filename); | ||||
| 	  grub_free (filename); | ||||
| 	} | ||||
|       else | ||||
| 	file = grub_file_open (p); | ||||
|       if (!file) | ||||
| 	{ | ||||
| 	  grub_file_close (hashlist); | ||||
| 	  grub_free (buf); | ||||
| 	  return grub_errno; | ||||
| 	} | ||||
|       err = hash_file (file, hash, actual); | ||||
|       grub_file_close (file); | ||||
|       if (err) | ||||
| 	{ | ||||
| 	  grub_printf ("%s: READ ERROR\n", p); | ||||
| 	  if (!keep) | ||||
| 	    { | ||||
| 	      grub_file_close (hashlist); | ||||
| 	      grub_free (buf); | ||||
| 	      return err; | ||||
| 	    } | ||||
| 	  grub_print_error (); | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  unread++; | ||||
| 	  continue; | ||||
| 	} | ||||
|       if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0) | ||||
| 	{ | ||||
| 	  grub_printf ("%s: HASH MISMATCH\n", p); | ||||
| 	  if (!keep) | ||||
| 	    { | ||||
| 	      grub_file_close (hashlist); | ||||
| 	      grub_free (buf); | ||||
| 	      return grub_error (GRUB_ERR_TEST_FAILURE, | ||||
| 				 "hash of '%s' mismatches", p); | ||||
| 	    } | ||||
| 	  mismatch++; | ||||
| 	  continue;	   | ||||
| 	} | ||||
|       grub_printf ("%s: OK\n", p); | ||||
|     } | ||||
|   if (mismatch || unread) | ||||
|     return grub_error (GRUB_ERR_TEST_FAILURE, | ||||
| 		       "%d files couldn't be read and hash " | ||||
| 		       "of %d files mismatches", unread, mismatch); | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_hashsum (struct grub_extcmd *cmd, | ||||
| 		  int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   const char *hashname = NULL; | ||||
|   const char *prefix = NULL; | ||||
|   const gcry_md_spec_t *hash; | ||||
|   unsigned i; | ||||
|   int keep = state[3].set; | ||||
|   unsigned unread = 0; | ||||
| 
 | ||||
|   for (i = 0; i < ARRAY_SIZE (aliases); i++) | ||||
|     if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0) | ||||
|       hashname = aliases[i].hashname; | ||||
|   if (state[0].set) | ||||
|     hashname = state[0].arg; | ||||
| 
 | ||||
|   if (!hashname) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified"); | ||||
| 
 | ||||
|   hash = grub_crypto_lookup_md_by_name (hashname); | ||||
|   if (!hash) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash"); | ||||
| 
 | ||||
|   if (state[2].set) | ||||
|     prefix = state[2].arg; | ||||
| 
 | ||||
|   if (state[1].set) | ||||
|     { | ||||
|       if (argc != 0) | ||||
| 	return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 			   "--check is incompatible with file list"); | ||||
|       return check_list (hash, state[1].arg, prefix, keep); | ||||
|     } | ||||
| 
 | ||||
|   for (i = 0; i < (unsigned) argc; i++) | ||||
|     { | ||||
|       grub_uint8_t result[hash->mdlen]; | ||||
|       grub_file_t file; | ||||
|       grub_err_t err; | ||||
|       unsigned j; | ||||
|       file = grub_file_open (args[i]); | ||||
|       if (!file) | ||||
| 	{ | ||||
| 	  if (!keep) | ||||
| 	    return grub_errno; | ||||
| 	  grub_print_error (); | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  unread++; | ||||
| 	  continue; | ||||
| 	} | ||||
|       err = hash_file (file, hash, result); | ||||
|       grub_file_close (file); | ||||
|       if (err) | ||||
| 	{ | ||||
| 	  if (!keep) | ||||
| 	    return err; | ||||
| 	  grub_print_error (); | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  unread++; | ||||
| 	  continue; | ||||
| 	} | ||||
|       for (j = 0; j < hash->mdlen; j++) | ||||
| 	grub_printf ("%02x", result[j]); | ||||
|       grub_printf ("  %s\n", args[i]); | ||||
|     } | ||||
| 
 | ||||
|   if (unread) | ||||
|     return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.", | ||||
| 		       unread); | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512; | ||||
| 
 | ||||
| GRUB_MOD_INIT(hashsum) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      "hashsum -h HASH [-c FILE [-p PREFIX]] " | ||||
| 			      "[FILE1 [FILE2 ...]]", | ||||
| 			      "Compute or check hash checksum.", | ||||
| 			      options); | ||||
|   cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, | ||||
| 				  GRUB_COMMAND_FLAG_BOTH, | ||||
| 				  N_("[-c FILE [-p PREFIX]] " | ||||
| 				     "[FILE1 [FILE2 ...]]"), | ||||
| 				  N_("Compute or check hash checksum."), | ||||
| 				  options); | ||||
|   cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, | ||||
| 				     GRUB_COMMAND_FLAG_BOTH, | ||||
| 				     N_("[-c FILE [-p PREFIX]] " | ||||
| 					"[FILE1 [FILE2 ...]]"), | ||||
| 				     "Compute or check hash checksum.", | ||||
| 				     options); | ||||
|   cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, | ||||
| 				     GRUB_COMMAND_FLAG_BOTH, | ||||
| 				     N_("[-c FILE [-p PREFIX]] " | ||||
| 					"[FILE1 [FILE2 ...]]"), | ||||
| 				     N_("Compute or check hash checksum."), | ||||
| 				     options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(hashsum) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
|   grub_unregister_extcmd (cmd_md5); | ||||
|   grub_unregister_extcmd (cmd_sha256); | ||||
|   grub_unregister_extcmd (cmd_sha512); | ||||
| } | ||||
							
								
								
									
										421
									
								
								grub-core/commands/hdparm.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								grub-core/commands/hdparm.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,421 @@ | |||
| /* hdparm.c - command to get/set ATA disk parameters.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/ata.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/lib/hexdump.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = { | ||||
|   {"apm",             'B', 0, N_("Set Advanced Power Management\n" | ||||
| 			      "(1=low, ..., 254=high, 255=off)."), | ||||
| 			      0, ARG_TYPE_INT}, | ||||
|   {"power",           'C', 0, N_("Check power mode."), 0, ARG_TYPE_NONE}, | ||||
|   {"security-freeze", 'F', 0, N_("Freeze ATA security settings until reset."), | ||||
| 			      0, ARG_TYPE_NONE}, | ||||
|   {"health",          'H', 0, N_("Check SMART health status."), 0, ARG_TYPE_NONE}, | ||||
|   {"aam",             'M', 0, N_("Set Automatic Acoustic Management\n" | ||||
| 			      "(0=off, 128=quiet, ..., 254=fast)."), | ||||
| 			      0, ARG_TYPE_INT}, | ||||
|   {"standby-timeout", 'S', 0, N_("Set standby timeout\n" | ||||
| 			      "(0=off, 1=5s, 2=10s, ..., 240=20m, 241=30m, ...)."), | ||||
| 			      0, ARG_TYPE_INT}, | ||||
|   {"standby",         'y', 0, N_("Set drive to standby mode."), 0, ARG_TYPE_NONE}, | ||||
|   {"sleep",           'Y', 0, N_("Set drive to sleep mode."), 0, ARG_TYPE_NONE}, | ||||
|   {"identify",        'i', 0, N_("Print drive identity and settings."), | ||||
| 			      0, ARG_TYPE_NONE}, | ||||
|   {"dumpid",          'I', 0, N_("Dump contents of ATA IDENTIFY sector."), | ||||
| 			       0, ARG_TYPE_NONE}, | ||||
|   {"smart",            -1, 0, N_("Disable/enable SMART (0/1)."), 0, ARG_TYPE_INT}, | ||||
|   {"quiet",           'q', 0, N_("Do not print messages."), 0, ARG_TYPE_NONE}, | ||||
|   {0, 0, 0, 0, 0, 0} | ||||
| }; | ||||
| 
 | ||||
| enum grub_ata_smart_commands | ||||
|   { | ||||
|     GRUB_ATA_FEAT_SMART_ENABLE  = 0xd8, | ||||
|     GRUB_ATA_FEAT_SMART_DISABLE = 0xd9, | ||||
|     GRUB_ATA_FEAT_SMART_STATUS  = 0xda, | ||||
|   }; | ||||
| 
 | ||||
| static int quiet = 0; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_hdparm_do_ata_cmd (grub_disk_t disk, 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.buffer = buffer; | ||||
|   apt.size = size; | ||||
| 
 | ||||
|   if (grub_disk_ata_pass_through (disk, &apt)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_hdparm_do_check_powermode_cmd (grub_disk_t disk) | ||||
| { | ||||
|   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; | ||||
| 
 | ||||
|   if (grub_disk_ata_pass_through (disk, &apt)) | ||||
|     return -1; | ||||
| 
 | ||||
|   return apt.taskfile[GRUB_ATA_REG_SECTORS]; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_hdparm_do_smart_cmd (grub_disk_t disk, 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; | ||||
| 
 | ||||
|   if (grub_disk_ata_pass_through (disk, &apt)) | ||||
|     return -1; | ||||
| 
 | ||||
|   if (features == GRUB_ATA_FEAT_SMART_STATUS) | ||||
|     { | ||||
|       if (   apt.taskfile[GRUB_ATA_REG_LBAMID]  == 0x4f | ||||
|           && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0xc2) | ||||
| 	return 0; /* Good SMART status.  */ | ||||
|       else if (   apt.taskfile[GRUB_ATA_REG_LBAMID]  == 0xf4 | ||||
| 	       && apt.taskfile[GRUB_ATA_REG_LBAHIGH] == 0x2c) | ||||
| 	return 1; /* Bad SMART status.  */ | ||||
|       else | ||||
| 	return -1; | ||||
|     } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_hdparm_simple_cmd (const char * msg, | ||||
| 			grub_disk_t disk, 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); | ||||
| 
 | ||||
|   if (! quiet && msg) | ||||
|     grub_printf ("%s\n", ! err ? "" : ": not supported"); | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_hdparm_set_val_cmd (const char * msg, int val, | ||||
| 			 grub_disk_t disk, grub_uint8_t cmd, | ||||
| 			 grub_uint8_t features, grub_uint8_t sectors) | ||||
| { | ||||
|   if (! quiet && msg && *msg) | ||||
|     { | ||||
|       if (val >= 0) | ||||
| 	grub_printf ("Set %s to %d", msg, val); | ||||
|       else | ||||
| 	grub_printf ("Disable %s", msg); | ||||
|     } | ||||
| 
 | ||||
|   grub_err_t err = grub_hdparm_do_ata_cmd (disk, cmd, features, sectors, | ||||
| 					   NULL, 0); | ||||
| 
 | ||||
|   if (! quiet && msg) | ||||
|     grub_printf ("%s\n", ! err ? "" : ": not supported"); | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static const char * | ||||
| le16_to_char (char *dest, const grub_uint16_t * src16, unsigned bytes) | ||||
| { | ||||
|   grub_uint16_t * dest16 = (grub_uint16_t *) dest; | ||||
|   unsigned i; | ||||
|   for (i = 0; i < bytes / 2; i++) | ||||
|     dest16[i] = grub_be_to_cpu16 (src16[i]); | ||||
|   return dest; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_hdparm_print_identify (const char * idbuf) | ||||
| { | ||||
|   const grub_uint16_t * idw = (const grub_uint16_t *) idbuf; | ||||
| 
 | ||||
|   /* Print identity strings.  */ | ||||
|   char tmp[40]; | ||||
|   grub_printf ("Model:    \"%.40s\"\n", le16_to_char (tmp, &idw[27], 40)); | ||||
|   grub_printf ("Firmware: \"%.8s\"\n",  le16_to_char (tmp, &idw[23], 8)); | ||||
|   grub_printf ("Serial:   \"%.20s\"\n", le16_to_char (tmp, &idw[10], 20)); | ||||
| 
 | ||||
|   /* Print AAM, APM and SMART settings.  */ | ||||
|   grub_uint16_t features1 = grub_le_to_cpu16 (idw[82]); | ||||
|   grub_uint16_t features2 = grub_le_to_cpu16 (idw[83]); | ||||
|   grub_uint16_t enabled1  = grub_le_to_cpu16 (idw[85]); | ||||
|   grub_uint16_t enabled2  = grub_le_to_cpu16 (idw[86]); | ||||
| 
 | ||||
|   grub_printf ("Automatic Acoustic Management: "); | ||||
|   if (features2 & 0x0200) | ||||
|     { | ||||
|       if (enabled2 & 0x0200) | ||||
| 	{ | ||||
| 	  grub_uint16_t aam = grub_le_to_cpu16 (idw[94]); | ||||
| 	  grub_printf ("%u (128=quiet, ..., 254=fast, recommended=%u)\n", | ||||
| 		       aam & 0xff, (aam >> 8) & 0xff); | ||||
| 	} | ||||
|       else | ||||
| 	grub_printf ("disabled\n"); | ||||
|     } | ||||
|   else | ||||
|     grub_printf ("not supported\n"); | ||||
| 
 | ||||
|   grub_printf ("Advanced Power Management: "); | ||||
|   if (features2 & 0x0008) | ||||
|     { | ||||
|       if (enabled2 & 0x0008) | ||||
| 	grub_printf ("%u (1=low, ..., 254=high)\n", | ||||
| 		     grub_le_to_cpu16 (idw[91]) & 0xff); | ||||
|       else | ||||
| 	grub_printf ("disabled\n"); | ||||
|     } | ||||
|   else | ||||
|     grub_printf ("not supported\n"); | ||||
| 
 | ||||
|   grub_printf ("SMART Feature Set: "); | ||||
|   if (features1 & 0x0001) | ||||
|     grub_printf ("%sabled\n", (enabled1 & 0x0001 ? "en" : "dis")); | ||||
|   else | ||||
|     grub_printf ("not supported\n"); | ||||
| 
 | ||||
|   /* Print security settings.  */ | ||||
|   grub_uint16_t security = grub_le_to_cpu16 (idw[128]); | ||||
| 
 | ||||
|   grub_printf ("ATA Security: "); | ||||
|   if (security & 0x0001) | ||||
|     grub_printf ("%s, %s, %s, %s\n", | ||||
| 		 (security & 0x0002 ? "ENABLED" : "disabled"), | ||||
| 		 (security & 0x0004 ? "**LOCKED**"  : "not locked"), | ||||
| 		 (security & 0x0008 ? "frozen" : "NOT FROZEN"), | ||||
| 		 (security & 0x0010 ? "COUNT EXPIRED" : "count not expired")); | ||||
|   else | ||||
|     grub_printf ("not supported\n"); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_hdparm_print_standby_tout (int timeout) | ||||
| { | ||||
|   if (timeout == 0) | ||||
|     grub_printf ("off"); | ||||
|   else if (timeout <= 252 || timeout == 255) | ||||
|     { | ||||
|       int h = 0, m = 0 , s = 0; | ||||
|       if (timeout == 255) | ||||
| 	{ | ||||
| 	  m = 21; | ||||
| 	  s = 15; | ||||
| 	} | ||||
|       else if (timeout == 252) | ||||
| 	m = 21; | ||||
|       else if (timeout <= 240) | ||||
| 	{ | ||||
| 	  s = timeout * 5; | ||||
| 	  m = s / 60; | ||||
| 	  s %= 60; | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  m = (timeout - 240) * 30; | ||||
| 	  h  = m / 60; | ||||
| 	  m %= 60; | ||||
| 	} | ||||
|       grub_printf ("%02d:%02d:%02d", h, m, s); | ||||
|     } | ||||
|   else | ||||
|     grub_printf ("invalid or vendor-specific"); | ||||
| } | ||||
| 
 | ||||
| static int get_int_arg (const struct grub_arg_list *state) | ||||
| { | ||||
|   return (state->set ? (int)grub_strtoul (state->arg, 0, 0) : -1); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_hdparm (grub_extcmd_t cmd, int argc, char **args) // state????
 | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
| 
 | ||||
|   /* Check command line.  */ | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing device name argument"); | ||||
| 
 | ||||
|   grub_size_t len = grub_strlen (args[0]); | ||||
|   if (! (args[0][0] == '(' && args[0][len - 1] == ')')) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "argument is not a device name"); | ||||
|   args[0][len - 1] = 0; | ||||
| 
 | ||||
|   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; | ||||
|   int sec_freeze   = state[i++].set; | ||||
|   int health       = state[i++].set; | ||||
|   int aam          = get_int_arg (&state[i++]); | ||||
|   int standby_tout = get_int_arg (&state[i++]); | ||||
|   int standby_now  = state[i++].set; | ||||
|   int sleep_now    = state[i++].set; | ||||
|   int ident        = state[i++].set; | ||||
|   int dumpid       = state[i++].set; | ||||
|   int enable_smart = get_int_arg (&state[i++]); | ||||
|   quiet            = state[i++].set; | ||||
| 
 | ||||
|   /* Open disk.  */ | ||||
|   grub_disk_t disk = grub_disk_open (&args[0][1]); | ||||
|   if (! disk) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (disk->partition) | ||||
|     { | ||||
|       grub_disk_close (disk); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "partition not allowed"); | ||||
|     } | ||||
| 
 | ||||
|   /* 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); | ||||
| 
 | ||||
|   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)); | ||||
| 
 | ||||
|   if (standby_tout >= 0) | ||||
|     { | ||||
|       if (! quiet) | ||||
| 	{ | ||||
| 	  grub_printf ("Set standby timeout to %d (", standby_tout); | ||||
| 	  grub_hdparm_print_standby_tout (standby_tout); | ||||
| 	  grub_printf (")"); | ||||
| 	} | ||||
|       /* The IDLE cmd sets disk to idle mode and configures standby timer.  */ | ||||
|       grub_hdparm_set_val_cmd ("", -1, disk, 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 ? | ||||
| 	          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_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, | ||||
|           0, 0, buf, sizeof (buf))) | ||||
| 	grub_printf ("Cannot read ATA IDENTIFY data\n"); | ||||
|       else | ||||
| 	{ | ||||
| 	  if (ident) | ||||
| 	    grub_hdparm_print_identify (buf); | ||||
| 	  if (dumpid) | ||||
| 	    hexdump (0, buf, sizeof (buf)); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   /* Check power mode.  */ | ||||
|   if (power) | ||||
|     { | ||||
|       grub_printf ("Disk power mode is: "); | ||||
|       int mode = grub_hdparm_do_check_powermode_cmd (disk); | ||||
|       if (mode < 0) | ||||
|         grub_printf ("unknown\n"); | ||||
|       else | ||||
| 	grub_printf ("%s (0x%02x)\n", | ||||
| 		     (mode == 0xff ? "active/idle" : | ||||
| 		      mode == 0x80 ? "idle" : | ||||
| 		      mode == 0x00 ? "standby" : "unknown"), mode); | ||||
|     } | ||||
| 
 | ||||
|   /* Check health.  */ | ||||
|   int status = 0; | ||||
|   if (health) | ||||
|     { | ||||
|       if (! quiet) | ||||
| 	grub_printf ("SMART status is: "); | ||||
|       int err = grub_hdparm_do_smart_cmd (disk, GRUB_ATA_FEAT_SMART_STATUS); | ||||
|       if (! quiet) | ||||
| 	grub_printf ("%s\n", (err  < 0 ? "unknown" : | ||||
| 	                      err == 0 ? "OK" : "*BAD*")); | ||||
|       status = (err > 0); | ||||
|     } | ||||
| 
 | ||||
|   /* Change power mode.  */ | ||||
|   if (standby_now) | ||||
|     grub_hdparm_simple_cmd ("Set disk to standby mode", disk, | ||||
| 			    GRUB_ATA_CMD_STANDBY_IMMEDIATE); | ||||
| 
 | ||||
|   if (sleep_now) | ||||
|     grub_hdparm_simple_cmd ("Set disk to sleep mode", disk, | ||||
| 			    GRUB_ATA_CMD_SLEEP); | ||||
| 
 | ||||
|   grub_disk_close (disk); | ||||
| 
 | ||||
|   grub_errno = GRUB_ERR_NONE; | ||||
|   return status; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(hdparm) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[OPTIONS] DISK"), | ||||
| 			      N_("Get/set ATA disk parameters."), options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(hdparm) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										142
									
								
								grub-core/commands/help.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								grub-core/commands/help.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | |||
| /* help.c - command to show a help text.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/charset.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, | ||||
| 	       char **args) | ||||
| { | ||||
|   int cnt = 0; | ||||
|   char *currarg; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     { | ||||
|       grub_command_t cmd; | ||||
|       FOR_COMMANDS(cmd) | ||||
|       { | ||||
| 	if ((cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) && | ||||
| 	    (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)) | ||||
| 	  { | ||||
| 	    struct grub_term_output *term; | ||||
| 	    const char *summary_translated = _(cmd->summary); | ||||
| 	    char *command_help; | ||||
| 	    grub_uint32_t *unicode_command_help; | ||||
| 	    grub_uint32_t *unicode_last_position; | ||||
| 	  			       | ||||
| 	    command_help = grub_xasprintf ("%s %s", cmd->name, summary_translated); | ||||
| 	    if (!command_help) | ||||
| 	      break; | ||||
| 
 | ||||
| 	    grub_utf8_to_ucs4_alloc (command_help, &unicode_command_help, | ||||
| 				     &unicode_last_position); | ||||
| 
 | ||||
| 	    FOR_ACTIVE_TERM_OUTPUTS(term) | ||||
| 	    { | ||||
| 	      unsigned stringwidth; | ||||
| 	      grub_uint32_t *unicode_last_screen_position; | ||||
| 
 | ||||
| 	      unicode_last_screen_position = unicode_command_help; | ||||
| 
 | ||||
| 	      stringwidth = 0; | ||||
| 
 | ||||
| 	      while (unicode_last_screen_position < unicode_last_position &&  | ||||
| 		     stringwidth < ((grub_term_width (term) / 2) - 2)) | ||||
| 		{ | ||||
| 		  struct grub_unicode_glyph glyph; | ||||
| 		  unicode_last_screen_position  | ||||
| 		    += grub_unicode_aglomerate_comb (unicode_last_screen_position, | ||||
| 						     unicode_last_position | ||||
| 						     - unicode_last_screen_position, | ||||
| 						     &glyph); | ||||
| 
 | ||||
| 		  stringwidth | ||||
| 		    += grub_term_getcharwidth (term, &glyph); | ||||
| 		} | ||||
| 
 | ||||
| 	      grub_print_ucs4 (unicode_command_help, | ||||
| 			       unicode_last_screen_position, 0, 0, term); | ||||
| 	      if (!(cnt % 2)) | ||||
| 		grub_print_spaces (term, grub_term_width (term) / 2 | ||||
| 				   - stringwidth); | ||||
| 	    } | ||||
| 
 | ||||
| 	    if (cnt % 2) | ||||
| 	      grub_printf ("\n"); | ||||
| 	    cnt++; | ||||
| 	   | ||||
| 	    grub_free (command_help); | ||||
| 	    grub_free (unicode_command_help); | ||||
| 	  } | ||||
|       } | ||||
|       if (!(cnt % 2)) | ||||
| 	grub_printf ("\n"); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       int i; | ||||
|       grub_command_t cmd; | ||||
| 
 | ||||
|       for (i = 0; i < argc; i++) | ||||
| 	{ | ||||
| 	  currarg = args[i]; | ||||
| 	  FOR_COMMANDS(cmd) | ||||
| 	  { | ||||
| 	    if (cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) | ||||
| 	      { | ||||
| 		if (! grub_strncmp (cmd->name, currarg, grub_strlen (currarg))) | ||||
| 		  { | ||||
| 		    if (cnt++ > 0) | ||||
| 		      grub_printf ("\n\n"); | ||||
| 
 | ||||
| 		    if (cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) | ||||
| 		      grub_arg_show_help ((grub_extcmd_t) cmd->data); | ||||
| 		    else | ||||
| 		      grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary), | ||||
| 				   _(cmd->description)); | ||||
| 		  } | ||||
| 	      } | ||||
| 	  } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(help) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("help", grub_cmd_help, | ||||
| 			      GRUB_COMMAND_FLAG_CMDLINE, | ||||
| 			      N_("[PATTERN ...]"), | ||||
| 			      N_("Show a help message."), 0); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(help) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										133
									
								
								grub-core/commands/hexdump.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								grub-core/commands/hexdump.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,133 @@ | |||
| /* hexdump.c - command to dump the contents of a file or memory */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/gzio.h> | ||||
| #include <grub/lib/hexdump.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = { | ||||
|   {"skip", 's', 0, N_("Skip offset bytes from the beginning of file."), 0, | ||||
|    ARG_TYPE_INT}, | ||||
|   {"length", 'n', 0, N_("Read only LENGTH bytes."), 0, ARG_TYPE_INT}, | ||||
|   {0, 0, 0, 0, 0, 0} | ||||
| }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   char buf[GRUB_DISK_SECTOR_SIZE * 4]; | ||||
|   grub_ssize_t size, length; | ||||
|   grub_disk_addr_t skip; | ||||
|   int namelen; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); | ||||
| 
 | ||||
|   namelen = grub_strlen (args[0]); | ||||
|   skip = (state[0].set) ? grub_strtoull (state[0].arg, 0, 0) : 0; | ||||
|   length = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 256; | ||||
| 
 | ||||
|   if (!grub_strcmp (args[0], "(mem)")) | ||||
|     hexdump (skip, (char *) (grub_addr_t) skip, length); | ||||
|   else if ((args[0][0] == '(') && (args[0][namelen - 1] == ')')) | ||||
|     { | ||||
|       grub_disk_t disk; | ||||
|       grub_disk_addr_t sector; | ||||
|       grub_size_t ofs; | ||||
| 
 | ||||
|       args[0][namelen - 1] = 0; | ||||
|       disk = grub_disk_open (&args[0][1]); | ||||
|       if (! disk) | ||||
|         return 0; | ||||
| 
 | ||||
|       sector = (skip >> (GRUB_DISK_SECTOR_BITS + 2)) * 4; | ||||
|       ofs = skip & (GRUB_DISK_SECTOR_SIZE * 4 - 1); | ||||
|       while (length) | ||||
|         { | ||||
|           grub_size_t len; | ||||
| 
 | ||||
|           len = length; | ||||
|           if (len > sizeof (buf)) | ||||
|             len = sizeof (buf); | ||||
| 
 | ||||
|           if (grub_disk_read (disk, sector, ofs, len, buf)) | ||||
|             break; | ||||
| 
 | ||||
|           hexdump (skip, buf, len); | ||||
| 
 | ||||
|           ofs = 0; | ||||
|           skip += len; | ||||
|           length -= len; | ||||
|           sector += 4; | ||||
|         } | ||||
| 
 | ||||
|       grub_disk_close (disk); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       grub_file_t file; | ||||
| 
 | ||||
|       file = grub_gzfile_open (args[0], 1); | ||||
|       if (! file) | ||||
| 	return 0; | ||||
| 
 | ||||
|       file->offset = skip; | ||||
| 
 | ||||
|       while ((size = grub_file_read (file, buf, sizeof (buf))) > 0) | ||||
| 	{ | ||||
| 	  unsigned long len; | ||||
| 
 | ||||
| 	  len = ((length) && (size > length)) ? length : size; | ||||
| 	  hexdump (skip, buf, len); | ||||
| 	  skip += len; | ||||
| 	  if (length) | ||||
| 	    { | ||||
| 	      length -= len; | ||||
| 	      if (!length) | ||||
| 		break; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       grub_file_close (file); | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT (hexdump) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("hexdump", grub_cmd_hexdump, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[OPTIONS] FILE_OR_DEVICE"), | ||||
| 			      N_("Dump the contents of a file or memory."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (hexdump) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										59
									
								
								grub-core/commands/i386/cmostest.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								grub-core/commands/i386/cmostest.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/cmos.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		   int argc, char *argv[]) | ||||
| { | ||||
|   int byte, bit; | ||||
|   char *rest; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Address required."); | ||||
| 
 | ||||
|   byte = grub_strtoul (argv[0], &rest, 0); | ||||
|   if (*rest != ':') | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Address required."); | ||||
| 
 | ||||
|   bit = grub_strtoul (rest + 1, 0, 0); | ||||
| 
 | ||||
|   if (grub_cmos_read (byte) & (1 << bit)) | ||||
|     return GRUB_ERR_NONE; | ||||
| 
 | ||||
|   return grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
|  | ||||
| GRUB_MOD_INIT(cmostest) | ||||
| { | ||||
|   cmd = grub_register_command ("cmostest", grub_cmd_cmostest, | ||||
| 			       "cmostest BYTE:BIT", | ||||
| 			       "Test bit at BYTE:BIT in CMOS."); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(cmostest) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										98
									
								
								grub-core/commands/i386/cpuid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								grub-core/commands/i386/cpuid.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | |||
| /* cpuid.c - test for CPU features */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006, 2007, 2009  Free Software Foundation, Inc. | ||||
|  *  Based on gcc/gcc/config/i386/driver-i386.c | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU 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/mm.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i386/cpuid.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| #define cpuid(num,a,b,c,d) \ | ||||
|   asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \ | ||||
| 		: "=a" (a), "=r" (b), "=c" (c), "=d" (d)  \ | ||||
| 		: "0" (num)) | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"long-mode", 'l', 0, N_("Check for long mode flag (default)."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| #define bit_LM (1 << 29) | ||||
| 
 | ||||
| unsigned char grub_cpuid_has_longmode = 0; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_cpuid (grub_extcmd_t cmd __attribute__ ((unused)), | ||||
| 		int argc __attribute__ ((unused)), | ||||
| 		char **args __attribute__ ((unused))) | ||||
| { | ||||
|   return grub_cpuid_has_longmode ? GRUB_ERR_NONE | ||||
|     : grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(cpuid) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
|   /* grub-emu */ | ||||
|   grub_cpuid_has_longmode = 1; | ||||
| #else | ||||
|   unsigned int eax, ebx, ecx, edx; | ||||
|   unsigned int max_level; | ||||
|   unsigned int ext_level; | ||||
| 
 | ||||
|   /* See if we can use cpuid.  */ | ||||
|   asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;" | ||||
| 		"pushl %0; popfl; pushfl; popl %0; popfl" | ||||
| 		: "=&r" (eax), "=&r" (ebx) | ||||
| 		: "i" (0x00200000)); | ||||
|   if (((eax ^ ebx) & 0x00200000) == 0) | ||||
|     goto done; | ||||
| 
 | ||||
|   /* Check the highest input value for eax.  */ | ||||
|   cpuid (0, eax, ebx, ecx, edx); | ||||
|   /* We only look at the first four characters.  */ | ||||
|   max_level = eax; | ||||
|   if (max_level == 0) | ||||
|     goto done; | ||||
| 
 | ||||
|   cpuid (0x80000000, eax, ebx, ecx, edx); | ||||
|   ext_level = eax; | ||||
|   if (ext_level < 0x80000000) | ||||
|     goto done; | ||||
| 
 | ||||
|   cpuid (0x80000001, eax, ebx, ecx, edx); | ||||
|   grub_cpuid_has_longmode = !!(edx & bit_LM); | ||||
| done: | ||||
| #endif | ||||
| 
 | ||||
|   cmd = grub_register_extcmd ("cpuid", grub_cmd_cpuid, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      "[-l]", N_("Check for CPU features."), options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(cpuid) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										81
									
								
								grub-core/commands/i386/pc/acpi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								grub-core/commands/i386/pc/acpi.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| /* acpi.c - get acpi tables. */ | ||||
| /*
 | ||||
|  *  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/acpi.h> | ||||
| #include <grub/misc.h> | ||||
| 
 | ||||
| struct grub_acpi_rsdp_v10 * | ||||
| grub_machine_acpi_get_rsdpv1 (void) | ||||
| { | ||||
|   int ebda_len; | ||||
|   grub_uint8_t *ebda, *ptr; | ||||
| 
 | ||||
|   grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n"); | ||||
|   ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4); | ||||
|   ebda_len = * (grub_uint16_t *) ebda; | ||||
|   if (! ebda_len) | ||||
|     return 0; | ||||
|   for (ptr = ebda; ptr < ebda + 0x400; ptr += 16) | ||||
|     if (grub_memcmp (ptr, "RSD PTR ", 8) == 0 | ||||
| 	&& grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0 | ||||
| 	&& ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0) | ||||
|       return (struct grub_acpi_rsdp_v10 *) ptr; | ||||
| 
 | ||||
|   grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n"); | ||||
|   for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000; | ||||
|        ptr += 16) | ||||
|     if (grub_memcmp (ptr, "RSD PTR ", 8) == 0 | ||||
| 	&& grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0 | ||||
| 	&& ((struct grub_acpi_rsdp_v10 *) ptr)->revision == 0) | ||||
|       return (struct grub_acpi_rsdp_v10 *) ptr; | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| struct grub_acpi_rsdp_v20 * | ||||
| grub_machine_acpi_get_rsdpv2 (void) | ||||
| { | ||||
|   int ebda_len; | ||||
|   grub_uint8_t *ebda, *ptr; | ||||
| 
 | ||||
|   grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n"); | ||||
|   ebda = (grub_uint8_t *) ((* ((grub_uint16_t *) 0x40e)) << 4); | ||||
|   ebda_len = * (grub_uint16_t *) ebda; | ||||
|   if (! ebda_len) | ||||
|     return 0; | ||||
|   for (ptr = ebda; ptr < ebda + 0x400; ptr += 16) | ||||
|     if (grub_memcmp (ptr, "RSD PTR ", 8) == 0 | ||||
| 	&& grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0 | ||||
| 	&& ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0 | ||||
| 	&& ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024 | ||||
| 	&& grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length) | ||||
| 	== 0) | ||||
|       return (struct grub_acpi_rsdp_v20 *) ptr; | ||||
| 
 | ||||
|   grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n"); | ||||
|   for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000; | ||||
|        ptr += 16) | ||||
|     if (grub_memcmp (ptr, "RSD PTR ", 8) == 0 | ||||
| 	&& grub_byte_checksum (ptr, sizeof (struct grub_acpi_rsdp_v10)) == 0 | ||||
| 	&& ((struct grub_acpi_rsdp_v10 *) ptr)->revision != 0 | ||||
| 	&& ((struct grub_acpi_rsdp_v20 *) ptr)->length < 1024 | ||||
| 	&& grub_byte_checksum (ptr, ((struct grub_acpi_rsdp_v20 *) ptr)->length) | ||||
| 	== 0) | ||||
|       return (struct grub_acpi_rsdp_v20 *) ptr; | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										421
									
								
								grub-core/commands/i386/pc/drivemap.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										421
									
								
								grub-core/commands/i386/pc/drivemap.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,421 @@ | |||
| /* drivemap.c - command to manage the BIOS drive mappings.  */ | ||||
| /*
 | ||||
|  *  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/extcmd.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/loader.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/machine/memory.h> | ||||
| #include <grub/machine/biosnum.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| 
 | ||||
| /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13.  */ | ||||
| static grub_uint32_t *const int13slot = UINT_TO_PTR (4 * 0x13); | ||||
| 
 | ||||
| /* Remember to update enum opt_idxs accordingly.  */ | ||||
| static const struct grub_arg_option options[] = { | ||||
|   {"list", 'l', 0, N_("Show the current mappings."), 0, 0}, | ||||
|   {"reset", 'r', 0, N_("Reset all mappings to the default values."), 0, 0}, | ||||
|   {"swap", 's', 0, N_("Perform both direct and reverse mappings."), 0, 0}, | ||||
|   {0, 0, 0, 0, 0, 0} | ||||
| }; | ||||
| 
 | ||||
| /* Remember to update options[] accordingly.  */ | ||||
| enum opt_idxs | ||||
| { | ||||
|   OPTIDX_LIST = 0, | ||||
|   OPTIDX_RESET, | ||||
|   OPTIDX_SWAP, | ||||
| }; | ||||
| 
 | ||||
| /* Realmode far ptr (2 * 16b) to the previous INT13h handler.  */ | ||||
| extern grub_uint32_t grub_drivemap_oldhandler; | ||||
| 
 | ||||
| /* The type "void" is used for imported assembly labels, takes no storage and
 | ||||
|    serves just to take the address with &label.  */ | ||||
| 
 | ||||
| /* The assembly function to replace the old INT13h handler. It does not follow
 | ||||
|    any C callspecs and returns with IRET.  */ | ||||
| extern const void grub_drivemap_handler; | ||||
| 
 | ||||
| /* Start of the drive mappings area (space reserved at runtime).  */ | ||||
| extern const void grub_drivemap_mapstart; | ||||
| 
 | ||||
| typedef struct drivemap_node | ||||
| { | ||||
|   struct drivemap_node *next; | ||||
|   grub_uint8_t newdrive; | ||||
|   grub_uint8_t redirto; | ||||
| } drivemap_node_t; | ||||
| 
 | ||||
| typedef struct __attribute__ ((packed)) int13map_node | ||||
| { | ||||
|   grub_uint8_t disknum; | ||||
|   grub_uint8_t mapto; | ||||
| } int13map_node_t; | ||||
| 
 | ||||
| #define INT13H_OFFSET(x) \ | ||||
| 	(((grub_uint8_t *)(x)) - ((grub_uint8_t *)&grub_drivemap_handler)) | ||||
| 
 | ||||
| static drivemap_node_t *map_head; | ||||
| static void *drivemap_hook; | ||||
| static int drivemap_mmap; | ||||
| 
 | ||||
| /* Puts the specified mapping into the table, replacing an existing mapping
 | ||||
|    for newdrive or adding a new one if required.  */ | ||||
| static grub_err_t | ||||
| drivemap_set (grub_uint8_t newdrive, grub_uint8_t redirto) | ||||
| { | ||||
|   drivemap_node_t *mapping = 0; | ||||
|   drivemap_node_t *search = map_head; | ||||
|   while (search) | ||||
|     { | ||||
|       if (search->newdrive == newdrive) | ||||
| 	{ | ||||
| 	  mapping = search; | ||||
| 	  break; | ||||
| 	} | ||||
|       search = search->next; | ||||
|     } | ||||
| 
 | ||||
|   /* Check for pre-existing mappings to modify before creating a new one.  */ | ||||
|   if (mapping) | ||||
|     mapping->redirto = redirto; | ||||
|   else | ||||
|     { | ||||
|       mapping = grub_malloc (sizeof (drivemap_node_t)); | ||||
|       if (! mapping) | ||||
| 	return grub_error (GRUB_ERR_OUT_OF_MEMORY, | ||||
| 			   "cannot allocate map entry, not enough memory"); | ||||
|       mapping->newdrive = newdrive; | ||||
|       mapping->redirto = redirto; | ||||
|       mapping->next = map_head; | ||||
|       map_head = mapping; | ||||
|     } | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| /* Removes the mapping for newdrive from the table.  If there is no mapping,
 | ||||
|    then this function behaves like a no-op on the map.  */ | ||||
| static void | ||||
| drivemap_remove (grub_uint8_t newdrive) | ||||
| { | ||||
|   drivemap_node_t *mapping = 0; | ||||
|   drivemap_node_t *search = map_head; | ||||
|   drivemap_node_t *previous = 0; | ||||
| 
 | ||||
|   while (search) | ||||
|     { | ||||
|       if (search->newdrive == newdrive) | ||||
| 	{ | ||||
| 	  mapping = search; | ||||
| 	  break; | ||||
| 	} | ||||
|       previous = search; | ||||
|       search = search->next; | ||||
|     } | ||||
| 
 | ||||
|   if (mapping) | ||||
|     { | ||||
|       if (previous) | ||||
| 	previous->next = mapping->next; | ||||
|       else | ||||
| 	map_head = mapping->next; | ||||
|       grub_free (mapping); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Given a GRUB-like device name and a convenient location, stores the
 | ||||
|    related BIOS disk number.  Accepts devices like \((f|h)dN\), with | ||||
|    0 <= N < 128.  */ | ||||
| static grub_err_t | ||||
| tryparse_diskstring (const char *str, grub_uint8_t *output) | ||||
| { | ||||
|   /* Skip opening paren in order to allow both (hd0) and hd0.  */ | ||||
|   if (*str == '(') | ||||
|     str++; | ||||
|   if ((str[0] == 'f' || str[0] == 'h') && str[1] == 'd') | ||||
|     { | ||||
|       grub_uint8_t bios_num = (str[0] == 'h') ? 0x80 : 0x00; | ||||
|       unsigned long drivenum = grub_strtoul (str + 2, 0, 0); | ||||
|       if (grub_errno == GRUB_ERR_NONE && drivenum < 128) | ||||
| 	{ | ||||
| 	  bios_num |= drivenum; | ||||
| 	  if (output) | ||||
| 	    *output = bios_num; | ||||
| 	  return GRUB_ERR_NONE; | ||||
| 	} | ||||
|     } | ||||
|   return grub_error (GRUB_ERR_BAD_ARGUMENT, "device format \"%s\" " | ||||
| 		     "invalid: must be (f|h)dN, with 0 <= N < 128", str); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| list_mappings (void) | ||||
| { | ||||
|   /* Show: list mappings.  */ | ||||
|   if (! map_head) | ||||
|     { | ||||
|       grub_printf ("No drives have been remapped\n"); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   grub_printf ("OS disk #num ------> GRUB/BIOS device\n"); | ||||
|   drivemap_node_t *curnode = map_head; | ||||
|   while (curnode) | ||||
|     { | ||||
|       grub_printf ("%cD #%-3u (0x%02x)       %cd%d\n", | ||||
| 		   (curnode->newdrive & 0x80) ? 'H' : 'F', | ||||
| 		   curnode->newdrive & 0x7F, curnode->newdrive, | ||||
| 		   (curnode->redirto & 0x80) ? 'h' : 'f', | ||||
| 		   curnode->redirto & 0x7F | ||||
| 		   ); | ||||
|       curnode = curnode->next; | ||||
|     } | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) | ||||
| { | ||||
|   if (cmd->state[OPTIDX_LIST].set) | ||||
|     { | ||||
|       return list_mappings (); | ||||
|     } | ||||
|   else if (cmd->state[OPTIDX_RESET].set) | ||||
|     { | ||||
|       /* Reset: just delete all mappings, freeing their memory.  */ | ||||
|       drivemap_node_t *curnode = map_head; | ||||
|       drivemap_node_t *prevnode = 0; | ||||
|       while (curnode) | ||||
| 	{ | ||||
| 	  prevnode = curnode; | ||||
| 	  curnode = curnode->next; | ||||
| 	  grub_free (prevnode); | ||||
| 	} | ||||
|       map_head = 0; | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   else if (!cmd->state[OPTIDX_SWAP].set && argc == 0) | ||||
|     { | ||||
|       /* No arguments */ | ||||
|       return list_mappings (); | ||||
|     } | ||||
| 
 | ||||
|   /* Neither flag: put mapping.  */ | ||||
|   grub_uint8_t mapfrom = 0; | ||||
|   grub_uint8_t mapto = 0xFF; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   if (argc != 2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments required"); | ||||
| 
 | ||||
|   err = tryparse_diskstring (args[0], &mapfrom); | ||||
|   if (err != GRUB_ERR_NONE) | ||||
|     return err; | ||||
| 
 | ||||
|   err = tryparse_diskstring (args[1], &mapto); | ||||
|   if (err != GRUB_ERR_NONE) | ||||
|     return err; | ||||
| 
 | ||||
|   if (mapto == mapfrom) | ||||
|     { | ||||
|       /* Reset to default.  */ | ||||
|       grub_dprintf ("drivemap", "Removing mapping for %s (%02x)\n", | ||||
| 		    args[0], mapfrom); | ||||
|       drivemap_remove (mapfrom); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   /* Set the mapping for the disk (overwrites any existing mapping).  */ | ||||
|   grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n", | ||||
| 		cmd->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping", | ||||
| 		args[1], mapto, args[0], mapfrom); | ||||
|   err = drivemap_set (mapto, mapfrom); | ||||
|   /* If -s, perform the reverse mapping too (only if the first was OK).  */ | ||||
|   if (cmd->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE) | ||||
|     err = drivemap_set (mapfrom, mapto); | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| /* Int13h handler installer - reserves conventional memory for the handler,
 | ||||
|    copies it over and sets the IVT entry for int13h. | ||||
|    This code rests on the assumption that GRUB does not activate any kind | ||||
|    of memory mapping apart from identity paging, since it accesses | ||||
|    realmode structures by their absolute addresses, like the IVT at 0; | ||||
|    and transforms a pmode pointer into a rmode seg:off far ptr.  */ | ||||
| static grub_err_t | ||||
| install_int13_handler (int noret __attribute__ ((unused))) | ||||
| { | ||||
|   /* Size of the full int13 handler "bundle", including code and map.  */ | ||||
|   grub_uint32_t total_size; | ||||
|   /* Base address of the space reserved for the handler bundle.  */ | ||||
|   grub_uint8_t *handler_base = 0; | ||||
|   /* Address of the map within the deployed bundle.  */ | ||||
|   int13map_node_t *handler_map; | ||||
| 
 | ||||
|   int i; | ||||
|   int entries = 0; | ||||
|   drivemap_node_t *curentry = map_head; | ||||
| 
 | ||||
|   /* Count entries to prepare a contiguous map block.  */ | ||||
|   while (curentry) | ||||
|     { | ||||
|       entries++; | ||||
|       curentry = curentry->next; | ||||
|     } | ||||
|   if (entries == 0) | ||||
|     { | ||||
|       /* No need to install the int13h handler.  */ | ||||
|       grub_dprintf ("drivemap", "No drives marked as remapped, not installing " | ||||
| 		    "our int13h handler.\n"); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("drivemap", "Installing our int13h handler\n"); | ||||
| 
 | ||||
|   /* Save the pointer to the old handler.  */ | ||||
|   grub_drivemap_oldhandler = *int13slot; | ||||
|   grub_dprintf ("drivemap", "Original int13 handler: %04x:%04x\n", | ||||
| 		(grub_drivemap_oldhandler >> 16) & 0x0ffff, | ||||
| 		grub_drivemap_oldhandler & 0x0ffff); | ||||
| 
 | ||||
|   /* Find a rmode-segment-aligned zone in conventional memory big
 | ||||
|      enough to hold the handler and its data.  */ | ||||
|   total_size = INT13H_OFFSET (&grub_drivemap_mapstart) | ||||
|     + (entries + 1) * sizeof (int13map_node_t); | ||||
|   grub_dprintf ("drivemap", "Payload is %u bytes long\n", total_size); | ||||
|   handler_base = grub_mmap_malign_and_register (16, total_size, | ||||
| 						&drivemap_mmap, | ||||
| 						GRUB_MACHINE_MEMORY_RESERVED, | ||||
| 						GRUB_MMAP_MALLOC_LOW); | ||||
|   if (! handler_base) | ||||
|     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't reserve " | ||||
| 		       "memory for the int13h handler"); | ||||
| 
 | ||||
|   /* Copy int13h handler bundle to reserved area.  */ | ||||
|   grub_dprintf ("drivemap", "Reserved memory at %p, copying handler\n", | ||||
| 		handler_base); | ||||
|   grub_memcpy (handler_base, &grub_drivemap_handler, | ||||
| 	       INT13H_OFFSET (&grub_drivemap_mapstart)); | ||||
| 
 | ||||
|   /* Copy the mappings to the reserved area.  */ | ||||
|   curentry = map_head; | ||||
|   handler_map = (int13map_node_t *) (handler_base + | ||||
| 				     INT13H_OFFSET (&grub_drivemap_mapstart)); | ||||
|   grub_dprintf ("drivemap", "Target map at %p, copying mappings\n", handler_map); | ||||
|   for (i = 0; i < entries; ++i, curentry = curentry->next) | ||||
|     { | ||||
|       handler_map[i].disknum = curentry->newdrive; | ||||
|       handler_map[i].mapto = curentry->redirto; | ||||
|       grub_dprintf ("drivemap", "\t#%d: 0x%02x <- 0x%02x\n", i, | ||||
| 		    handler_map[i].disknum, handler_map[i].mapto); | ||||
|     } | ||||
|   /* Signal end-of-map.  */ | ||||
|   handler_map[i].disknum = 0; | ||||
|   handler_map[i].mapto = 0; | ||||
|   grub_dprintf ("drivemap", "\t#%d: 0x00 <- 0x00 (end)\n", i); | ||||
| 
 | ||||
|   /* Install our function as the int13h handler in the IVT.  */ | ||||
|   *int13slot = ((grub_uint32_t) handler_base) << 12;	/* Segment address.  */ | ||||
|   grub_dprintf ("drivemap", "New int13 handler: %04x:%04x\n", | ||||
| 		(*int13slot >> 16) & 0x0ffff, *int13slot & 0x0ffff); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| uninstall_int13_handler (void) | ||||
| { | ||||
|   if (! grub_drivemap_oldhandler) | ||||
|     return GRUB_ERR_NONE; | ||||
| 
 | ||||
|   *int13slot = grub_drivemap_oldhandler; | ||||
|   grub_mmap_free_and_unregister (drivemap_mmap); | ||||
|   grub_drivemap_oldhandler = 0; | ||||
|   grub_dprintf ("drivemap", "Restored int13 handler: %04x:%04x\n", | ||||
| 		(*int13slot >> 16) & 0x0ffff, *int13slot & 0x0ffff); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_get_root_biosnumber_drivemap (void) | ||||
| { | ||||
|   char *biosnum; | ||||
|   int ret = -1; | ||||
|   grub_device_t dev; | ||||
| 
 | ||||
|   biosnum = grub_env_get ("biosnum"); | ||||
| 
 | ||||
|   if (biosnum) | ||||
|     return grub_strtoul (biosnum, 0, 0); | ||||
| 
 | ||||
|   dev = grub_device_open (0); | ||||
|   if (dev && dev->disk && dev->disk->dev | ||||
|       && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID) | ||||
|     { | ||||
|       drivemap_node_t *curnode = map_head; | ||||
|       ret = (int) dev->disk->id; | ||||
|       while (curnode) | ||||
| 	{ | ||||
| 	  if (curnode->redirto == ret) | ||||
| 	    { | ||||
| 	      ret = curnode->newdrive; | ||||
| 	      break; | ||||
| 	    } | ||||
| 	  curnode = curnode->next; | ||||
| 	} | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|   if (dev) | ||||
|     grub_device_close (dev); | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| static int (*grub_get_root_biosnumber_saved) (void); | ||||
| 
 | ||||
| GRUB_MOD_INIT (drivemap) | ||||
| { | ||||
|   grub_get_root_biosnumber_saved = grub_get_root_biosnumber; | ||||
|   grub_get_root_biosnumber = grub_get_root_biosnumber_drivemap; | ||||
|   cmd = grub_register_extcmd ("drivemap", grub_cmd_drivemap, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("-l | -r | [-s] grubdev osdisk."), | ||||
| 			      N_("Manage the BIOS drive mappings."), | ||||
| 			      options); | ||||
|   drivemap_hook = | ||||
|     grub_loader_register_preboot_hook (&install_int13_handler, | ||||
| 				       &uninstall_int13_handler, | ||||
| 				       GRUB_LOADER_PREBOOT_HOOK_PRIO_NORMAL); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (drivemap) | ||||
| { | ||||
|   grub_get_root_biosnumber = grub_get_root_biosnumber_saved; | ||||
|   grub_loader_unregister_preboot_hook (drivemap_hook); | ||||
|   drivemap_hook = 0; | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										110
									
								
								grub-core/commands/i386/pc/drivemap_int13h.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								grub-core/commands/i386/pc/drivemap_int13h.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | |||
| /* drivemap_int13h.S - interrupt handler for the BIOS drive remapper */ | ||||
| /* | ||||
|  *  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/symbol.h> | ||||
| 
 | ||||
| #define INT13H_OFFSET(x) ((x) - LOCAL (base)) | ||||
| 
 | ||||
| .code16 | ||||
| 
 | ||||
| /* Copy starts here.  When deployed, this code must be segment-aligned.  */ | ||||
| 
 | ||||
| /* The replacement int13 handler.   Preserve all registers.  */ | ||||
| FUNCTION(grub_drivemap_handler) | ||||
| LOCAL (base): | ||||
| 	/* Save %dx for future restore. */ | ||||
| 	push	%dx | ||||
| 	/* Push flags. Used to simulate interrupt with original flags. */ | ||||
| 	pushf | ||||
| 
 | ||||
| 	/* Map the drive number (always in DL).  */ | ||||
| 	push	%ax | ||||
| 	push	%bx | ||||
| 	movw	$INT13H_OFFSET(LOCAL (mapstart)), %bx | ||||
| 
 | ||||
| more_remaining: | ||||
| 	movw	%cs:(%bx), %ax | ||||
| 	cmpb	%ah, %al | ||||
| 	jz	not_found /* DRV=DST => map end - drive not remapped, keep DL.  */ | ||||
| 	inc	%bx | ||||
| 	inc	%bx | ||||
| 	cmpb	%dl, %al | ||||
| 	jnz	more_remaining /* Not found, but more remaining, loop.  */ | ||||
| 	movb	%ah, %dl /* Found - drive remapped, modify DL.  */ | ||||
| 
 | ||||
| not_found: | ||||
| 	pop	%bx | ||||
| 	pop	%ax | ||||
| 
 | ||||
| 	/* If the call isn't ah=0x8 or ah=0x15 we must restore %dx.  */ | ||||
| 	cmpb	$0x8, %ah | ||||
| 	jz	norestore | ||||
| 	cmpb	$0x15, %ah | ||||
| 	jz	norestore | ||||
| 
 | ||||
| 	/* Restore flags.  */ | ||||
| 	popf | ||||
| 	pushf | ||||
| 
 | ||||
| 	lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler)) | ||||
| 
 | ||||
| 	push	%bp | ||||
| 	mov	%sp, %bp | ||||
| 
 | ||||
| tail: | ||||
| 	/* Save new flags below %esp so the caller will recieve new flags.  */ | ||||
| 	pushf | ||||
| 	pop	%dx | ||||
| 	mov	%dx, 8(%bp) | ||||
| 
 | ||||
| 	pop	%bp | ||||
| 
 | ||||
| 	/* Restore %dx.  */ | ||||
| 	pop	%dx | ||||
| 	iret | ||||
| 
 | ||||
| norestore: | ||||
| 
 | ||||
| 	/* Restore flags.  */ | ||||
| 	popf | ||||
| 	pushf | ||||
| 
 | ||||
| 	lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler)) | ||||
| 
 | ||||
| 	push	%bp | ||||
| 	mov	%sp, %bp | ||||
| 
 | ||||
| 	/* Save %dx. So it won't be restored to original value.  */ | ||||
| 	mov	%dx, 2(%bp) | ||||
| 
 | ||||
| 	jmp tail | ||||
| 
 | ||||
| /* Far pointer to the old handler.  Stored as a CS:IP in the style of real-mode | ||||
|    IVT entries (thus PI:SC in mem).  */ | ||||
| VARIABLE(grub_drivemap_oldhandler) | ||||
| LOCAL (oldhandler): | ||||
| 	.word 0x0, 0x0 | ||||
| 
 | ||||
| /* This label MUST be at the end of the copied block, since the installer code | ||||
|    reserves additional space for mappings at runtime and copies them over it.  */ | ||||
| 	.align 2
 | ||||
| 	 | ||||
| VARIABLE(grub_drivemap_mapstart) | ||||
| LOCAL (mapstart): | ||||
| 	.byte 0
 | ||||
							
								
								
									
										122
									
								
								grub-core/commands/i386/pc/halt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								grub-core/commands/i386/pc/halt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,122 @@ | |||
| /* halt.c - command to halt the computer.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <grub/machine/int.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"no-apm", 'n', 0, N_("Do not use APM to halt the computer."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static inline void __attribute__ ((noreturn)) | ||||
| stop (void) | ||||
| { | ||||
|   while (1) | ||||
|     { | ||||
|       asm volatile ("hlt"); | ||||
|     } | ||||
| } | ||||
| /*
 | ||||
|  * Halt the system, using APM if possible. If NO_APM is true, don't use | ||||
|  * APM even if it is available. | ||||
|  */ | ||||
| void  | ||||
| grub_halt (int no_apm) | ||||
| { | ||||
|   struct grub_bios_int_registers regs; | ||||
| 
 | ||||
|   if (no_apm) | ||||
|     stop (); | ||||
| 
 | ||||
|   /* detect APM */ | ||||
|   regs.eax = 0x5300; | ||||
|   regs.ebx = 0; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x15, ®s); | ||||
|    | ||||
|   if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) | ||||
|     stop (); | ||||
| 
 | ||||
|   /* disconnect APM first */ | ||||
|   regs.eax = 0x5304; | ||||
|   regs.ebx = 0; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x15, ®s); | ||||
| 
 | ||||
|   /* connect APM */ | ||||
|   regs.eax = 0x5301; | ||||
|   regs.ebx = 0; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x15, ®s); | ||||
|   if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) | ||||
|     stop (); | ||||
| 
 | ||||
|   /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */ | ||||
|   regs.eax = 0x530E; | ||||
|   regs.ebx = 0; | ||||
|   regs.ecx = 0x0101; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x15, ®s); | ||||
|   if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) | ||||
|     stop (); | ||||
| 
 | ||||
|   /* set the power state to off */ | ||||
|   regs.eax = 0x5307; | ||||
|   regs.ebx = 1; | ||||
|   regs.ecx = 3; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x15, ®s); | ||||
| 
 | ||||
|   /* shouldn't reach here */ | ||||
|   stop (); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_halt (grub_extcmd_t cmd, | ||||
| 	       int argc __attribute__ ((unused)), | ||||
| 	       char **args __attribute__ ((unused))) | ||||
| 
 | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   int no_apm = 0; | ||||
|   if (state[0].set) | ||||
|     no_apm = 1; | ||||
|   grub_halt (no_apm); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(halt) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("halt", grub_cmd_halt, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      "[-n]", | ||||
| 			      N_("Halt the system, if possible using APM."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(halt) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										273
									
								
								grub-core/commands/i386/pc/play.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								grub-core/commands/i386/pc/play.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,273 @@ | |||
| /* play.c - command to play a tune  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| /* Lots of this file is borrowed from GNU/Hurd generic-speaker driver.  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/machine/time.h> | ||||
| #include <grub/cpu/io.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| #define BASE_TEMPO (60 * GRUB_TICKS_PER_SECOND) | ||||
| 
 | ||||
| /* The speaker port.  */ | ||||
| #define SPEAKER			0x61 | ||||
| 
 | ||||
| /* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
 | ||||
|    from timer 2.  */ | ||||
| #define SPEAKER_TMR2		0x01 | ||||
| 
 | ||||
| /* If SPEAKER_TMR2 is not set, this provides direct input into the
 | ||||
|    speaker.  Otherwise, this enables or disables the output from the | ||||
|    timer.  */ | ||||
| #define SPEAKER_DATA		0x02 | ||||
| 
 | ||||
| /* The PIT channel value ports.  You can write to and read from them.
 | ||||
|    Do not mess with timer 0 or 1.  */ | ||||
| #define PIT_COUNTER_0		0x40 | ||||
| #define PIT_COUNTER_1		0x41 | ||||
| #define PIT_COUNTER_2		0x42 | ||||
| 
 | ||||
| /* The frequency of the PIT clock.  */ | ||||
| #define PIT_FREQUENCY		0x1234dd | ||||
| 
 | ||||
| /* The PIT control port.  You can only write to it.  Do not mess with
 | ||||
|    timer 0 or 1.  */ | ||||
| #define PIT_CTRL		0x43 | ||||
| #define PIT_CTRL_SELECT_MASK	0xc0 | ||||
| #define PIT_CTRL_SELECT_0	0x00 | ||||
| #define PIT_CTRL_SELECT_1	0x40 | ||||
| #define PIT_CTRL_SELECT_2	0x80 | ||||
| 
 | ||||
| /* Read and load control.  */ | ||||
| #define PIT_CTRL_READLOAD_MASK	0x30 | ||||
| #define PIT_CTRL_COUNTER_LATCH	0x00	/* Hold timer value until read.  */ | ||||
| #define PIT_CTRL_READLOAD_LSB	0x10	/* Read/load the LSB.  */ | ||||
| #define PIT_CTRL_READLOAD_MSB	0x20	/* Read/load the MSB.  */ | ||||
| #define PIT_CTRL_READLOAD_WORD	0x30	/* Read/load the LSB then the MSB.  */ | ||||
| 
 | ||||
| /* Mode control.  */ | ||||
| #define PIT_CTRL_MODE_MASK	0x0e | ||||
| 
 | ||||
| /* Interrupt on terminal count.  Setting the mode sets output to low.
 | ||||
|    When counter is set and terminated, output is set to high.  */ | ||||
| #define PIT_CTRL_INTR_ON_TERM	0x00 | ||||
| 
 | ||||
| /* Programmable one-shot.  When loading counter, output is set to
 | ||||
|    high.  When counter terminated, output is set to low.  Can be | ||||
|    triggered again from that point on by setting the gate pin to | ||||
|    high.  */ | ||||
| #define PIT_CTRL_PROGR_ONE_SHOT	0x02 | ||||
| 
 | ||||
| /* Rate generator.  Output is low for one period of the counter, and
 | ||||
|    high for the other.  */ | ||||
| #define PIT_CTRL_RATE_GEN	0x04 | ||||
| 
 | ||||
| /* Square wave generator.  Output is low for one half of the period,
 | ||||
|    and high for the other half.  */ | ||||
| #define PIT_CTRL_SQUAREWAVE_GEN	0x06 | ||||
| 
 | ||||
| /* Software triggered strobe.  Setting the mode sets output to high.
 | ||||
|    When counter is set and terminated, output is set to low.  */ | ||||
| #define PIT_CTRL_SOFTSTROBE	0x08 | ||||
| 
 | ||||
| /* Hardware triggered strobe.  Like software triggered strobe, but
 | ||||
|    only starts the counter when the gate pin is set to high.  */ | ||||
| #define PIT_CTRL_HARDSTROBE	0x0a | ||||
| 
 | ||||
| /* Count mode.  */ | ||||
| #define PIT_CTRL_COUNT_MASK	0x01 | ||||
| #define PIT_CTRL_COUNT_BINARY	0x00	/* 16-bit binary counter.  */ | ||||
| #define PIT_CTRL_COUNT_BCD	0x01	/* 4-decade BCD counter.  */ | ||||
| 
 | ||||
| #define T_REST			((grub_uint16_t) 0) | ||||
| #define T_FINE			((grub_uint16_t) -1) | ||||
| 
 | ||||
| struct note | ||||
| { | ||||
|   grub_uint16_t pitch; | ||||
|   grub_uint16_t duration; | ||||
| }; | ||||
| 
 | ||||
| static void | ||||
| beep_off (void) | ||||
| { | ||||
|   unsigned char status; | ||||
| 
 | ||||
|   status = grub_inb (SPEAKER); | ||||
|   grub_outb (status & ~(SPEAKER_TMR2 | SPEAKER_DATA), SPEAKER); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| beep_on (grub_uint16_t pitch) | ||||
| { | ||||
|   unsigned char status; | ||||
|   unsigned int counter; | ||||
| 
 | ||||
|   if (pitch < 20) | ||||
|     pitch = 20; | ||||
|   else if (pitch > 20000) | ||||
|     pitch = 20000; | ||||
| 
 | ||||
|   counter = PIT_FREQUENCY / pitch; | ||||
| 
 | ||||
|   /* Program timer 2.  */ | ||||
|   grub_outb (PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD | ||||
| 	| PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY, PIT_CTRL); | ||||
|   grub_outb (counter & 0xff, PIT_COUNTER_2);		/* LSB */ | ||||
|   grub_outb ((counter >> 8) & 0xff, PIT_COUNTER_2);	/* MSB */ | ||||
| 
 | ||||
|   /* Start speaker.  */ | ||||
|   status = grub_inb (SPEAKER); | ||||
|   grub_outb (status | SPEAKER_TMR2 | SPEAKER_DATA, SPEAKER); | ||||
| } | ||||
| 
 | ||||
| /* Returns whether playing should continue.  */ | ||||
| static int | ||||
| play (unsigned tempo, struct note *note) | ||||
| { | ||||
|   unsigned int to; | ||||
| 
 | ||||
|   if (note->pitch == T_FINE || grub_checkkey () >= 0) | ||||
|     return 1; | ||||
| 
 | ||||
|   grub_dprintf ("play", "pitch = %d, duration = %d\n", note->pitch, | ||||
|                 note->duration); | ||||
| 
 | ||||
|   switch (note->pitch) | ||||
|     { | ||||
|       case T_REST: | ||||
|         beep_off (); | ||||
|         break; | ||||
| 
 | ||||
|       default: | ||||
|         beep_on (note->pitch); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|   to = grub_get_rtc () + BASE_TEMPO * note->duration / tempo; | ||||
|   while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0)) | ||||
|     ; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), | ||||
| 	       int argc, char **args) | ||||
| { | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name or tempo and notes required"); | ||||
| 
 | ||||
|   if (argc == 1) | ||||
|     { | ||||
|       struct note buf; | ||||
|       grub_uint32_t tempo; | ||||
|       grub_file_t file; | ||||
| 
 | ||||
|       file = grub_file_open (args[0]); | ||||
| 
 | ||||
|       if (! file) | ||||
|         return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); | ||||
| 
 | ||||
|       if (grub_file_read (file, &tempo, sizeof (tempo)) != sizeof (tempo)) | ||||
|         { | ||||
|           grub_file_close (file); | ||||
|           return grub_error (GRUB_ERR_FILE_READ_ERROR, | ||||
|                              "file doesn't even contains a full tempo record"); | ||||
|         } | ||||
| 
 | ||||
|       tempo = grub_le_to_cpu32 (tempo); | ||||
|       grub_dprintf ("play","tempo = %d\n", tempo); | ||||
| 
 | ||||
|       while (grub_file_read (file, &buf, | ||||
|                              sizeof (struct note)) == sizeof (struct note)) | ||||
|         { | ||||
|           buf.pitch = grub_le_to_cpu16 (buf.pitch); | ||||
|           buf.duration = grub_le_to_cpu16 (buf.duration); | ||||
| 
 | ||||
|           if (play (tempo, &buf)) | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|       grub_file_close (file); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       char *end; | ||||
|       unsigned tempo; | ||||
|       struct note note; | ||||
|       int i; | ||||
| 
 | ||||
|       tempo = grub_strtoul (args[0], &end, 0); | ||||
| 
 | ||||
|       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"); | ||||
| 
 | ||||
|       grub_dprintf ("play","tempo = %d\n", tempo); | ||||
| 
 | ||||
|       for (i = 1; i + 1 < argc; i += 2) | ||||
|         { | ||||
|           note.pitch = grub_strtoul (args[i], &end, 0); | ||||
|           if (*end) | ||||
|             { | ||||
|               grub_error (GRUB_ERR_BAD_NUMBER, "bogus pitch number"); | ||||
|               break; | ||||
|             } | ||||
| 
 | ||||
|           note.duration = grub_strtoul (args[i + 1], &end, 0); | ||||
|           if (*end) | ||||
|             { | ||||
|               grub_error (GRUB_ERR_BAD_NUMBER, "bogus duration number"); | ||||
|               break; | ||||
|             } | ||||
| 
 | ||||
|           if (play (tempo, ¬e)) | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   beep_off (); | ||||
| 
 | ||||
|   while (grub_checkkey () > 0) | ||||
|     grub_getkey (); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(play) | ||||
| { | ||||
|   cmd = grub_register_command ("play", grub_cmd_play, | ||||
| 			       N_("FILE | TEMPO [PITCH1 DURATION1] [PITCH2 DURATION2] ... "), | ||||
| 			       N_("Play a tune.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(play) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										52
									
								
								grub-core/commands/i386/pc/pxecmd.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								grub-core/commands/i386/pc/pxecmd.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| /* 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> | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
							
								
								
									
										384
									
								
								grub-core/commands/i386/pc/sendkey.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								grub-core/commands/i386/pc/sendkey.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,384 @@ | |||
| /* sendkey.c - fake keystroke. */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  This program is free software; you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation; either version 2 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program; if not, write to the Free Software | ||||
|  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/cpu/io.h> | ||||
| #include <grub/loader.h> | ||||
| 
 | ||||
| static char sendkey[0x20]; | ||||
| /* Length of sendkey.  */ | ||||
| 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}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| static int simple_flag_offsets[]  | ||||
| = {5, 6, 4, 7, 11, 1, 0, 10, 13, 14, 12, 15, 9, 3, 8, 2}; | ||||
| 
 | ||||
| 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 */ | ||||
|   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 */ | ||||
| }; | ||||
| 
 | ||||
| /* The table for key symbols. If the "shifted" member of an entry is
 | ||||
|    NULL, the entry does not have shifted state. Copied from GRUB Legacy setkey fuction  */ | ||||
| static struct keysym keysym_table[] = | ||||
| { | ||||
|   {"escape",		0,		0x1b,	0,	0x01}, | ||||
|   {"1",			"exclam",	'1',	'!',	0x02}, | ||||
|   {"2",			"at",		'2',	'@',	0x03}, | ||||
|   {"3",			"numbersign",	'3',	'#',	0x04}, | ||||
|   {"4",			"dollar",	'4',	'$',	0x05}, | ||||
|   {"5",			"percent",	'5',	'%',	0x06}, | ||||
|   {"6",			"caret",	'6',	'^',	0x07}, | ||||
|   {"7",			"ampersand",	'7',	'&',	0x08}, | ||||
|   {"8",			"asterisk",	'8',	'*',	0x09}, | ||||
|   {"9",			"parenleft",	'9',	'(',	0x0a}, | ||||
|   {"0",			"parenright",	'0',	')',	0x0b}, | ||||
|   {"minus",		"underscore",	'-',	'_',	0x0c}, | ||||
|   {"equal",		"plus",		'=',	'+',	0x0d}, | ||||
|   {"backspace",		0,		'\b',	0,	0x0e}, | ||||
|   {"tab",		0,		'\t',	0,	0x0f}, | ||||
|   {"q",			"Q",		'q',	'Q',	0x10}, | ||||
|   {"w",			"W",		'w',	'W',	0x11}, | ||||
|   {"e",			"E",		'e',	'E',	0x12}, | ||||
|   {"r",			"R",		'r',	'R',	0x13}, | ||||
|   {"t",			"T",		't',	'T',	0x14}, | ||||
|   {"y",			"Y",		'y',	'Y',	0x15}, | ||||
|   {"u",			"U",		'u',	'U',	0x16}, | ||||
|   {"i",			"I",		'i',	'I',	0x17}, | ||||
|   {"o",			"O",		'o',	'O',	0x18}, | ||||
|   {"p",			"P",		'p',	'P',	0x19}, | ||||
|   {"bracketleft",	"braceleft",	'[',	'{',	0x1a}, | ||||
|   {"bracketright",	"braceright",	']',	'}',	0x1b}, | ||||
|   {"enter",		0,		'\r',	0,	0x1c}, | ||||
|   {"control",		0,		0,	0,	0x1d}, | ||||
|   {"a",			"A",		'a',	'A',	0x1e}, | ||||
|   {"s",			"S",		's',	'S',	0x1f}, | ||||
|   {"d",			"D",		'd',	'D',	0x20}, | ||||
|   {"f",			"F",		'f',	'F',	0x21}, | ||||
|   {"g",			"G",		'g',	'G',	0x22}, | ||||
|   {"h",			"H",		'h',	'H',	0x23}, | ||||
|   {"j",			"J",		'j',	'J',	0x24}, | ||||
|   {"k",			"K",		'k',	'K',	0x25}, | ||||
|   {"l",			"L",		'l',	'L',	0x26}, | ||||
|   {"semicolon",		"colon",	';',	':',	0x27}, | ||||
|   {"quote",		"doublequote",	'\'',	'"',	0x28}, | ||||
|   {"backquote",		"tilde",	'`',	'~',	0x29}, | ||||
|   {"shift",		0,		0,	0,	0x2a}, | ||||
|   {"backslash",		"bar",		'\\',	'|',	0x2b}, | ||||
|   {"z",			"Z",		'z',	'Z',	0x2c}, | ||||
|   {"x",			"X",		'x',	'X',	0x2d}, | ||||
|   {"c",			"C",		'c',	'C',	0x2e}, | ||||
|   {"v",			"V",		'v',	'V',	0x2f}, | ||||
|   {"b",			"B",		'b',	'B',	0x30}, | ||||
|   {"n",			"N",		'n',	'N',	0x31}, | ||||
|   {"m",			"M",		'm',	'M',	0x32}, | ||||
|   {"comma",		"less",		',',	'<',	0x33}, | ||||
|   {"period",		"greater",	'.',	'>',	0x34}, | ||||
|   {"slash",		"question",	'/',	'?',	0x35}, | ||||
|   {"rshift",		0,		0,	0,	0x36}, | ||||
|   {"numasterisk",		0,		'*',	0,	0x37}, | ||||
|   {"alt",		0,		0,	0,	0x38}, | ||||
|   {"space",		0,		' ',	0,	0x39}, | ||||
|   {"capslock",		0,		0,	0,	0x3a}, | ||||
|   {"F1",		0,		0,	0,	0x3b}, | ||||
|   {"F2",		0,		0,	0,	0x3c}, | ||||
|   {"F3",		0,		0,	0,	0x3d}, | ||||
|   {"F4",		0,		0,	0,	0x3e}, | ||||
|   {"F5",		0,		0,	0,	0x3f}, | ||||
|   {"F6",	 	0,		0,	0,	0x40}, | ||||
|   {"F7",		0,		0,	0,	0x41}, | ||||
|   {"F8",		0,		0,	0,	0x42}, | ||||
|   {"F9",		0,		0,	0,	0x43}, | ||||
|   {"F10",		0,		0,	0,	0x44}, | ||||
|   {"num7",		"numhome",		'7',	0,	0x47}, | ||||
|   {"num8",		"numup",		'8',	0,	0x48}, | ||||
|   {"num9",		"numpgup",		'9',	0,	0x49}, | ||||
|   {"numminus",		0,		'-',	0,	0x4a}, | ||||
|   {"num4",		"numleft",		'4',	0,	0x4b}, | ||||
|   {"num5",		"numcenter",		'5',	0,	0x4c}, | ||||
|   {"num6",		"numright",		'6',	0,	0x4d}, | ||||
|   {"numplus",		0,		'-',	0,	0x4e}, | ||||
|   {"num1",		"numend",		'1',	0,	0x4f}, | ||||
|   {"num2",		"numdown",		'2',	0,	0x50}, | ||||
|   {"num3",		"numpgdown",		'3',	0,	0x51}, | ||||
|   {"num0",		"numinsert",		'0',	0,	0x52}, | ||||
|   {"numperiod",	"numdelete", 0,	0x7f,		0x53}, | ||||
|   {"F11",		0,		0,	0,	0x57}, | ||||
|   {"F12",		0,		0,	0,	0x58}, | ||||
|   {"numenter",		0,		'\r',	0,	0xe0}, | ||||
|   {"numslash",		0,		'/',	0,	0xe0}, | ||||
|   {"delete",		0,		0x7f,	0,	0xe0}, | ||||
|   {"insert",		0,		0xe0,	0,	0x52}, | ||||
|   {"home",		0,		0xe0,	0,	0x47}, | ||||
|   {"end",		0,		0xe0,	0,	0x4f}, | ||||
|   {"pgdown",		0,		0xe0,	0,	0x51}, | ||||
|   {"pgup",		0,		0xe0,	0,	0x49}, | ||||
|   {"down",		0,		0xe0,	0,	0x50}, | ||||
|   {"up",		0,		0xe0,	0,	0x48}, | ||||
|   {"left",		0,		0xe0,	0,	0x4b}, | ||||
|   {"right",		0,		0xe0,	0,	0x4d} | ||||
| }; | ||||
| 
 | ||||
| /* Set a simple flag in flags variable  
 | ||||
|    OUTOFFSET - offset of flag in FLAGS, | ||||
|    OP - action id | ||||
| */ | ||||
| static void | ||||
| grub_sendkey_set_simple_flag (int outoffset, int op) | ||||
| {       | ||||
|   if (op == 2) | ||||
|     { | ||||
|       andmask |= (1 << outoffset); | ||||
|       ormask &= ~(1 << outoffset); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       andmask &= (~(1 << outoffset)); | ||||
|       if (op == 1) | ||||
| 	ormask |= (1 << outoffset); | ||||
|       else | ||||
| 	ormask &= ~(1 << outoffset); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_sendkey_parse_op (struct grub_arg_list state) | ||||
| { | ||||
|   if (! state.set) | ||||
|     return 2; | ||||
| 
 | ||||
|   if (grub_strcmp (state.arg, "off") == 0 || grub_strcmp (state.arg, "0") == 0  | ||||
|       || grub_strcmp (state.arg, "unpress") == 0) | ||||
|     return 0; | ||||
| 
 | ||||
|   if (grub_strcmp (state.arg, "on")  == 0 || grub_strcmp (state.arg, "1")  == 0 | ||||
|       || grub_strcmp (state.arg, "press") == 0) | ||||
|     return 1; | ||||
| 
 | ||||
|   return 2; | ||||
| } | ||||
| 
 | ||||
| static grub_uint32_t oldflags; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_sendkey_postboot (void) | ||||
| { | ||||
|   /* For convention: pointer to flags.  */ | ||||
|   grub_uint32_t *flags = (grub_uint32_t *) 0x417; | ||||
| 
 | ||||
|   *flags = oldflags; | ||||
| 
 | ||||
|   *((char *) 0x41a) = 0x1e; | ||||
|   *((char *) 0x41c) = 0x1e; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| /* Set keyboard buffer to our sendkey  */ | ||||
| static grub_err_t | ||||
| grub_sendkey_preboot (int noret __attribute__ ((unused))) | ||||
| { | ||||
|   /* For convention: pointer to flags.  */ | ||||
|   grub_uint32_t *flags = (grub_uint32_t *) 0x417; | ||||
| 
 | ||||
|   oldflags = *flags; | ||||
|    | ||||
|   /* Set the sendkey.  */ | ||||
|   *((char *) 0x41a) = 0x1e; | ||||
|   *((char *) 0x41c) = keylen + 0x1e; | ||||
|   grub_memcpy ((char *) 0x41e, sendkey, 0x20); | ||||
| 
 | ||||
|   /* Transform "any ctrl" to "right ctrl" flag.  */ | ||||
|   if (*flags & (1 << 8)) | ||||
|     *flags &= ~(1 << 2); | ||||
| 
 | ||||
|   /* Transform "any alt" to "right alt" flag.  */ | ||||
|   if (*flags & (1 << 9)) | ||||
|     *flags &= ~(1 << 3); | ||||
|    | ||||
|   *flags = (*flags & andmask) | ormask; | ||||
| 
 | ||||
|   /* Transform "right ctrl" to "any ctrl" flag.  */ | ||||
|   if (*flags & (1 << 8)) | ||||
|     *flags |= (1 << 2); | ||||
| 
 | ||||
|   /* Transform "right alt" to "any alt" flag.  */ | ||||
|   if (*flags & (1 << 9)) | ||||
|     *flags |= (1 << 3); | ||||
| 
 | ||||
|   /* Write new LED state  */ | ||||
|   if (!noled) | ||||
|     { | ||||
|       int value = 0; | ||||
|       int failed; | ||||
|       /* Try 5 times  */ | ||||
|       for (failed = 0; failed < 5; failed++) | ||||
| 	{ | ||||
| 	  value = 0; | ||||
| 	  /* Send command change LEDs  */ | ||||
| 	  grub_outb (0xed, 0x60); | ||||
| 
 | ||||
| 	  /* Wait */ | ||||
| 	  do | ||||
| 	    value = grub_inb (0x60); | ||||
| 	  while ((value != 0xfa) && (value != 0xfe)); | ||||
| 
 | ||||
| 	  if (value == 0xfa) | ||||
| 	    { | ||||
| 	      /* Set new LEDs*/ | ||||
| 	      grub_outb ((*flags >> 4) & 7, 0x60); | ||||
| 	      break; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_sendkey (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
| 
 | ||||
|   auto int find_key_code (char *key);  | ||||
|   auto int find_ascii_code (char *key); | ||||
| 
 | ||||
|   int find_key_code (char *key) | ||||
|     { | ||||
|       unsigned i; | ||||
| 
 | ||||
|       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++) | ||||
| 	{ | ||||
| 	  if (keysym_table[i].unshifted_name  | ||||
| 	      && grub_strcmp (key, keysym_table[i].unshifted_name) == 0) | ||||
| 	    return keysym_table[i].keycode; | ||||
| 	  else if (keysym_table[i].shifted_name  | ||||
| 		   && grub_strcmp (key, keysym_table[i].shifted_name) == 0) | ||||
| 	    return keysym_table[i].keycode; | ||||
| 	} | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   int find_ascii_code (char *key) | ||||
|     { | ||||
|       unsigned i; | ||||
| 
 | ||||
|       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++) | ||||
| 	{ | ||||
| 	  if (keysym_table[i].unshifted_name  | ||||
| 	      && grub_strcmp (key, keysym_table[i].unshifted_name) == 0) | ||||
| 	    return keysym_table[i].unshifted_ascii; | ||||
| 	  else if (keysym_table[i].shifted_name  | ||||
| 		   && grub_strcmp (key, keysym_table[i].shifted_name) == 0) | ||||
| 	    return keysym_table[i].shifted_ascii; | ||||
| 	} | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   andmask = 0xffffffff; | ||||
|   ormask = 0; | ||||
| 
 | ||||
|   { | ||||
|     int i; | ||||
| 
 | ||||
|     keylen = 0; | ||||
| 
 | ||||
|     for (i = 0; i < argc && keylen < 0x20; i++) | ||||
|       { | ||||
| 	int key_code; | ||||
| 	 | ||||
| 	key_code = find_key_code (args[i]); | ||||
| 	if (key_code) | ||||
| 	  { | ||||
| 	    sendkey[keylen++] = find_ascii_code (args[i]); | ||||
| 	    sendkey[keylen++] = key_code; | ||||
| 	  } | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
|   { | ||||
|     unsigned i; | ||||
|     for (i = 0; i < sizeof (simple_flag_offsets)  | ||||
| 	   / sizeof (simple_flag_offsets[0]); i++) | ||||
|       grub_sendkey_set_simple_flag (simple_flag_offsets[i],  | ||||
| 				    grub_sendkey_parse_op(state[i])); | ||||
|   } | ||||
| 
 | ||||
|   /* Set noled. */ | ||||
|   noled = (state[sizeof (simple_flag_offsets)  | ||||
| 		 / sizeof (simple_flag_offsets[0])].set); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| static void *preboot_hook; | ||||
| 
 | ||||
| GRUB_MOD_INIT (sendkey) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey,  | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      "sendkey [KEYSTROKE1] [KEYSTROKE2] ...", | ||||
| 			      "Emulate a keystroke", options); | ||||
| 
 | ||||
|   preboot_hook  | ||||
|     = grub_loader_register_preboot_hook (grub_sendkey_preboot,  | ||||
| 					 grub_sendkey_postboot, | ||||
| 					 GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (sendkey) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
|   grub_loader_unregister_preboot_hook (preboot_hook); | ||||
| } | ||||
							
								
								
									
										185
									
								
								grub-core/commands/i386/pc/vbeinfo.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								grub-core/commands/i386/pc/vbeinfo.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,185 @@ | |||
| /* vbeinfo.c - command to list compatible VBE video modes.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/machine/init.h> | ||||
| #include <grub/machine/vbe.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static void * | ||||
| real2pm (grub_vbe_farptr_t ptr) | ||||
| { | ||||
|   return (void *) ((((unsigned long) ptr & 0xFFFF0000) >> 12UL) | ||||
| 		   + ((unsigned long) ptr & 0x0000FFFF)); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_vbeinfo (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		  int argc __attribute__ ((unused)), | ||||
| 		  char **args __attribute__ ((unused))) | ||||
| { | ||||
|   struct grub_vbe_info_block controller_info; | ||||
|   struct grub_vbe_mode_info_block mode_info_tmp; | ||||
|   grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE; | ||||
|   grub_uint16_t *video_mode_list; | ||||
|   grub_uint16_t *p; | ||||
|   grub_uint16_t *saved_video_mode_list; | ||||
|   grub_size_t video_mode_list_size; | ||||
|   grub_err_t err; | ||||
|   char *modevar; | ||||
| 
 | ||||
|   err = grub_vbe_probe (&controller_info); | ||||
|   if (err != GRUB_ERR_NONE) | ||||
|     return err; | ||||
| 
 | ||||
|   grub_printf ("VBE info:   version: %d.%d  OEM software rev: %d.%d\n", | ||||
| 	       controller_info.version >> 8, | ||||
|                controller_info.version & 0xFF, | ||||
|                controller_info.oem_software_rev >> 8, | ||||
|                controller_info.oem_software_rev & 0xFF); | ||||
| 
 | ||||
|   /* The total_memory field is in 64 KiB units.  */ | ||||
|   grub_printf ("            total memory: %d KiB\n", | ||||
|                (controller_info.total_memory << 16) / 1024); | ||||
| 
 | ||||
|   /* Because the information on video modes is stored in a temporary place,
 | ||||
|      it is better to copy it to somewhere safe.  */ | ||||
|   p = video_mode_list = real2pm (controller_info.video_mode_ptr); | ||||
|   while (*p++ != 0xFFFF) | ||||
|     ; | ||||
| 
 | ||||
|   video_mode_list_size = (grub_addr_t) p - (grub_addr_t) video_mode_list; | ||||
|   saved_video_mode_list = grub_malloc (video_mode_list_size); | ||||
|   if (! saved_video_mode_list) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_memcpy (saved_video_mode_list, video_mode_list, video_mode_list_size); | ||||
| 
 | ||||
|   grub_printf ("List of compatible video modes:\n"); | ||||
|   grub_printf ("Legend: P=Packed pixel, D=Direct color, " | ||||
| 	       "mask/pos=R/G/B/reserved\n"); | ||||
| 
 | ||||
|   /* Walk through all video modes listed.  */ | ||||
|   for (p = saved_video_mode_list; *p != 0xFFFF; p++) | ||||
|     { | ||||
|       const char *memory_model = 0; | ||||
|       grub_uint32_t mode = (grub_uint32_t) *p; | ||||
| 
 | ||||
|       err = grub_vbe_get_video_mode_info (mode, &mode_info_tmp); | ||||
|       if (err != GRUB_ERR_NONE) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  continue; | ||||
| 	} | ||||
| 
 | ||||
|       if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_SUPPORTED) == 0) | ||||
| 	/* If not available, skip it.  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_RESERVED_1) == 0) | ||||
| 	/* Not enough information.  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_COLOR) == 0) | ||||
| 	/* Monochrome is unusable.  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_LFB_AVAIL) == 0) | ||||
| 	/* We support only linear frame buffer modes.  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_GRAPHICS) == 0) | ||||
| 	/* We allow only graphical modes.  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       switch (mode_info_tmp.memory_model) | ||||
| 	{ | ||||
| 	case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL: | ||||
| 	  memory_model = "Packed"; | ||||
| 	  break; | ||||
| 	case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR: | ||||
| 	  memory_model = "Direct"; | ||||
| 	  break; | ||||
| 
 | ||||
| 	default: | ||||
| 	  break; | ||||
| 	} | ||||
| 
 | ||||
|       if (! memory_model) | ||||
| 	continue; | ||||
| 
 | ||||
|       grub_printf ("0x%03x:  %4d x %4d x %2d  %s", | ||||
|                    mode, | ||||
|                    mode_info_tmp.x_resolution, | ||||
|                    mode_info_tmp.y_resolution, | ||||
|                    mode_info_tmp.bits_per_pixel, | ||||
|                    memory_model); | ||||
| 
 | ||||
|       /* Show mask and position details for direct color modes.  */ | ||||
|       if (mode_info_tmp.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR) | ||||
|         grub_printf (", mask: %d/%d/%d/%d  pos: %d/%d/%d/%d", | ||||
|                      mode_info_tmp.red_mask_size, | ||||
|                      mode_info_tmp.green_mask_size, | ||||
|                      mode_info_tmp.blue_mask_size, | ||||
|                      mode_info_tmp.rsvd_mask_size, | ||||
|                      mode_info_tmp.red_field_position, | ||||
|                      mode_info_tmp.green_field_position, | ||||
|                      mode_info_tmp.blue_field_position, | ||||
|                      mode_info_tmp.rsvd_field_position); | ||||
|       grub_printf ("\n"); | ||||
|     } | ||||
| 
 | ||||
|   grub_free (saved_video_mode_list); | ||||
| 
 | ||||
|   /* Check existence of vbe_mode environment variable.  */ | ||||
|   modevar = grub_env_get ("vbe_mode"); | ||||
| 
 | ||||
|   if (modevar != 0) | ||||
|     { | ||||
|       unsigned long value; | ||||
| 
 | ||||
|       value = grub_strtoul (modevar, 0, 0); | ||||
|       if (grub_errno == GRUB_ERR_NONE) | ||||
| 	use_mode = value; | ||||
|       else | ||||
| 	grub_errno = GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   grub_printf ("Configured VBE mode (vbe_mode) = 0x%03x\n", use_mode); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(vbeinfo) | ||||
| { | ||||
|   cmd = | ||||
|     grub_register_command ("vbeinfo", grub_cmd_vbeinfo, 0, | ||||
| 			   N_("List compatible VESA BIOS extension video modes.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(vbeinfo) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										179
									
								
								grub-core/commands/i386/pc/vbetest.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								grub-core/commands/i386/pc/vbetest.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,179 @@ | |||
| /* vbetest.c - command to test VESA BIOS Extension 2.0+ support.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/normal.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/machine/init.h> | ||||
| #include <grub/machine/vbe.h> | ||||
| #include <grub/video.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_vbetest (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		  int argc __attribute__ ((unused)), | ||||
| 		  char **args __attribute__ ((unused))) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   char *modevar; | ||||
|   struct grub_vbe_mode_info_block mode_info; | ||||
|   struct grub_vbe_info_block controller_info; | ||||
|   grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE; | ||||
|   grub_uint32_t old_mode; | ||||
|   grub_uint8_t *framebuffer = 0; | ||||
|   grub_uint32_t bytes_per_scan_line = 0; | ||||
|   unsigned char *ptr; | ||||
|   int i; | ||||
| 
 | ||||
|   grub_printf ("Probing for VESA BIOS Extension ... "); | ||||
| 
 | ||||
|   /* Check if VESA BIOS exists.  */ | ||||
|   err = grub_vbe_probe (&controller_info); | ||||
|   if (err != GRUB_ERR_NONE) | ||||
|     return err; | ||||
| 
 | ||||
|   grub_printf ("found!\n"); | ||||
| 
 | ||||
|   /* Dump out controller information.  */ | ||||
|   grub_printf ("VBE signature = %c%c%c%c\n", | ||||
| 	       controller_info.signature[0], | ||||
| 	       controller_info.signature[1], | ||||
| 	       controller_info.signature[2], | ||||
| 	       controller_info.signature[3]); | ||||
| 
 | ||||
|   grub_printf ("VBE version = %d.%d\n", | ||||
| 	       controller_info.version >> 8, | ||||
| 	       controller_info.version & 0xFF); | ||||
|   grub_printf ("OEM string ptr = %08x\n", | ||||
| 	       controller_info.oem_string_ptr); | ||||
|   grub_printf ("Total memory = %d\n", | ||||
| 	       controller_info.total_memory); | ||||
| 
 | ||||
|   err = grub_vbe_get_video_mode (&old_mode); | ||||
|   grub_printf ("Get video mode err = %04x\n", err); | ||||
| 
 | ||||
|   if (err == GRUB_ERR_NONE) | ||||
|     grub_printf ("Old video mode = %04x\n", old_mode); | ||||
|   else | ||||
|     grub_errno = GRUB_ERR_NONE; | ||||
| 
 | ||||
|   /* Check existence of vbe_mode environment variable.  */ | ||||
|   modevar = grub_env_get ("vbe_mode"); | ||||
|   if (modevar != 0) | ||||
|     { | ||||
|       unsigned long value; | ||||
| 
 | ||||
|       value = grub_strtoul (modevar, 0, 0); | ||||
|       if (grub_errno == GRUB_ERR_NONE) | ||||
| 	use_mode = value; | ||||
|       else | ||||
| 	grub_errno = GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   err = grub_vbe_get_video_mode_info (use_mode, &mode_info); | ||||
|   if (err != GRUB_ERR_NONE) | ||||
|     return err; | ||||
| 
 | ||||
|   /* Dump out details about the mode being tested.  */ | ||||
|   grub_printf ("mode: 0x%03x\n", | ||||
|                use_mode); | ||||
|   grub_printf ("width : %d\n", | ||||
|                mode_info.x_resolution); | ||||
|   grub_printf ("height: %d\n", | ||||
|                mode_info.y_resolution); | ||||
|   grub_printf ("memory model: %02x\n", | ||||
|                mode_info.memory_model); | ||||
|   grub_printf ("bytes/scanline: %d\n", | ||||
|                mode_info.bytes_per_scan_line); | ||||
|   grub_printf ("bytes/scanline (lin): %d\n", | ||||
|                mode_info.lin_bytes_per_scan_line); | ||||
|   grub_printf ("base address: %08x\n", | ||||
|                mode_info.phys_base_addr); | ||||
|   grub_printf ("red mask/pos: %d/%d\n", | ||||
|                mode_info.red_mask_size, | ||||
|                mode_info.red_field_position); | ||||
|   grub_printf ("green mask/pos: %d/%d\n", | ||||
|                mode_info.green_mask_size, | ||||
|                mode_info.green_field_position); | ||||
|   grub_printf ("blue mask/pos: %d/%d\n", | ||||
|                mode_info.blue_mask_size, | ||||
|                mode_info.blue_field_position); | ||||
| 
 | ||||
|   grub_printf ("Press any key to continue.\n"); | ||||
| 
 | ||||
|   grub_getkey (); | ||||
| 
 | ||||
|   /* Setup GFX mode.  */ | ||||
|   err = grub_vbe_set_video_mode (use_mode, &mode_info); | ||||
|   if (err != GRUB_ERR_NONE) | ||||
|     return err; | ||||
| 
 | ||||
|   /* Determine framebuffer address and how many bytes are in scan line.  */ | ||||
|   framebuffer = (grub_uint8_t *) mode_info.phys_base_addr; | ||||
|   ptr = framebuffer; | ||||
| 
 | ||||
|   if (controller_info.version >= 0x300) | ||||
|     { | ||||
|       bytes_per_scan_line = mode_info.lin_bytes_per_scan_line; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       bytes_per_scan_line = mode_info.bytes_per_scan_line; | ||||
|     } | ||||
| 
 | ||||
|   /* Draw some random data to screen.  */ | ||||
|   for (i = 0; i < 256 * 256; i++) | ||||
|     { | ||||
|       ptr[i] = i & 0x0F; | ||||
|     } | ||||
| 
 | ||||
|   /* Draw white line to screen.  */ | ||||
|   for (i = 0; i < 100; i++) | ||||
|     { | ||||
|       ptr[mode_info.bytes_per_scan_line * 50 + i] = 0x0F; | ||||
|     } | ||||
| 
 | ||||
|   /* Draw another white line to screen.  */ | ||||
|   grub_memset (ptr + bytes_per_scan_line * 51, 0x0f, bytes_per_scan_line); | ||||
| 
 | ||||
|   grub_getkey (); | ||||
| 
 | ||||
|   grub_video_restore (); | ||||
| 
 | ||||
|   /* Restore old video mode.  */ | ||||
|   grub_vbe_set_video_mode (old_mode, 0); | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(vbetest) | ||||
| { | ||||
|   cmd = grub_register_command ("vbetest", grub_cmd_vbetest, | ||||
| 			       0, N_("Test VESA BIOS Extension 2.0+ support.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(vbetest) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										49
									
								
								grub-core/commands/ieee1275/suspend.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								grub-core/commands/ieee1275/suspend.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| /* suspend.c - command to suspend GRUB and return to Open Firmware  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/ieee1275/ieee1275.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_suspend (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		  int argc __attribute__ ((unused)), | ||||
| 		  char **args __attribute__ ((unused))) | ||||
| { | ||||
|   grub_printf ("Run 'go' to resume GRUB.\n"); | ||||
|   grub_ieee1275_enter (); | ||||
|   grub_cls (); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(ieee1275_suspend) | ||||
| { | ||||
|   cmd = grub_register_command ("suspend", grub_cmd_suspend, | ||||
| 			       0, N_("Return to Open Firmware prompt.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(ieee1275_suspend) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										150
									
								
								grub-core/commands/iorw.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								grub-core/commands/iorw.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,150 @@ | |||
| /* memrw.c - command to read / write physical memory  */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/cpu/io.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; | ||||
| static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {0, 'v', 0, N_("Save read value into variable VARNAME."), | ||||
|      N_("VARNAME"), ARG_TYPE_STRING}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) | ||||
| { | ||||
|   grub_target_addr_t addr; | ||||
|   grub_uint32_t value = 0; | ||||
|   char buf[sizeof ("XXXXXXXX")]; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); | ||||
| 
 | ||||
|   addr = grub_strtoul (argv[0], 0, 0); | ||||
|   switch (cmd->cmd->name[sizeof ("in") - 1]) | ||||
|     { | ||||
|     case 'l': | ||||
|       value = grub_inl (addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 'w': | ||||
|       value = grub_inw (addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 'b': | ||||
|       value = grub_inb (addr); | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   if (cmd->state[0].set) | ||||
|     { | ||||
|       grub_snprintf (buf, sizeof (buf), "%x", value); | ||||
|       grub_env_set (cmd->state[0].arg, buf); | ||||
|     } | ||||
|   else | ||||
|     grub_printf ("0x%x\n", value); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_write (grub_command_t cmd, int argc, char **argv) | ||||
| { | ||||
|   grub_target_addr_t addr; | ||||
|   grub_uint32_t value; | ||||
|   grub_uint32_t mask = 0xffffffff; | ||||
| 
 | ||||
|   if (argc != 2 && argc != 3) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); | ||||
| 
 | ||||
|   addr = grub_strtoul (argv[0], 0, 0); | ||||
|   value = grub_strtoul (argv[1], 0, 0); | ||||
|   if (argc == 3) | ||||
|     mask = grub_strtoul (argv[2], 0, 0); | ||||
|   value &= mask; | ||||
|   switch (cmd->name[sizeof ("out") - 1]) | ||||
|     { | ||||
|     case 'l': | ||||
|       if (mask != 0xffffffff) | ||||
| 	grub_outl ((grub_inl (addr) & ~mask) | value, addr); | ||||
|       else | ||||
| 	grub_outl (value, addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 'w': | ||||
|       if ((mask & 0xffff) != 0xffff) | ||||
| 	grub_outw ((grub_inw (addr) & ~mask) | value, addr); | ||||
|       else | ||||
| 	grub_outw (value, addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 'b': | ||||
|       if ((mask & 0xff) != 0xff) | ||||
| 	grub_outb ((grub_inb (addr) & ~mask) | value, addr); | ||||
|       else | ||||
| 	grub_outb (value, addr); | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_INIT(memrw) | ||||
| { | ||||
|   cmd_read_byte = | ||||
|     grub_register_extcmd ("inb", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("PORT"), N_("Read byte from PORT."), options); | ||||
|   cmd_read_word = | ||||
|     grub_register_extcmd ("inw", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("PORT"), N_("Read word from PORT."), options); | ||||
|   cmd_read_dword = | ||||
|     grub_register_extcmd ("inl", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("PORT"), N_("Read dword from PORT."), options); | ||||
|   cmd_write_byte = | ||||
|     grub_register_command ("outb", grub_cmd_write, | ||||
| 			   N_("PORT VALUE [MASK]"), | ||||
| 			   N_("Write byte VALUE to PORT.")); | ||||
|   cmd_write_word = | ||||
|     grub_register_command ("outw", grub_cmd_write, | ||||
| 			   N_("PORT VALUE [MASK]"), | ||||
| 			   N_("Write word VALUE to PORT.")); | ||||
|   cmd_write_dword = | ||||
|     grub_register_command ("outl", grub_cmd_write, | ||||
| 			   N_("ADDR VALUE [MASK]"), | ||||
| 			   N_("Write dword VALUE to PORT.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(memrw) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd_read_byte); | ||||
|   grub_unregister_extcmd (cmd_read_word); | ||||
|   grub_unregister_extcmd (cmd_read_dword); | ||||
|   grub_unregister_command (cmd_write_byte); | ||||
|   grub_unregister_command (cmd_write_word); | ||||
|   grub_unregister_command (cmd_write_dword); | ||||
| } | ||||
							
								
								
									
										93
									
								
								grub-core/commands/keystatus.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								grub-core/commands/keystatus.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,93 @@ | |||
| /* keystatus.c - Command to check key modifier status.  */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"shift", 's', 0, N_("Check Shift key."), 0, 0}, | ||||
|     {"ctrl", 'c', 0, N_("Check Control key."), 0, 0}, | ||||
|     {"alt", 'a', 0, N_("Check Alt key."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| #define grub_cur_term_input	grub_term_get_current_input () | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_keystatus (grub_extcmd_t cmd, | ||||
| 		    int argc __attribute__ ((unused)), | ||||
| 		    char **args __attribute__ ((unused))) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   int expect_mods = 0; | ||||
|   int mods; | ||||
| 
 | ||||
|   if (state[0].set) | ||||
|     expect_mods |= GRUB_TERM_STATUS_SHIFT; | ||||
|   if (state[1].set) | ||||
|     expect_mods |= GRUB_TERM_STATUS_CTRL; | ||||
|   if (state[2].set) | ||||
|     expect_mods |= GRUB_TERM_STATUS_ALT; | ||||
| 
 | ||||
|   grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); | ||||
| 
 | ||||
|   /* Without arguments, just check whether getkeystatus is supported at
 | ||||
|      all.  */ | ||||
|   if (expect_mods == 0) | ||||
|     { | ||||
|       grub_term_input_t term; | ||||
|       int nterms = 0; | ||||
| 
 | ||||
|       FOR_ACTIVE_TERM_INPUTS (term) | ||||
| 	if (!term->getkeystatus) | ||||
| 	  return grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
| 	else | ||||
| 	  nterms++; | ||||
|       if (!nterms) | ||||
| 	return grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   mods = grub_getkeystatus (); | ||||
|   grub_dprintf ("keystatus", "mods: %d\n", mods); | ||||
|   if (mods >= 0 && (mods & expect_mods) != 0) | ||||
|     return 0; | ||||
|   else | ||||
|     return grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(keystatus) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("keystatus", grub_cmd_keystatus, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[--shift] [--ctrl] [--alt]"), | ||||
| 			      N_("Check key modifier status."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(keystatus) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										400
									
								
								grub-core/commands/loadenv.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								grub-core/commands/loadenv.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,400 @@ | |||
| /* loadenv.c - command to load/save environment variable.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/lib/envblk.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static grub_file_t | ||||
| open_envblk_file (char *filename) | ||||
| { | ||||
|   grub_file_t file; | ||||
| 
 | ||||
|   if (! filename) | ||||
|     { | ||||
|       char *prefix; | ||||
| 
 | ||||
|       prefix = grub_env_get ("prefix"); | ||||
|       if (prefix) | ||||
|         { | ||||
|           int len; | ||||
| 
 | ||||
|           len = grub_strlen (prefix); | ||||
|           filename = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG)); | ||||
|           if (! filename) | ||||
|             return 0; | ||||
| 
 | ||||
|           grub_strcpy (filename, prefix); | ||||
|           filename[len] = '/'; | ||||
|           grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG); | ||||
|           file = grub_file_open (filename); | ||||
|           grub_free (filename); | ||||
|           return file; | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           grub_error (GRUB_ERR_FILE_NOT_FOUND, "prefix is not found"); | ||||
|           return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   return grub_file_open (filename); | ||||
| } | ||||
| 
 | ||||
| static grub_envblk_t | ||||
| read_envblk_file (grub_file_t file) | ||||
| { | ||||
|   grub_off_t offset = 0; | ||||
|   char *buf; | ||||
|   grub_size_t size = grub_file_size (file); | ||||
|   grub_envblk_t envblk; | ||||
| 
 | ||||
|   buf = grub_malloc (size); | ||||
|   if (! buf) | ||||
|     return 0; | ||||
| 
 | ||||
|   while (size > 0) | ||||
|     { | ||||
|       grub_ssize_t ret; | ||||
| 
 | ||||
|       ret = grub_file_read (file, buf + offset, size); | ||||
|       if (ret <= 0) | ||||
|         { | ||||
|           if (grub_errno == GRUB_ERR_NONE) | ||||
|             grub_error (GRUB_ERR_FILE_READ_ERROR, "cannot read"); | ||||
|           grub_free (buf); | ||||
|           return 0; | ||||
|         } | ||||
| 
 | ||||
|       size -= ret; | ||||
|       offset += ret; | ||||
|     } | ||||
| 
 | ||||
|   envblk = grub_envblk_open (buf, offset); | ||||
|   if (! envblk) | ||||
|     { | ||||
|       grub_free (buf); | ||||
|       grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   return envblk; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_load_env (grub_extcmd_t cmd, | ||||
| 		   int argc __attribute__ ((unused)), | ||||
| 		   char **args __attribute__ ((unused))) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   grub_file_t file; | ||||
|   grub_envblk_t envblk; | ||||
| 
 | ||||
|   auto int set_var (const char *name, const char *value); | ||||
|   int set_var (const char *name, const char *value) | ||||
|   { | ||||
|     grub_env_set (name, value); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   file = open_envblk_file ((state[0].set) ? state[0].arg : 0); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   envblk = read_envblk_file (file); | ||||
|   if (! envblk) | ||||
|     goto fail; | ||||
| 
 | ||||
|   grub_envblk_iterate (envblk, set_var); | ||||
|   grub_envblk_close (envblk); | ||||
| 
 | ||||
|  fail: | ||||
|   grub_file_close (file); | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_list_env (grub_extcmd_t cmd, | ||||
| 		   int argc __attribute__ ((unused)), | ||||
| 		   char **args __attribute__ ((unused))) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   grub_file_t file; | ||||
|   grub_envblk_t envblk; | ||||
| 
 | ||||
|   /* Print all variables in current context.  */ | ||||
|   auto int print_var (const char *name, const char *value); | ||||
|   int print_var (const char *name, const char *value) | ||||
|     { | ||||
|       grub_printf ("%s=%s\n", name, value); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   file = open_envblk_file ((state[0].set) ? state[0].arg : 0); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   envblk = read_envblk_file (file); | ||||
|   if (! envblk) | ||||
|     goto fail; | ||||
| 
 | ||||
|   grub_envblk_iterate (envblk, print_var); | ||||
|   grub_envblk_close (envblk); | ||||
| 
 | ||||
|  fail: | ||||
|   grub_file_close (file); | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| /* Used to maintain a variable length of blocklists internally.  */ | ||||
| struct blocklist | ||||
| { | ||||
|   grub_disk_addr_t sector; | ||||
|   unsigned offset; | ||||
|   unsigned length; | ||||
|   struct blocklist *next; | ||||
| }; | ||||
| 
 | ||||
| static void | ||||
| free_blocklists (struct blocklist *p) | ||||
| { | ||||
|   struct blocklist *q; | ||||
| 
 | ||||
|   for (; p; p = q) | ||||
|     { | ||||
|       q = p->next; | ||||
|       grub_free (p); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, | ||||
|                   grub_file_t file) | ||||
| { | ||||
|   grub_size_t total_length; | ||||
|   grub_size_t index; | ||||
|   grub_disk_t disk; | ||||
|   grub_disk_addr_t part_start; | ||||
|   struct blocklist *p; | ||||
|   char *buf; | ||||
| 
 | ||||
|   /* Sanity checks.  */ | ||||
|   total_length = 0; | ||||
|   for (p = blocklists; p; p = p->next) | ||||
|     { | ||||
|       struct blocklist *q; | ||||
|       for (q = p->next; q; q = q->next) | ||||
|         { | ||||
|           /* Check if any pair of blocks overlap.  */ | ||||
|           if (p->sector == q->sector) | ||||
|             { | ||||
|               /* This might be actually valid, but it is unbelievable that
 | ||||
|                  any filesystem makes such a silly allocation.  */ | ||||
|               return grub_error (GRUB_ERR_BAD_FS, "malformed file"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|       total_length += p->length; | ||||
|     } | ||||
| 
 | ||||
|   if (total_length != grub_file_size (file)) | ||||
|     { | ||||
|       /* Maybe sparse, unallocated sectors. No way in GRUB.  */ | ||||
|       return grub_error (GRUB_ERR_BAD_FILE_TYPE, "sparse file not allowed"); | ||||
|     } | ||||
| 
 | ||||
|   /* One more sanity check. Re-read all sectors by blocklists, and compare
 | ||||
|      those with the data read via a file.  */ | ||||
|   disk = file->device->disk; | ||||
| 
 | ||||
|   part_start = grub_partition_get_start (disk->partition); | ||||
| 
 | ||||
|   buf = grub_envblk_buffer (envblk); | ||||
|   for (p = blocklists, index = 0; p; index += p->length, p = p->next) | ||||
|     { | ||||
|       char blockbuf[GRUB_DISK_SECTOR_SIZE]; | ||||
| 
 | ||||
|       if (grub_disk_read (disk, p->sector - part_start, | ||||
|                           p->offset, p->length, blockbuf)) | ||||
|         return grub_errno; | ||||
| 
 | ||||
|       if (grub_memcmp (buf + index, blockbuf, p->length) != 0) | ||||
| 	return grub_error (GRUB_ERR_FILE_READ_ERROR, "invalid blocklist"); | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, | ||||
|                   grub_file_t file) | ||||
| { | ||||
|   char *buf; | ||||
|   grub_disk_t disk; | ||||
|   grub_disk_addr_t part_start; | ||||
|   struct blocklist *p; | ||||
|   grub_size_t index; | ||||
| 
 | ||||
|   buf = grub_envblk_buffer (envblk); | ||||
|   disk = file->device->disk; | ||||
|   part_start = grub_partition_get_start (disk->partition); | ||||
| 
 | ||||
|   index = 0; | ||||
|   for (p = blocklists; p; index += p->length, p = p->next) | ||||
|     { | ||||
|       if (grub_disk_write (disk, p->sector - part_start, | ||||
|                            p->offset, p->length, buf + index)) | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   grub_file_t file; | ||||
|   grub_envblk_t envblk; | ||||
|   struct blocklist *head = 0; | ||||
|   struct blocklist *tail = 0; | ||||
| 
 | ||||
|   /* Store blocklists in a linked list.  */ | ||||
|   auto void NESTED_FUNC_ATTR read_hook (grub_disk_addr_t sector, | ||||
|                                         unsigned offset, | ||||
|                                         unsigned length); | ||||
|   void NESTED_FUNC_ATTR read_hook (grub_disk_addr_t sector, | ||||
|                                    unsigned offset, unsigned length) | ||||
|     { | ||||
|       struct blocklist *block; | ||||
| 
 | ||||
|       if (offset + length > GRUB_DISK_SECTOR_SIZE) | ||||
|         /* Seemingly a bug.  */ | ||||
|         return; | ||||
| 
 | ||||
|       block = grub_malloc (sizeof (*block)); | ||||
|       if (! block) | ||||
|         return; | ||||
| 
 | ||||
|       block->sector = sector; | ||||
|       block->offset = offset; | ||||
|       block->length = length; | ||||
| 
 | ||||
|       /* Slightly complicated, because the list should be FIFO.  */ | ||||
|       block->next = 0; | ||||
|       if (tail) | ||||
|         tail->next = block; | ||||
|       tail = block; | ||||
|       if (! head) | ||||
|         head = block; | ||||
|     } | ||||
| 
 | ||||
|   if (! argc) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified"); | ||||
| 
 | ||||
|   file = open_envblk_file ((state[0].set) ? state[0].arg : 0); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (! file->device->disk) | ||||
|     { | ||||
|       grub_file_close (file); | ||||
|       return grub_error (GRUB_ERR_BAD_DEVICE, "disk device required"); | ||||
|     } | ||||
| 
 | ||||
|   file->read_hook = read_hook; | ||||
|   envblk = read_envblk_file (file); | ||||
|   file->read_hook = 0; | ||||
|   if (! envblk) | ||||
|     goto fail; | ||||
| 
 | ||||
|   if (check_blocklists (envblk, head, file)) | ||||
|     goto fail; | ||||
| 
 | ||||
|   while (argc) | ||||
|     { | ||||
|       char *value; | ||||
| 
 | ||||
|       value = grub_env_get (args[0]); | ||||
|       if (value) | ||||
|         { | ||||
|           if (! grub_envblk_set (envblk, args[0], value)) | ||||
|             { | ||||
|               grub_error (GRUB_ERR_BAD_ARGUMENT, "environment block too small"); | ||||
|               goto fail; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|       argc--; | ||||
|       args++; | ||||
|     } | ||||
| 
 | ||||
|   write_blocklists (envblk, head, file); | ||||
| 
 | ||||
|  fail: | ||||
|   if (envblk) | ||||
|     grub_envblk_close (envblk); | ||||
|   free_blocklists (head); | ||||
|   grub_file_close (file); | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd_load, cmd_list, cmd_save; | ||||
| 
 | ||||
| GRUB_MOD_INIT(loadenv) | ||||
| { | ||||
|   cmd_load = | ||||
|     grub_register_extcmd ("load_env", grub_cmd_load_env, | ||||
| 			  GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("[-f FILE]"), | ||||
| 			  N_("Load variables from environment block file."), | ||||
| 			  options); | ||||
|   cmd_list = | ||||
|     grub_register_extcmd ("list_env", grub_cmd_list_env, | ||||
| 			  GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("[-f FILE]"), | ||||
| 			  N_("List variables from environment block file."), | ||||
| 			  options); | ||||
|   cmd_save = | ||||
|     grub_register_extcmd ("save_env", grub_cmd_save_env, | ||||
| 			  GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("[-f FILE] variable_name [...]"), | ||||
| 			  N_("Save variables to environment block file."), | ||||
| 			  options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(loadenv) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd_load); | ||||
|   grub_unregister_extcmd (cmd_list); | ||||
|   grub_unregister_extcmd (cmd_save); | ||||
| } | ||||
							
								
								
									
										276
									
								
								grub-core/commands/ls.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								grub-core/commands/ls.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,276 @@ | |||
| /* ls.c - command to list files and devices */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2003,2005,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/datetime.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"long", 'l', 0, N_("Show a long list with more detailed information."), 0, 0}, | ||||
|     {"human-readable", 'h', 0, N_("Print sizes in a human readable format."), 0, 0}, | ||||
|     {"all", 'a', 0, N_("List all files."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static const char grub_human_sizes[] = {' ', 'K', 'M', 'G', 'T'}; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ls_list_devices (int longlist) | ||||
| { | ||||
|   auto int grub_ls_print_devices (const char *name); | ||||
|   int grub_ls_print_devices (const char *name) | ||||
|     { | ||||
|       if (longlist) | ||||
| 	grub_normal_print_device_info (name); | ||||
|       else | ||||
| 	grub_printf ("(%s) ", name); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   grub_device_iterate (grub_ls_print_devices); | ||||
|   grub_xputs ("\n"); | ||||
|   grub_refresh (); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ls_list_files (char *dirname, int longlist, int all, int human) | ||||
| { | ||||
|   char *device_name; | ||||
|   grub_fs_t fs; | ||||
|   const char *path; | ||||
|   grub_device_t dev; | ||||
| 
 | ||||
|   auto int print_files (const char *filename, | ||||
| 			const struct grub_dirhook_info *info); | ||||
|   auto int print_files_long (const char *filename, | ||||
| 			     const struct grub_dirhook_info *info); | ||||
| 
 | ||||
|   int print_files (const char *filename, const struct grub_dirhook_info *info) | ||||
|     { | ||||
|       if (all || filename[0] != '.') | ||||
| 	grub_printf ("%s%s ", filename, info->dir ? "/" : ""); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   int print_files_long (const char *filename, | ||||
| 			const struct grub_dirhook_info *info) | ||||
|     { | ||||
|       if ((! all) && (filename[0] == '.')) | ||||
| 	return 0; | ||||
| 
 | ||||
|       if (! info->dir) | ||||
| 	{ | ||||
| 	  grub_file_t file; | ||||
| 	  char *pathname; | ||||
| 
 | ||||
| 	  if (dirname[grub_strlen (dirname) - 1] == '/') | ||||
| 	    pathname = grub_xasprintf ("%s%s", dirname, filename); | ||||
| 	  else | ||||
| 	    pathname = grub_xasprintf ("%s/%s", dirname, filename); | ||||
| 
 | ||||
| 	  if (!pathname) | ||||
| 	    return 1; | ||||
| 
 | ||||
| 	  /* XXX: For ext2fs symlinks are detected as files while they
 | ||||
| 	     should be reported as directories.  */ | ||||
| 	  file = grub_file_open (pathname); | ||||
| 	  if (! file) | ||||
| 	    { | ||||
| 	      grub_errno = 0; | ||||
| 	      grub_free (pathname); | ||||
| 	      return 0; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (! human) | ||||
| 	    grub_printf ("%-12llu", (unsigned long long) file->size); | ||||
| 	  else | ||||
| 	    { | ||||
| 	      grub_uint64_t fsize = file->size * 100ULL; | ||||
| 	      int fsz = file->size; | ||||
| 	      int units = 0; | ||||
| 	      char buf[20]; | ||||
| 
 | ||||
| 	      while (fsz / 1024) | ||||
| 		{ | ||||
| 		  fsize = (fsize + 512) / 1024; | ||||
| 		  fsz /= 1024; | ||||
| 		  units++; | ||||
| 		} | ||||
| 
 | ||||
| 	      if (units) | ||||
| 		{ | ||||
| 		  grub_uint32_t whole, fraction; | ||||
| 
 | ||||
| 		  whole = grub_divmod64 (fsize, 100, &fraction); | ||||
| 		  grub_snprintf (buf, sizeof (buf), | ||||
| 				 "%u.%02u%c", whole, fraction, | ||||
| 				 grub_human_sizes[units]); | ||||
| 		  grub_printf ("%-12s", buf); | ||||
| 		} | ||||
| 	      else | ||||
| 		grub_printf ("%-12llu", (unsigned long long) file->size); | ||||
| 
 | ||||
| 	    } | ||||
| 	  grub_file_close (file); | ||||
| 	  grub_free (pathname); | ||||
| 	} | ||||
|       else | ||||
| 	grub_printf ("%-12s", "DIR"); | ||||
| 
 | ||||
|       if (info->mtimeset) | ||||
| 	{ | ||||
| 	  struct grub_datetime datetime; | ||||
| 	  grub_unixtime2datetime (info->mtime, &datetime); | ||||
| 	  if (human) | ||||
| 	    grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ", | ||||
| 			 datetime.year, datetime.month, datetime.day, | ||||
| 			 datetime.hour, datetime.minute, | ||||
| 			 datetime.second, | ||||
| 			 grub_get_weekday_name (&datetime)); | ||||
| 	  else | ||||
| 	    grub_printf (" %04d%02d%02d%02d%02d%02d ", | ||||
| 			 datetime.year, datetime.month, | ||||
| 			 datetime.day, datetime.hour, | ||||
| 			 datetime.minute, datetime.second); | ||||
| 	} | ||||
|       grub_printf ("%s%s\n", filename, info->dir ? "/" : ""); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   device_name = grub_file_get_device_name (dirname); | ||||
|   dev = grub_device_open (device_name); | ||||
|   if (! dev) | ||||
|     goto fail; | ||||
| 
 | ||||
|   fs = grub_fs_probe (dev); | ||||
|   path = grub_strchr (dirname, ')'); | ||||
|   if (! path) | ||||
|     path = dirname; | ||||
|   else | ||||
|     path++; | ||||
| 
 | ||||
|   if (! path && ! device_name) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   if (! *path) | ||||
|     { | ||||
|       if (grub_errno == GRUB_ERR_UNKNOWN_FS) | ||||
| 	grub_errno = GRUB_ERR_NONE; | ||||
| 
 | ||||
|       grub_normal_print_device_info (device_name); | ||||
|     } | ||||
|   else if (fs) | ||||
|     { | ||||
|       if (longlist) | ||||
| 	(fs->dir) (dev, path, print_files_long); | ||||
|       else | ||||
| 	(fs->dir) (dev, path, print_files); | ||||
| 
 | ||||
|       if (grub_errno == GRUB_ERR_BAD_FILE_TYPE | ||||
| 	  && path[grub_strlen (path) - 1] != '/') | ||||
| 	{ | ||||
| 	  /* PATH might be a regular file.  */ | ||||
| 	  char *p; | ||||
| 	  grub_file_t file; | ||||
| 	  struct grub_dirhook_info info; | ||||
| 	  grub_errno = 0; | ||||
| 
 | ||||
| 	  file = grub_file_open (dirname); | ||||
| 	  if (! file) | ||||
| 	    goto fail; | ||||
| 
 | ||||
| 	  grub_file_close (file); | ||||
| 
 | ||||
| 	  p = grub_strrchr (dirname, '/') + 1; | ||||
| 	  dirname = grub_strndup (dirname, p - dirname); | ||||
| 	  if (! dirname) | ||||
| 	    goto fail; | ||||
| 
 | ||||
| 	  all = 1; | ||||
| 	  grub_memset (&info, 0, sizeof (info)); | ||||
| 	  if (longlist) | ||||
| 	    print_files_long (p, &info); | ||||
| 	  else | ||||
| 	    print_files (p, &info); | ||||
| 
 | ||||
| 	  grub_free (dirname); | ||||
| 	} | ||||
| 
 | ||||
|       if (grub_errno == GRUB_ERR_NONE) | ||||
| 	grub_xputs ("\n"); | ||||
| 
 | ||||
|       grub_refresh (); | ||||
|     } | ||||
| 
 | ||||
|  fail: | ||||
|   if (dev) | ||||
|     grub_device_close (dev); | ||||
| 
 | ||||
|   grub_free (device_name); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_ls (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     grub_ls_list_devices (state[0].set); | ||||
|   else | ||||
|     grub_ls_list_files (args[0], state[0].set, state[2].set, | ||||
| 			state[1].set); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(ls) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("ls", grub_cmd_ls, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[-l|-h|-a] [FILE]"), | ||||
| 			      N_("List devices and files."), options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(ls) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										57
									
								
								grub-core/commands/lsmmap.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								grub-core/commands/lsmmap.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,57 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #ifndef GRUB_MACHINE_EMU | ||||
| #include <grub/machine/memory.h> | ||||
| #endif | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		 int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) | ||||
| 
 | ||||
| { | ||||
|   auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); | ||||
|   int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) | ||||
|     { | ||||
|       grub_printf ("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n", | ||||
| 		   (long long) addr, (long long) size, type); | ||||
|       return 0; | ||||
|     } | ||||
| #ifndef GRUB_MACHINE_EMU | ||||
|   grub_machine_mmap_iterate (hook); | ||||
| #endif | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(lsmmap) | ||||
| { | ||||
|   cmd = grub_register_command ("lsmmap", grub_cmd_lsmmap, | ||||
| 			       0, N_("List memory map provided by firmware.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(lsmmap) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										234
									
								
								grub-core/commands/lspci.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								grub-core/commands/lspci.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,234 @@ | |||
| /* lspci.c - List PCI devices.  */ | ||||
| /*
 | ||||
|  *  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/pci.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| struct grub_pci_classname | ||||
| { | ||||
|   int class; | ||||
|   int subclass; | ||||
|   char *desc; | ||||
| }; | ||||
| 
 | ||||
| static const struct grub_pci_classname grub_pci_classes[] = | ||||
|   { | ||||
|     { 0, 0, "" }, | ||||
|     { 1, 0, "SCSI Controller" }, | ||||
|     { 1, 1, "IDE Controller" }, | ||||
|     { 1, 2, "Floppy Controller" }, | ||||
|     { 1, 3, "IPI Controller" }, | ||||
|     { 1, 4, "RAID Controller" }, | ||||
|     { 1, 6, "SATA Controller" }, | ||||
|     { 1, 0x80, "Mass storage Controller" }, | ||||
|     { 2, 0, "Ethernet Controller" }, | ||||
|     { 2, 1, "Token Ring Controller" }, | ||||
|     { 2, 2, "FDDI Controller" }, | ||||
|     { 2, 3, "ATM Controller" }, | ||||
|     { 2, 4, "ISDN Controller" }, | ||||
|     { 2, 0x80, "Network controller" }, | ||||
|     { 3, 0, "VGA Controller" }, | ||||
|     { 3, 1, "XGA Controller" }, | ||||
|     { 3, 2, "3D Controller" }, | ||||
|     { 3, 0x80, "Display Controller" }, | ||||
|     { 4, 0, "Multimedia Video Device" }, | ||||
|     { 4, 1, "Multimedia Audio Device" }, | ||||
|     { 4, 2, "Multimedia Telephony Device" }, | ||||
|     { 4, 0x80, "Multimedia device" }, | ||||
|     { 5, 0, "RAM Controller" }, | ||||
|     { 5, 1, "Flash Memory Controller" }, | ||||
|     { 5, 0x80, "Memory Controller" }, | ||||
|     { 6, 0, "Host Bridge" }, | ||||
|     { 6, 1, "ISA Bridge" }, | ||||
|     { 6, 2, "EISA Bride" }, | ||||
|     { 6, 3, "MCA Bridge" }, | ||||
|     { 6, 4, "PCI-PCI Bridge" }, | ||||
|     { 6, 5, "PCMCIA Bridge" }, | ||||
|     { 6, 6, "NuBus Bridge" }, | ||||
|     { 6, 7, "CardBus Bridge" }, | ||||
|     { 6, 8, "Raceway Bridge" }, | ||||
|     { 6, 0x80, "Unknown Bridge" }, | ||||
|     { 7, 0x80, "Communication controller" }, | ||||
|     { 8, 0x80, "System hardware" }, | ||||
|     { 9, 0, "Keyboard Controller" }, | ||||
|     { 9, 1, "Digitizer" }, | ||||
|     { 9, 2, "Mouse Controller" }, | ||||
|     { 9, 3, "Scanner Controller" }, | ||||
|     { 9, 4, "Gameport Controller" }, | ||||
|     { 9, 0x80, "Unknown Input Device" }, | ||||
|     { 10, 0, "Generic Docking Station" }, | ||||
|     { 10, 0x80, "Unknown Docking Station" }, | ||||
|     { 11, 0, "80386 Processor" }, | ||||
|     { 11, 1, "80486 Processor" }, | ||||
|     { 11, 2, "Pentium Processor" }, | ||||
|     { 11, 0x10, "Alpha Processor" }, | ||||
|     { 11, 0x20, "PowerPC Processor" }, | ||||
|     { 11, 0x30, "MIPS Processor" }, | ||||
|     { 11, 0x40, "Co-Processor" }, | ||||
|     { 11, 0x80, "Unknown Processor" }, | ||||
|     { 12, 3, "USB Controller" }, | ||||
|     { 12, 0x80, "Serial Bus Controller" }, | ||||
|     { 13, 0x80, "Wireless Controller" }, | ||||
|     { 14, 0, "I2O" }, | ||||
|     { 15, 0, "IrDA Controller" }, | ||||
|     { 15, 1, "Consumer IR" }, | ||||
|     { 15, 0x10, "RF-Controller" }, | ||||
|     { 15, 0x80, "Satellite Communication Controller" }, | ||||
|     { 16, 0, "Network Decryption" }, | ||||
|     { 16, 1, "Entertainment Decryption" }, | ||||
|     { 16, 0x80, "Unknown Decryption Controller" }, | ||||
|     { 17, 0, "Digital IO Module" }, | ||||
|     { 17, 0x80, "Unknown Data Input System" }, | ||||
|     { 0, 0, 0 }, | ||||
|   }; | ||||
| 
 | ||||
| static const char * | ||||
| grub_pci_get_class (int class, int subclass) | ||||
| { | ||||
|   const struct grub_pci_classname *curr = grub_pci_classes; | ||||
| 
 | ||||
|   while (curr->desc) | ||||
|     { | ||||
|       if (curr->class == class && curr->subclass == subclass) | ||||
| 	return curr->desc; | ||||
|       curr++; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"iospace", 'i', 0, "show I/O spaces", 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static int iospace; | ||||
| 
 | ||||
| static int NESTED_FUNC_ATTR | ||||
| grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) | ||||
| { | ||||
|   grub_uint32_t class; | ||||
|   const char *sclass; | ||||
|   grub_pci_address_t addr; | ||||
|   int reg; | ||||
| 
 | ||||
|   grub_printf ("%02x:%02x.%x %04x:%04x", grub_pci_get_bus (dev), | ||||
| 	       grub_pci_get_device (dev), grub_pci_get_function (dev), | ||||
| 	       pciid & 0xFFFF, pciid >> 16); | ||||
|   addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); | ||||
|   class = grub_pci_read (addr); | ||||
| 
 | ||||
|   /* Lookup the class name, if there isn't a specific one,
 | ||||
|      retry with 0x80 to get the generic class name.  */ | ||||
|   sclass = grub_pci_get_class (class >> 24, (class >> 16) & 0xFF); | ||||
|   if (! sclass) | ||||
|     sclass = grub_pci_get_class (class >> 24, 0x80); | ||||
|   if (! sclass) | ||||
|     sclass = ""; | ||||
| 
 | ||||
|   grub_printf (" [%04x] %s", (class >> 16) & 0xffff, sclass); | ||||
| 
 | ||||
|   grub_uint8_t pi = (class >> 8) & 0xff; | ||||
|   if (pi) | ||||
|     grub_printf (" [PI %02x]", pi); | ||||
| 
 | ||||
|   grub_printf ("\n"); | ||||
| 
 | ||||
|   if (iospace) | ||||
|     { | ||||
|       reg = GRUB_PCI_REG_ADDRESSES; | ||||
|       while (reg < GRUB_PCI_REG_CIS_POINTER) | ||||
| 	{ | ||||
| 	  grub_uint64_t space; | ||||
| 	  addr = grub_pci_make_address (dev, reg); | ||||
| 	  space = grub_pci_read (addr); | ||||
| 
 | ||||
| 	  reg += sizeof (grub_uint32_t); | ||||
| 
 | ||||
| 	  if (space == 0) | ||||
| 	    continue; | ||||
| 	  | ||||
| 	  switch (space & GRUB_PCI_ADDR_SPACE_MASK) | ||||
| 	    { | ||||
| 	    case GRUB_PCI_ADDR_SPACE_IO: | ||||
| 	      grub_printf ("\tIO space %d at 0x%llx\n", | ||||
| 			   (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES) | ||||
| 			    / sizeof (grub_uint32_t)) - 1, | ||||
| 			   (unsigned long long) | ||||
| 			   (space & GRUB_PCI_ADDR_IO_MASK)); | ||||
| 	      break; | ||||
| 	    case GRUB_PCI_ADDR_SPACE_MEMORY: | ||||
| 	      if ((space & GRUB_PCI_ADDR_MEM_TYPE_MASK) | ||||
| 		  == GRUB_PCI_ADDR_MEM_TYPE_64) | ||||
| 		{ | ||||
| 		  addr = grub_pci_make_address (dev, reg); | ||||
| 		  space |= ((grub_uint64_t) grub_pci_read (addr)) << 32; | ||||
| 		  reg += sizeof (grub_uint32_t); | ||||
| 		  grub_printf ("\t64-bit memory space %d at 0x%016llx [%s]\n", | ||||
| 			       (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES) | ||||
| 				/ sizeof (grub_uint32_t)) - 2, | ||||
| 			       (unsigned long long) | ||||
| 			       (space & GRUB_PCI_ADDR_MEM_MASK), | ||||
| 			       space & GRUB_PCI_ADDR_MEM_PREFETCH | ||||
| 			       ? "prefetchable" : "non-prefetchable"); | ||||
| 		  | ||||
| 		} | ||||
| 	      else | ||||
| 		grub_printf ("\t32-bit memory space %d at 0x%016llx [%s]\n", | ||||
| 			     (unsigned) ((reg - GRUB_PCI_REG_ADDRESSES) | ||||
| 			      / sizeof (grub_uint32_t)) - 1, | ||||
| 			     (unsigned long long)  | ||||
| 			     (space & GRUB_PCI_ADDR_MEM_MASK), | ||||
| 			     space & GRUB_PCI_ADDR_MEM_PREFETCH | ||||
| 			     ? "prefetchable" : "non-prefetchable"); | ||||
| 	      break; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_lspci (grub_extcmd_t cmd, | ||||
| 		int argc __attribute__ ((unused)), | ||||
| 		char **args __attribute__ ((unused))) | ||||
| { | ||||
|   iospace = cmd->state[0].set; | ||||
|   grub_pci_iterate (grub_lspci_iter); | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(lspci) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("lspci", grub_cmd_lspci, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      "[-i]", N_("List PCI devices."), options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(lspci) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										149
									
								
								grub-core/commands/memrw.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								grub-core/commands/memrw.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | |||
| /* memrw.c - command to read / write physical memory  */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; | ||||
| static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {0, 'v', 0, N_("Save read value into variable VARNAME."), | ||||
|      "VARNAME", ARG_TYPE_STRING}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) | ||||
| { | ||||
|   grub_target_addr_t addr; | ||||
|   grub_uint32_t value = 0; | ||||
|   char buf[sizeof ("XXXXXXXX")]; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments"); | ||||
| 
 | ||||
|   addr = grub_strtoul (argv[0], 0, 0); | ||||
|   switch (cmd->cmd->name[sizeof ("read_") - 1]) | ||||
|     { | ||||
|     case 'd': | ||||
|       value = *((volatile grub_uint32_t *) addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 'w': | ||||
|       value = *((volatile grub_uint16_t *) addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 'b': | ||||
|       value = *((volatile grub_uint8_t *) addr); | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   if (cmd->state[0].set) | ||||
|     { | ||||
|       grub_snprintf (buf, sizeof (buf), "%x", value); | ||||
|       grub_env_set (cmd->state[0].arg, buf); | ||||
|     } | ||||
|   else | ||||
|     grub_printf ("0x%x\n", value); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_write (grub_command_t cmd, int argc, char **argv) | ||||
| { | ||||
|   grub_target_addr_t addr; | ||||
|   grub_uint32_t value; | ||||
|   grub_uint32_t mask = 0xffffffff; | ||||
| 
 | ||||
|   if (argc != 2 && argc != 3) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments"); | ||||
| 
 | ||||
|   addr = grub_strtoul (argv[0], 0, 0); | ||||
|   value = grub_strtoul (argv[1], 0, 0); | ||||
|   if (argc == 3) | ||||
|     mask = grub_strtoul (argv[2], 0, 0); | ||||
|   value &= mask; | ||||
|   switch (cmd->name[sizeof ("write_") - 1]) | ||||
|     { | ||||
|     case 'd': | ||||
|       if (mask != 0xffffffff) | ||||
| 	*((volatile grub_uint32_t *) addr) | ||||
| 	  = (*((volatile grub_uint32_t *) addr) & ~mask) | value; | ||||
|       else | ||||
| 	*((volatile grub_uint32_t *) addr) = value; | ||||
|       break; | ||||
| 
 | ||||
|     case 'w': | ||||
|       if ((mask & 0xffff) != 0xffff) | ||||
| 	*((volatile grub_uint16_t *) addr) | ||||
| 	  = (*((volatile grub_uint16_t *) addr) & ~mask) | value; | ||||
|       else | ||||
| 	*((volatile grub_uint16_t *) addr) = value; | ||||
|       break; | ||||
| 
 | ||||
|     case 'b': | ||||
|       if ((mask & 0xff) != 0xff) | ||||
| 	*((volatile grub_uint8_t *) addr) | ||||
| 	  = (*((volatile grub_uint8_t *) addr) & ~mask) | value; | ||||
|       else | ||||
| 	*((volatile grub_uint8_t *) addr) = value; | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_INIT(memrw) | ||||
| { | ||||
|   cmd_read_byte = | ||||
|     grub_register_extcmd ("read_byte", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("ADDR"), N_("Read byte from ADDR."), options); | ||||
|   cmd_read_word = | ||||
|     grub_register_extcmd ("read_word", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("ADDR"), N_("Read word from ADDR."), options); | ||||
|   cmd_read_dword = | ||||
|     grub_register_extcmd ("read_dword", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("ADDR"), N_("Read dword from ADDR."), options); | ||||
|   cmd_write_byte = | ||||
|     grub_register_command ("write_byte", grub_cmd_write, | ||||
| 			   N_("ADDR VALUE [MASK]"), N_("Write byte VALUE to ADDR.")); | ||||
|   cmd_write_word = | ||||
|     grub_register_command ("write_word", grub_cmd_write, | ||||
| 			   N_("ADDR VALUE [MASK]"), N_("Write word VALUE to ADDR.")); | ||||
|   cmd_write_dword = | ||||
|     grub_register_command ("write_dword", grub_cmd_write, | ||||
| 			   N_("ADDR VALUE [MASK]"), N_("Write dword VALUE to ADDR.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(memrw) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd_read_byte); | ||||
|   grub_unregister_extcmd (cmd_read_word); | ||||
|   grub_unregister_extcmd (cmd_read_dword); | ||||
|   grub_unregister_command (cmd_write_byte); | ||||
|   grub_unregister_command (cmd_write_word); | ||||
|   grub_unregister_command (cmd_write_dword); | ||||
| } | ||||
							
								
								
									
										372
									
								
								grub-core/commands/minicmd.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								grub-core/commands/minicmd.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,372 @@ | |||
| /* minicmd.c - commands for the rescue mode */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2003,2005,2006,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/loader.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| /* cat FILE */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_cat (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		   int argc, char *argv[]) | ||||
| { | ||||
|   grub_file_t file; | ||||
|   char buf[GRUB_DISK_SECTOR_SIZE]; | ||||
|   grub_ssize_t size; | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); | ||||
| 
 | ||||
|   file = grub_file_open (argv[0]); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   while ((size = grub_file_read (file, buf, sizeof (buf))) > 0) | ||||
|     { | ||||
|       int i; | ||||
| 
 | ||||
|       for (i = 0; i < size; i++) | ||||
| 	{ | ||||
| 	  unsigned char c = buf[i]; | ||||
| 
 | ||||
| 	  if ((grub_isprint (c) || grub_isspace (c)) && c != '\r') | ||||
| 	    grub_printf ("%c", c); | ||||
| 	  else | ||||
| 	    { | ||||
| 	      grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); | ||||
| 	      grub_printf ("<%x>", (int) c); | ||||
| 	      grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   grub_xputs ("\n"); | ||||
|   grub_refresh (); | ||||
|   grub_file_close (file); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* help */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_help (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		    int argc __attribute__ ((unused)), | ||||
| 		    char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   grub_command_t p; | ||||
| 
 | ||||
|   for (p = grub_command_list; p; p = p->next) | ||||
|     grub_printf ("%s (%d%c)\t%s\n", p->name, | ||||
| 		 p->prio & GRUB_PRIO_LIST_PRIO_MASK, | ||||
| 		 (p->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) ? '+' : '-', | ||||
| 		 p->description); | ||||
| 
 | ||||
|   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 | ||||
| 
 | ||||
| /* root [DEVICE] */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_root (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		    int argc, char *argv[]) | ||||
| { | ||||
|   grub_device_t dev; | ||||
|   grub_fs_t fs; | ||||
| 
 | ||||
|   if (argc > 0) | ||||
|     { | ||||
|       char *device_name = grub_file_get_device_name (argv[0]); | ||||
|       if (! device_name) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       grub_env_set ("root", device_name); | ||||
|       grub_free (device_name); | ||||
|     } | ||||
| 
 | ||||
|   dev = grub_device_open (0); | ||||
|   if (! dev) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   fs = grub_fs_probe (dev); | ||||
|   if (grub_errno == GRUB_ERR_UNKNOWN_FS) | ||||
|     grub_errno = GRUB_ERR_NONE; | ||||
| 
 | ||||
|   grub_printf ("(%s): Filesystem is %s.\n", | ||||
| 	       grub_env_get ("root"), fs ? fs->name : "unknown"); | ||||
| 
 | ||||
|   grub_device_close (dev); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| static void | ||||
| grub_rescue_cmd_testload (int argc, char *argv[]) | ||||
| { | ||||
|   grub_file_t file; | ||||
|   char *buf; | ||||
|   grub_ssize_t size; | ||||
|   grub_ssize_t pos; | ||||
|   auto void read_func (unsigned long sector, unsigned offset, unsigned len); | ||||
| 
 | ||||
|   void read_func (unsigned long sector __attribute__ ((unused)), | ||||
| 		  unsigned offset __attribute__ ((unused)), | ||||
| 		  unsigned len __attribute__ ((unused))) | ||||
|     { | ||||
|       grub_putchar ('.'); | ||||
|       grub_refresh (); | ||||
|     } | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   file = grub_file_open (argv[0]); | ||||
|   if (! file) | ||||
|     return; | ||||
| 
 | ||||
|   size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1); | ||||
|   if (size == 0) | ||||
|     { | ||||
|       grub_file_close (file); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   buf = grub_malloc (size); | ||||
|   if (! buf) | ||||
|     goto fail; | ||||
| 
 | ||||
|   grub_printf ("Reading %s sequentially", argv[0]); | ||||
|   file->read_hook = read_func; | ||||
|   if (grub_file_read (file, buf, size) != size) | ||||
|     goto fail; | ||||
|   grub_printf (" Done.\n"); | ||||
| 
 | ||||
|   /* Read sequentially again.  */ | ||||
|   grub_printf ("Reading %s sequentially again", argv[0]); | ||||
|   if (grub_file_seek (file, 0) < 0) | ||||
|     goto fail; | ||||
| 
 | ||||
|   for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE) | ||||
|     { | ||||
|       char sector[GRUB_DISK_SECTOR_SIZE]; | ||||
| 
 | ||||
|       if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE) | ||||
| 	  != GRUB_DISK_SECTOR_SIZE) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0) | ||||
| 	{ | ||||
| 	  grub_printf ("\nDiffers in %d\n", pos); | ||||
| 	  goto fail; | ||||
| 	} | ||||
|     } | ||||
|   grub_printf (" Done.\n"); | ||||
| 
 | ||||
|   /* Read backwards and compare.  */ | ||||
|   grub_printf ("Reading %s backwards", argv[0]); | ||||
|   pos = size; | ||||
|   while (pos > 0) | ||||
|     { | ||||
|       char sector[GRUB_DISK_SECTOR_SIZE]; | ||||
| 
 | ||||
|       pos -= GRUB_DISK_SECTOR_SIZE; | ||||
| 
 | ||||
|       if (grub_file_seek (file, pos) < 0) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE) | ||||
| 	  != GRUB_DISK_SECTOR_SIZE) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0) | ||||
| 	{ | ||||
| 	  int i; | ||||
| 
 | ||||
| 	  grub_printf ("\nDiffers in %d\n", pos); | ||||
| 
 | ||||
| 	  for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++) | ||||
| 	    grub_putchar (buf[pos + i]); | ||||
| 
 | ||||
| 	  if (i) | ||||
| 	    grub_refresh (); | ||||
| 
 | ||||
| 	  goto fail; | ||||
| 	} | ||||
|     } | ||||
|   grub_printf (" Done.\n"); | ||||
| 
 | ||||
|  fail: | ||||
| 
 | ||||
|   grub_file_close (file); | ||||
|   grub_free (buf); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* dump ADDRESS [SIZE] */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		    int argc, char *argv[]) | ||||
| { | ||||
|   grub_uint8_t *addr; | ||||
|   grub_size_t size = 4; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no address specified"); | ||||
| 
 | ||||
|   addr = (grub_uint8_t *) grub_strtoul (argv[0], 0, 0); | ||||
|   if (grub_errno) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (argc > 1) | ||||
|     size = (grub_size_t) grub_strtoul (argv[1], 0, 0); | ||||
| 
 | ||||
|   while (size--) | ||||
|     { | ||||
|       grub_printf ("%x%x ", *addr >> 4, *addr & 0xf); | ||||
|       addr++; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* rmmod MODULE */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		     int argc, char *argv[]) | ||||
| { | ||||
|   grub_dl_t mod; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); | ||||
| 
 | ||||
|   mod = grub_dl_get (argv[0]); | ||||
|   if (! mod) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such module"); | ||||
| 
 | ||||
|   if (grub_dl_unref (mod) <= 0) | ||||
|     grub_dl_unload (mod); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* lsmod */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		     int argc __attribute__ ((unused)), | ||||
| 		     char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   grub_dl_t mod; | ||||
| 
 | ||||
|   grub_printf ("Name\tRef Count\tDependencies\n"); | ||||
|   FOR_DL_MODULES (mod) | ||||
|   { | ||||
|     grub_dl_dep_t dep; | ||||
| 
 | ||||
|     grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count); | ||||
|     for (dep = mod->dep; dep; dep = dep->next) | ||||
|       { | ||||
| 	if (dep != mod->dep) | ||||
| 	  grub_xputs (","); | ||||
| 
 | ||||
| 	grub_printf ("%s", dep->mod->name); | ||||
|       } | ||||
|     grub_xputs ("\n"); | ||||
|   } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* exit */ | ||||
| static grub_err_t | ||||
| grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		    int argc __attribute__ ((unused)), | ||||
| 		    char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   grub_exit (); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_cat, cmd_help, cmd_root; | ||||
| static grub_command_t cmd_dump, cmd_rmmod, cmd_lsmod, cmd_exit; | ||||
| 
 | ||||
| GRUB_MOD_INIT(minicmd) | ||||
| { | ||||
|   cmd_cat = | ||||
|     grub_register_command ("cat", grub_mini_cmd_cat, | ||||
| 			   N_("FILE"), N_("Show the contents of a file.")); | ||||
|   cmd_help = | ||||
|     grub_register_command ("help", grub_mini_cmd_help, | ||||
| 			   0, N_("Show this message.")); | ||||
|   cmd_root = | ||||
|     grub_register_command ("root", grub_mini_cmd_root, | ||||
| 			   N_("[DEVICE]"), N_("Set the root device.")); | ||||
|   cmd_dump = | ||||
|     grub_register_command ("dump", grub_mini_cmd_dump, | ||||
| 			   N_("ADDR"), N_("Dump memory.")); | ||||
|   cmd_rmmod = | ||||
|     grub_register_command ("rmmod", grub_mini_cmd_rmmod, | ||||
| 			   N_("MODULE"), N_("Remove a module.")); | ||||
|   cmd_lsmod = | ||||
|     grub_register_command ("lsmod", grub_mini_cmd_lsmod, | ||||
| 			   0, N_("Show loaded modules.")); | ||||
|   cmd_exit = | ||||
|     grub_register_command ("exit", grub_mini_cmd_exit, | ||||
| 			   0, N_("Exit from GRUB.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(minicmd) | ||||
| { | ||||
|   grub_unregister_command (cmd_cat); | ||||
|   grub_unregister_command (cmd_help); | ||||
|   grub_unregister_command (cmd_root); | ||||
|   grub_unregister_command (cmd_dump); | ||||
|   grub_unregister_command (cmd_rmmod); | ||||
|   grub_unregister_command (cmd_lsmod); | ||||
|   grub_unregister_command (cmd_exit); | ||||
| } | ||||
							
								
								
									
										92
									
								
								grub-core/commands/mips/yeeloong/lsspd.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								grub-core/commands/mips/yeeloong/lsspd.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/cs5536.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_lsspd (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		int argc __attribute__ ((unused)), | ||||
| 		char **args __attribute__ ((unused))) | ||||
| { | ||||
|   grub_pci_device_t dev; | ||||
|   grub_port_t smbbase; | ||||
|   int i; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   if (!grub_cs5536_find (&dev)) | ||||
|     { | ||||
|       grub_printf ("No CS5536 found\n"); | ||||
|       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)); | ||||
|    | ||||
|   err = grub_cs5536_init_smbus (dev, 0x7fff, &smbbase); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   grub_printf ("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); | ||||
|       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); | ||||
|       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_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); | ||||
| 	} | ||||
|       else | ||||
| 	grub_printf ("Memory type: Unknown.\n"); | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(lsspd) | ||||
| { | ||||
|   cmd = grub_register_command ("lsspd", grub_cmd_lsspd, 0, | ||||
| 			       "Print Memory information."); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(lsspd) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										296
									
								
								grub-core/commands/net.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								grub-core/commands/net.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,296 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/net.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/command.h> | ||||
| 
 | ||||
| struct grub_net_route *grub_net_routes = NULL; | ||||
| struct grub_net_network_level_interface *grub_net_network_level_interfaces = NULL; | ||||
| struct grub_net_card *grub_net_cards = NULL; | ||||
| struct grub_net_network_level_protocol *grub_net_network_level_protocols = NULL; | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_net_resolve_address (struct grub_net_network_level_protocol **prot, | ||||
| 			  char *name, | ||||
| 			  grub_net_network_level_address_t *addr) | ||||
| { | ||||
|   FOR_NET_NETWORK_LEVEL_PROTOCOLS (*prot) | ||||
|     { | ||||
|       grub_err_t err; | ||||
|       err = grub_net_resolve_address_in_protocol (*prot, name, addr); | ||||
|       if (err == GRUB_ERR_NET_BAD_ADDRESS) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  continue; | ||||
| 	} | ||||
|       if (err) | ||||
| 	return err; | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   return grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("Unrecognised address %s"), | ||||
| 		     name); | ||||
| } | ||||
| 
 | ||||
| grub_err_t | ||||
| grub_net_route_address (grub_net_network_level_address_t addr, | ||||
| 			grub_net_network_level_address_t *gateway, | ||||
| 			struct grub_net_network_level_interface **interf) | ||||
| { | ||||
|   struct grub_net_route *route; | ||||
|   int depth = 0; | ||||
|   int routecnt = 0; | ||||
|   struct grub_net_network_level_protocol *prot = NULL; | ||||
|   grub_net_network_level_address_t curtarget = addr; | ||||
| 
 | ||||
|   *gateway = addr; | ||||
| 
 | ||||
|   FOR_NET_ROUTES(route) | ||||
|     routecnt++; | ||||
| 
 | ||||
|   for (depth = 0; depth < routecnt + 2; depth++) | ||||
|     { | ||||
|       FOR_NET_ROUTES(route) | ||||
|       { | ||||
| 	if (depth && prot != route->prot) | ||||
| 	  continue; | ||||
| 	prot = route->prot; | ||||
| 	if (!route->prot->match_net (route->target, curtarget)) | ||||
| 	  continue; | ||||
| 
 | ||||
| 	if (route->is_gateway) | ||||
| 	  { | ||||
| 	    if (depth == 0) | ||||
| 	      *gateway = route->gw; | ||||
| 	    curtarget = route->gw; | ||||
| 	    break; | ||||
| 	  } | ||||
| 	*interf = route->interface; | ||||
| 	return GRUB_ERR_NONE; | ||||
|       } | ||||
|       if (route == NULL) | ||||
| 	return grub_error (GRUB_ERR_NET_NO_ROUTE, "destination unreachable"); | ||||
|     } | ||||
| 
 | ||||
|   return grub_error (GRUB_ERR_NET_ROUTE_LOOP, "route loop detected"); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_deladdr (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		  int argc, char **args) | ||||
| { | ||||
|   struct grub_net_network_level_interface *inter; | ||||
| 
 | ||||
|   if (argc != 4) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); | ||||
| 
 | ||||
|   FOR_NET_NETWORK_LEVEL_INTERFACES (inter) | ||||
|     if (grub_strcmp (inter->name, args[1])) | ||||
|       break; | ||||
|   if (inter == NULL) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("address not found")); | ||||
| 
 | ||||
|   inter->protocol->fini (inter); | ||||
|   grub_net_network_level_interface_unregister (inter); | ||||
|   grub_free (inter->name); | ||||
|   grub_free (inter); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE;   | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_addaddr (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		  int argc, char **args) | ||||
| { | ||||
|   struct grub_net_card *card; | ||||
|   struct grub_net_network_level_protocol *prot; | ||||
|   grub_err_t err; | ||||
|   grub_net_network_level_address_t addr; | ||||
|   struct grub_net_network_level_interface *inter; | ||||
| 
 | ||||
|   if (argc != 4) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("four arguments expected")); | ||||
|    | ||||
|   FOR_NET_CARDS (card) | ||||
|     if (grub_strcmp (card->name, args[1])) | ||||
|       break; | ||||
|   if (card == NULL) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found"));  | ||||
| 
 | ||||
|   FOR_NET_NETWORK_LEVEL_PROTOCOLS (prot) | ||||
|     if (grub_strcmp (prot->name, args[2])) | ||||
|       break; | ||||
| 
 | ||||
|   if (card == NULL) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("protocol not found"));  | ||||
| 
 | ||||
|   err = grub_net_resolve_address_in_protocol (prot, args[3], &addr); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   inter = grub_zalloc (sizeof (*inter)); | ||||
|   if (!inter) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   inter->name = grub_strdup (args[0]); | ||||
|   inter->protocol = prot; | ||||
|   grub_memcpy (&(inter->address), &addr, sizeof (inter->address)); | ||||
|   inter->card = card; | ||||
| 
 | ||||
|   err = prot->init (inter); | ||||
|   if (err) | ||||
|     { | ||||
|       grub_free (inter->name); | ||||
|       grub_free (inter); | ||||
|       return err; | ||||
|     } | ||||
|   grub_net_network_level_interface_register (inter); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_delroute (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		   int argc, char **args) | ||||
| { | ||||
|   struct grub_net_route *route; | ||||
|   struct grub_net_route **prev; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); | ||||
|    | ||||
|   for (prev = &grub_net_routes, route = *prev; route; prev = &((*prev)->next), | ||||
| 	 route = *prev) | ||||
|     if (grub_strcmp (route->name, args[0]) == 0) | ||||
|       { | ||||
| 	*prev = route->next; | ||||
| 	grub_free (route->name); | ||||
| 	grub_free (route); | ||||
|       } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_addroute (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		  int argc, char **args) | ||||
| { | ||||
|   struct grub_net_network_level_protocol *prot; | ||||
|   struct grub_net_route *route; | ||||
| 
 | ||||
|   if (argc < 3) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 		       N_("At least 3 arguments are expected")); | ||||
| 
 | ||||
|   route = grub_zalloc (sizeof (*route)); | ||||
|   if (!route) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   route->name = grub_strdup (args[0]); | ||||
|   if (!route->name) | ||||
|     { | ||||
|       grub_free (route); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   FOR_NET_NETWORK_LEVEL_PROTOCOLS(prot) | ||||
|   { | ||||
|     grub_err_t err; | ||||
|     err = prot->net_ntoa (args[1], &(route->target)); | ||||
|     if (err == GRUB_ERR_NET_BAD_ADDRESS) | ||||
|       { | ||||
| 	grub_errno = GRUB_ERR_NONE; | ||||
| 	continue; | ||||
|       } | ||||
|     if (err) | ||||
|       return err; | ||||
|     break; | ||||
|   } | ||||
|    | ||||
|   if (!prot) | ||||
|     { | ||||
|       grub_free (route->name); | ||||
|       grub_free (route); | ||||
|       return grub_error (GRUB_ERR_NET_BAD_ADDRESS, | ||||
| 			 N_("Unrecognised address %s"), args[1]); | ||||
|     } | ||||
| 
 | ||||
|   if (grub_strcmp (args[2], "gw") == 0 && argc >= 4) | ||||
|     { | ||||
|       grub_err_t err; | ||||
|       route->is_gateway = 1; | ||||
|       err = grub_net_resolve_address_in_protocol (prot, | ||||
| 						  args[3], &(route->gw)); | ||||
|       if (err) | ||||
| 	{ | ||||
| 	  grub_free (route->name); | ||||
| 	  grub_free (route); | ||||
| 	  return err; | ||||
| 	} | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       struct grub_net_network_level_interface *inter; | ||||
|       route->is_gateway = 0; | ||||
| 
 | ||||
|       FOR_NET_NETWORK_LEVEL_INTERFACES (inter) | ||||
| 	if (grub_strcmp (inter->name, args[2])) | ||||
| 	  break; | ||||
| 
 | ||||
|       if (!inter) | ||||
| 	{ | ||||
| 	  grub_free (route->name); | ||||
| 	  grub_free (route); | ||||
| 	  return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 			     N_("Unrecognised interface %s"), args[2]); | ||||
| 	} | ||||
|       route->interface = inter; | ||||
|     } | ||||
| 
 | ||||
|   grub_net_route_register (route); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; | ||||
| 
 | ||||
| GRUB_MOD_INIT(net) | ||||
| { | ||||
|   cmd_addaddr = grub_register_command ("net_add_addr", grub_cmd_addaddr, | ||||
| 				       "SHORTNAME CARD PROTOCOL ADDRESS", | ||||
| 				       N_("Add a network address.")); | ||||
|   cmd_deladdr = grub_register_command ("net_del_addr", grub_cmd_deladdr, | ||||
| 				       "SHORTNAME", | ||||
| 				       N_("Delete a network address.")); | ||||
|   cmd_addroute = grub_register_command ("net_add_route", grub_cmd_addroute, | ||||
| 					"SHORTNAME NET [INTERFACE| gw GATEWAY]", | ||||
| 					N_("Add a network route.")); | ||||
|   cmd_delroute = grub_register_command ("net_del_route", grub_cmd_delroute, | ||||
| 					"SHORTNAME", | ||||
| 					N_("Delete a network route.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(net) | ||||
| { | ||||
|   grub_unregister_command (cmd_addaddr); | ||||
|   grub_unregister_command (cmd_deladdr); | ||||
|   grub_unregister_command (cmd_addroute); | ||||
|   grub_unregister_command (cmd_delroute); | ||||
| } | ||||
							
								
								
									
										331
									
								
								grub-core/commands/parttool.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								grub-core/commands/parttool.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,331 @@ | |||
| /* parttool.c - common dispatcher and parser for partition operations */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  This program is free software; you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation; either version 2 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program; if not, write to the Free Software | ||||
|  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/parttool.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| 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."; | ||||
| 
 | ||||
| int | ||||
| grub_parttool_register(const char *part_name, | ||||
| 		       const grub_parttool_function_t func, | ||||
| 		       const struct grub_parttool_argdesc *args) | ||||
| { | ||||
|   struct grub_parttool *cur; | ||||
|   int nargs = 0; | ||||
| 
 | ||||
|   if (! parts) | ||||
|     grub_dl_ref (mymod); | ||||
| 
 | ||||
|   cur = (struct grub_parttool *) grub_malloc (sizeof (struct grub_parttool)); | ||||
|   cur->next = parts; | ||||
|   cur->name = grub_strdup (part_name); | ||||
|   cur->handle = curhandle++; | ||||
|   for (nargs = 0; args[nargs].name != 0; nargs++); | ||||
|   cur->nargs = nargs; | ||||
|   cur->args = (struct grub_parttool_argdesc *) | ||||
|     grub_malloc ((nargs + 1) * sizeof (struct grub_parttool_argdesc)); | ||||
|   grub_memcpy (cur->args, args, | ||||
| 	       (nargs + 1) * sizeof (struct grub_parttool_argdesc)); | ||||
| 
 | ||||
|   cur->func = func; | ||||
|   parts = cur; | ||||
|   return cur->handle; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_parttool_unregister (int handle) | ||||
| { | ||||
|   struct grub_parttool *prev = 0, *cur, *t; | ||||
|   for (cur = parts; cur; ) | ||||
|     if (cur->handle == handle) | ||||
|       { | ||||
| 	grub_free (cur->args); | ||||
| 	grub_free (cur->name); | ||||
| 	if (prev) | ||||
| 	  prev->next = cur->next; | ||||
| 	else | ||||
| 	  parts = cur->next; | ||||
| 	t = cur; | ||||
| 	cur = cur->next; | ||||
| 	grub_free (t); | ||||
|       } | ||||
|     else | ||||
|       { | ||||
| 	prev = cur; | ||||
| 	cur = cur->next; | ||||
|       } | ||||
|   if (! parts) | ||||
|     grub_dl_unref (mymod); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		   int argc, char **args) | ||||
| { | ||||
|   grub_device_t dev; | ||||
|   struct grub_parttool *cur, *ptool; | ||||
|   int *parsed; | ||||
|   int i, j; | ||||
|   grub_err_t err = GRUB_ERR_NONE; | ||||
| 
 | ||||
|   auto grub_err_t show_help (void); | ||||
|   grub_err_t show_help (void) | ||||
|   { | ||||
|     int found = 0; | ||||
|     for (cur = parts; cur; cur = cur->next) | ||||
|       if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0) | ||||
| 	{ | ||||
| 	  struct grub_parttool_argdesc *curarg; | ||||
| 	  found = 1; | ||||
| 	  for (curarg = cur->args; curarg->name; curarg++) | ||||
| 	    { | ||||
| 	      int spacing = 20; | ||||
| 
 | ||||
| 	      spacing -= grub_strlen (curarg->name); | ||||
| 	      grub_printf ("%s", curarg->name); | ||||
| 
 | ||||
| 	      switch (curarg->type) | ||||
| 		{ | ||||
| 		case GRUB_PARTTOOL_ARG_BOOL: | ||||
| 		  grub_printf ("+/-"); | ||||
| 		  spacing -= 3; | ||||
| 		  break; | ||||
| 
 | ||||
| 		case GRUB_PARTTOOL_ARG_VAL: | ||||
| 		  grub_printf ("=VAL"); | ||||
| 		  spacing -= 4; | ||||
| 		  break; | ||||
| 
 | ||||
| 		    case GRUB_PARTTOOL_ARG_END: | ||||
| 		      break; | ||||
| 		} | ||||
| 	      while (spacing-- > 0) | ||||
| 		grub_printf (" "); | ||||
| 	      grub_printf ("%s\n", curarg->desc); | ||||
| 	    } | ||||
| 	} | ||||
|     if (! found) | ||||
|       grub_printf ("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); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments"); | ||||
|     } | ||||
| 
 | ||||
|   if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')') | ||||
|     { | ||||
|       args[0][grub_strlen (args[0]) - 1] = 0; | ||||
|       dev = grub_device_open (args[0] + 1); | ||||
|       args[0][grub_strlen (args[0]) - 1] = ')'; | ||||
|     } | ||||
|   else | ||||
|     dev = grub_device_open (args[0]); | ||||
| 
 | ||||
|   if (! dev) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (! dev->disk) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk"); | ||||
|     } | ||||
| 
 | ||||
|   if (! dev->disk->partition) | ||||
|     { | ||||
|       grub_device_close (dev); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a partition"); | ||||
|     } | ||||
| 
 | ||||
|   /* Load modules. */ | ||||
|   if (! grub_no_autoload) | ||||
|   { | ||||
|     const char *prefix; | ||||
|     prefix = grub_env_get ("prefix"); | ||||
|     if (prefix) | ||||
|       { | ||||
| 	char *filename; | ||||
| 
 | ||||
| 	filename = grub_xasprintf ("%s/parttool.lst", prefix); | ||||
| 	if (filename) | ||||
| 	  { | ||||
| 	    grub_file_t file; | ||||
| 
 | ||||
| 	    file = grub_file_open (filename); | ||||
| 	    if (file) | ||||
| 	      { | ||||
| 		char *buf = 0; | ||||
| 		for (;; grub_free(buf)) | ||||
| 		  { | ||||
| 		    char *p, *name; | ||||
| 
 | ||||
| 		    buf = grub_file_getline (file); | ||||
| 
 | ||||
| 		    if (! buf) | ||||
| 		      break; | ||||
| 
 | ||||
| 		    name = buf; | ||||
| 
 | ||||
| 		    if (! grub_isgraph (name[0])) | ||||
| 		      continue; | ||||
| 
 | ||||
| 		    p = grub_strchr (name, ':'); | ||||
| 		    if (! p) | ||||
| 		      continue; | ||||
| 
 | ||||
| 		    *p = '\0'; | ||||
| 		    while (*++p == ' ') | ||||
| 		      ; | ||||
| 
 | ||||
| 		    if (! grub_isgraph (*p)) | ||||
| 		      continue; | ||||
| 
 | ||||
| 		    if (grub_strcmp (name, dev->disk->partition->partmap->name) | ||||
| 			!= 0) | ||||
| 		      continue; | ||||
| 
 | ||||
| 		    grub_dl_load (p); | ||||
| 		  } | ||||
| 
 | ||||
| 		grub_file_close (file); | ||||
| 	      } | ||||
| 
 | ||||
| 	    grub_free (filename); | ||||
| 	  } | ||||
|       } | ||||
|     /* Ignore errors.  */ | ||||
|     grub_errno = GRUB_ERR_NONE; | ||||
|   } | ||||
| 
 | ||||
|   if (argc == 1) | ||||
|     return show_help (); | ||||
| 
 | ||||
|   for (i = 1; i < argc; i++) | ||||
|     if (grub_strcmp (args[i], "help") == 0) | ||||
|       return show_help (); | ||||
| 
 | ||||
|   parsed = (int *) grub_zalloc (argc * sizeof (int)); | ||||
| 
 | ||||
|   for (i = 1; i < argc; i++) | ||||
|     if (! parsed[i]) | ||||
|       { | ||||
| 	struct grub_parttool_argdesc *curarg; | ||||
| 	struct grub_parttool_args *pargs; | ||||
| 	for (cur = parts; cur; cur = cur->next) | ||||
| 	  if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0) | ||||
| 	    { | ||||
| 	      for (curarg = cur->args; curarg->name; curarg++) | ||||
| 		if (grub_strncmp (curarg->name, args[i], | ||||
| 				  grub_strlen (curarg->name)) == 0 | ||||
| 		    && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL | ||||
| 			 && (args[i][grub_strlen (curarg->name)] == '+' | ||||
| 			     || args[i][grub_strlen (curarg->name)] == '-' | ||||
| 			     || args[i][grub_strlen (curarg->name)] == 0)) | ||||
| 			|| (curarg->type == GRUB_PARTTOOL_ARG_VAL | ||||
| 			    && args[i][grub_strlen (curarg->name)] == '='))) | ||||
| 
 | ||||
| 		  break; | ||||
| 	      if (curarg->name) | ||||
| 		break; | ||||
| 	    } | ||||
| 	if (! cur) | ||||
| 	  return grub_error (GRUB_ERR_BAD_ARGUMENT, "unrecognised argument %s", | ||||
| 			     args[i]); | ||||
| 	ptool = cur; | ||||
| 	pargs = (struct grub_parttool_args *) | ||||
| 	  grub_zalloc (ptool->nargs * sizeof (struct grub_parttool_args)); | ||||
| 	for (j = i; j < argc; j++) | ||||
| 	  if (! parsed[j]) | ||||
| 	    { | ||||
| 	      for (curarg = ptool->args; curarg->name; curarg++) | ||||
| 		if (grub_strncmp (curarg->name, args[i], | ||||
| 				   grub_strlen (curarg->name)) == 0 | ||||
| 		    && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL | ||||
| 			 && (args[j][grub_strlen (curarg->name)] == '+' | ||||
| 			     || args[j][grub_strlen (curarg->name)] == '-' | ||||
| 			     || args[j][grub_strlen (curarg->name)] == 0)) | ||||
| 			|| (curarg->type == GRUB_PARTTOOL_ARG_VAL | ||||
| 			    && args[j][grub_strlen (curarg->name)] == '='))) | ||||
| 		  { | ||||
| 		    parsed[j] = 1; | ||||
| 		    pargs[curarg - ptool->args].set = 1; | ||||
| 		    switch (curarg->type) | ||||
| 		      { | ||||
| 		      case GRUB_PARTTOOL_ARG_BOOL: | ||||
| 			pargs[curarg - ptool->args].bool | ||||
| 			  = (args[j][grub_strlen (curarg->name)] != '-'); | ||||
| 			break; | ||||
| 
 | ||||
| 		      case GRUB_PARTTOOL_ARG_VAL: | ||||
| 			pargs[curarg - ptool->args].str | ||||
| 			  = (args[j] + grub_strlen (curarg->name) + 1); | ||||
| 			break; | ||||
| 
 | ||||
| 		      case GRUB_PARTTOOL_ARG_END: | ||||
| 			break; | ||||
| 		      } | ||||
| 		  } | ||||
| 	    } | ||||
| 
 | ||||
| 	err = ptool->func (dev, pargs); | ||||
| 	grub_free (pargs); | ||||
| 	if (err) | ||||
| 	  break; | ||||
|       } | ||||
| 
 | ||||
|   grub_free (parsed); | ||||
|   grub_device_close (dev); | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(parttool) | ||||
| { | ||||
|   mymod = mod; | ||||
|   cmd = grub_register_command ("parttool", grub_cmd_parttool, | ||||
| 			       N_("PARTITION COMMANDS"), | ||||
| 			       helpmsg); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(parttool) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										86
									
								
								grub-core/commands/password.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								grub-core/commands/password.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| /*
 | ||||
|  *  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/auth.h> | ||||
| #include <grub/crypto.h> | ||||
| #include <grub/list.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_dl_t my_mod; | ||||
| 
 | ||||
| static grub_err_t | ||||
| check_password (const char *user, const char *entered, | ||||
| 		void *password) | ||||
| { | ||||
|   if (grub_crypto_memcmp (entered, password, GRUB_AUTH_MAX_PASSLEN) != 0) | ||||
|     return GRUB_ACCESS_DENIED; | ||||
| 
 | ||||
|   grub_auth_authenticate (user); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		   int argc, char **args) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   char *pass; | ||||
|   int copylen; | ||||
| 
 | ||||
|   if (argc != 2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments expected"); | ||||
| 
 | ||||
|   pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN); | ||||
|   if (!pass) | ||||
|     return grub_errno; | ||||
|   copylen = grub_strlen (args[1]); | ||||
|   if (copylen >= GRUB_AUTH_MAX_PASSLEN) | ||||
|     copylen = GRUB_AUTH_MAX_PASSLEN - 1; | ||||
|   grub_memcpy (pass, args[1], copylen); | ||||
| 
 | ||||
|   err = grub_auth_register_authentication (args[0], check_password, pass); | ||||
|   if (err) | ||||
|     { | ||||
|       grub_free (pass); | ||||
|       return err; | ||||
|     } | ||||
|   grub_dl_ref (my_mod); | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(password) | ||||
| { | ||||
|   my_mod = mod; | ||||
|   cmd = grub_register_command ("password", grub_cmd_password, | ||||
| 			       N_("USER PASSWORD"), | ||||
| 			       N_("Set user password (plaintext). " | ||||
| 			       "Unrecommended and insecure.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(password) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										197
									
								
								grub-core/commands/password_pbkdf2.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								grub-core/commands/password_pbkdf2.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,197 @@ | |||
| /*
 | ||||
|  *  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/auth.h> | ||||
| #include <grub/crypto.h> | ||||
| #include <grub/list.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/normal.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_dl_t my_mod; | ||||
| 
 | ||||
| struct pbkdf2_password | ||||
| { | ||||
|   grub_uint8_t *salt; | ||||
|   grub_size_t saltlen; | ||||
|   unsigned int c; | ||||
|   grub_uint8_t *expected; | ||||
|   grub_size_t buflen; | ||||
| }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| check_password (const char *user, const char *entered, void *pin) | ||||
| { | ||||
|   grub_uint8_t *buf; | ||||
|   struct pbkdf2_password *pass = pin; | ||||
|   gcry_err_code_t err; | ||||
| 
 | ||||
|   buf = grub_malloc (pass->buflen); | ||||
|   if (!buf) | ||||
|     return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); | ||||
| 
 | ||||
|   err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered, | ||||
| 			    grub_strlen (entered), | ||||
| 			    pass->salt, pass->saltlen, pass->c, | ||||
| 			    buf, pass->buflen); | ||||
|   if (err) | ||||
|     { | ||||
|       grub_free (buf); | ||||
|       return grub_crypto_gcry_error (err); | ||||
|     } | ||||
| 
 | ||||
|   if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0) | ||||
|     return GRUB_ACCESS_DENIED; | ||||
| 
 | ||||
|   grub_auth_authenticate (user); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static inline int | ||||
| hex2val (char hex) | ||||
| { | ||||
|   if ('0' <= hex && hex <= '9') | ||||
|     return hex - '0'; | ||||
|   if ('a' <= hex && hex <= 'f') | ||||
|     return hex - 'a' + 10; | ||||
|   if ('A' <= hex && hex <= 'F') | ||||
|     return hex - 'A' + 10; | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		   int argc, char **args) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   char *ptr, *ptr2; | ||||
|   grub_uint8_t *ptro; | ||||
|   struct pbkdf2_password *pass; | ||||
| 
 | ||||
|   if (argc != 2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); | ||||
| 
 | ||||
|   if (grub_memcmp (args[1], "grub.pbkdf2.sha512.", | ||||
| 		   sizeof ("grub.pbkdf2.sha512.") - 1) != 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); | ||||
| 
 | ||||
|   ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1; | ||||
| 
 | ||||
|   pass = grub_malloc (sizeof (*pass)); | ||||
|   if (!pass) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   pass->c = grub_strtoul (ptr, &ptr, 0); | ||||
|   if (*ptr != '.') | ||||
|     { | ||||
|       grub_free (pass); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); | ||||
|     } | ||||
|   ptr++; | ||||
| 
 | ||||
|   ptr2 = grub_strchr (ptr, '.'); | ||||
|   if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1) | ||||
|     { | ||||
|       grub_free (pass); | ||||
|       return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); | ||||
|     } | ||||
| 
 | ||||
|   pass->saltlen = (ptr2 - ptr) >> 1; | ||||
|   pass->buflen = grub_strlen (ptr2 + 1) >> 1; | ||||
|   ptro = pass->salt = grub_malloc (pass->saltlen); | ||||
|   if (!ptro) | ||||
|     { | ||||
|       grub_free (pass); | ||||
|       return grub_errno; | ||||
|     } | ||||
|   while (ptr < ptr2) | ||||
|     { | ||||
|       int hex1, hex2; | ||||
|       hex1 = hex2val (*ptr); | ||||
|       ptr++; | ||||
|       hex2 = hex2val (*ptr); | ||||
|       ptr++; | ||||
|       if (hex1 < 0 || hex2 < 0) | ||||
| 	{ | ||||
| 	  grub_free (pass->salt); | ||||
| 	  grub_free (pass); | ||||
| 	  return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 			     "Incorrect PBKDF2 password."); | ||||
| 	} | ||||
| 
 | ||||
|       *ptro = (hex1 << 4) | hex2; | ||||
|       ptro++; | ||||
|     } | ||||
| 
 | ||||
|   ptro = pass->expected = grub_malloc (pass->buflen); | ||||
|   if (!ptro) | ||||
|     { | ||||
|       grub_free (pass->salt); | ||||
|       grub_free (pass); | ||||
|       return grub_errno; | ||||
|     } | ||||
|   ptr = ptr2 + 1; | ||||
|   ptr2 += grub_strlen (ptr2);  | ||||
|   while (ptr < ptr2) | ||||
|     { | ||||
|       int hex1, hex2; | ||||
|       hex1 = hex2val (*ptr); | ||||
|       ptr++; | ||||
|       hex2 = hex2val (*ptr); | ||||
|       ptr++; | ||||
|       if (hex1 < 0 || hex2 < 0) | ||||
| 	{ | ||||
| 	  grub_free (pass->expected); | ||||
| 	  grub_free (pass->salt); | ||||
| 	  grub_free (pass); | ||||
| 	  return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 			     "Incorrect PBKDF2 password."); | ||||
| 	} | ||||
| 
 | ||||
|       *ptro = (hex1 << 4) | hex2; | ||||
|       ptro++; | ||||
|     } | ||||
| 
 | ||||
|   err = grub_auth_register_authentication (args[0], check_password, pass); | ||||
|   if (err) | ||||
|     { | ||||
|       grub_free (pass); | ||||
|       return err; | ||||
|     } | ||||
|   grub_dl_ref (my_mod); | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(password_pbkdf2) | ||||
| { | ||||
|   my_mod = mod; | ||||
|   cmd = grub_register_command ("password_pbkdf2", grub_cmd_password, | ||||
| 			       N_("USER PBKDF2_PASSWORD"), | ||||
| 			       N_("Set user password (PBKDF2). ")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(password_pbkdf2) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										161
									
								
								grub-core/commands/probe.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								grub-core/commands/probe.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,161 @@ | |||
| /*
 | ||||
|  *  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/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/net.h> | ||||
| #include <grub/fs.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"set",             's', GRUB_ARG_OPTION_OPTIONAL, | ||||
|      N_("Set a variable to return value."), "VAR", ARG_TYPE_STRING}, | ||||
|     {"driver",		'd', 0, N_("Determine driver."), 0, 0}, | ||||
|     {"partmap",		'p', 0, N_("Determine partition map type."), 0, 0}, | ||||
|     {"fs",		'f', 0, N_("Determine filesystem type."), 0, 0}, | ||||
|     {"fs-uuid",		'u', 0, N_("Determine filesystem UUID."), 0, 0}, | ||||
|     {"label",		'l', 0, N_("Determine filesystem label."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_probe (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   grub_device_t dev; | ||||
|   grub_fs_t fs; | ||||
|   char *ptr; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); | ||||
| 
 | ||||
|   ptr = args[0] + grub_strlen (args[0]) - 1; | ||||
|   if (args[0][0] == '(' && *ptr == ')') | ||||
|     { | ||||
|       *ptr = 0; | ||||
|       dev = grub_device_open (args[0] + 1); | ||||
|       *ptr = ')'; | ||||
|     } | ||||
|   else | ||||
|     dev = grub_device_open (args[0]); | ||||
|   if (! dev) | ||||
|     return grub_error (GRUB_ERR_BAD_DEVICE, "couldn't open device"); | ||||
| 
 | ||||
|   if (state[1].set) | ||||
|     { | ||||
|       const char *val = "none"; | ||||
|       if (dev->net) | ||||
| 	val = dev->net->name; | ||||
|       if (dev->disk) | ||||
| 	val = dev->disk->dev->name; | ||||
|       if (state[0].set) | ||||
| 	grub_env_set (state[0].arg, val); | ||||
|       else | ||||
| 	grub_printf ("%s", val); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   if (state[2].set) | ||||
|     { | ||||
|       const char *val = "none"; | ||||
|       if (dev->disk && dev->disk->partition) | ||||
| 	val = dev->disk->partition->partmap->name; | ||||
|       if (state[0].set) | ||||
| 	grub_env_set (state[0].arg, val); | ||||
|       else | ||||
| 	grub_printf ("%s", val); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   fs = grub_fs_probe (dev); | ||||
|   if (! fs) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_FS, "unrecognised fs"); | ||||
|   if (state[3].set) | ||||
|     { | ||||
|       if (state[0].set) | ||||
| 	grub_env_set (state[0].arg, fs->name); | ||||
|       else | ||||
| 	grub_printf ("%s", fs->name); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   if (state[4].set) | ||||
|     { | ||||
|       char *uuid; | ||||
|       if (! fs->uuid) | ||||
| 	return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 			   "uuid for this FS isn't supported yet"); | ||||
|       err = fs->uuid (dev, &uuid); | ||||
|       if (err) | ||||
| 	return err; | ||||
|       if (! uuid) | ||||
| 	return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 			   "uuid for this FS isn't supported yet"); | ||||
| 
 | ||||
|       if (state[0].set) | ||||
| 	grub_env_set (state[0].arg, uuid); | ||||
|       else | ||||
| 	grub_printf ("%s", uuid); | ||||
|       grub_free (uuid); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   if (state[5].set) | ||||
|     { | ||||
|       char *label; | ||||
|       if (! fs->label) | ||||
| 	return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 			   "label for this FS isn't supported yet"); | ||||
|       err = fs->label (dev, &label); | ||||
|       if (err) | ||||
| 	return err; | ||||
|       if (! label) | ||||
| 	return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 			   "uuid for this FS isn't supported yet"); | ||||
| 
 | ||||
|       if (state[0].set) | ||||
| 	grub_env_set (state[0].arg, label); | ||||
|       else | ||||
| 	grub_printf ("%s", label); | ||||
|       grub_free (label); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   return grub_error (GRUB_ERR_BAD_ARGUMENT, "unrecognised target"); | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT (probe) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("probe", grub_cmd_probe, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[DEVICE]"), | ||||
| 			      N_("Retrieve device info."), options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (probe) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										90
									
								
								grub-core/commands/read.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								grub-core/commands/read.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| /* read.c - Command to read variables from user.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static char * | ||||
| grub_getline (void) | ||||
| { | ||||
|   int i; | ||||
|   char *line; | ||||
|   char *tmp; | ||||
|   char c; | ||||
| 
 | ||||
|   i = 0; | ||||
|   line = grub_malloc (1 + i + sizeof('\0')); | ||||
|   if (! line) | ||||
|     return NULL; | ||||
| 
 | ||||
|   while (1) | ||||
|     { | ||||
|       c = grub_getkey (); | ||||
|       if ((c == '\n') || (c == '\r')) | ||||
| 	break; | ||||
| 
 | ||||
|       line[i] = c; | ||||
|       if (grub_isprint (c)) | ||||
| 	grub_printf ("%c", c); | ||||
|       i++; | ||||
|       tmp = grub_realloc (line, 1 + i + sizeof('\0')); | ||||
|       if (! tmp) | ||||
| 	{ | ||||
| 	  grub_free (line); | ||||
| 	  return NULL; | ||||
| 	} | ||||
|       line = tmp; | ||||
|     } | ||||
|   line[i] = '\0'; | ||||
| 
 | ||||
|   return line; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_read (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) | ||||
| { | ||||
|   char *line = grub_getline (); | ||||
|   if (! line) | ||||
|     return grub_errno; | ||||
|   if (argc > 0) | ||||
|     grub_env_set (args[0], line); | ||||
| 
 | ||||
|   grub_free (line); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(read) | ||||
| { | ||||
|   cmd = grub_register_command ("read", grub_cmd_read, | ||||
| 			       N_("[ENVVAR]"), | ||||
| 			       N_("Set variable with user input.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(read) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										45
									
								
								grub-core/commands/reboot.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								grub-core/commands/reboot.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| /* reboot.c - command to reboot the computer.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| 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; | ||||
|  | ||||
| GRUB_MOD_INIT(reboot) | ||||
| { | ||||
|   cmd = grub_register_command ("reboot", grub_cmd_reboot, | ||||
| 			       0, N_("Reboot the computer.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(reboot) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										80
									
								
								grub-core/commands/regexp.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								grub-core/commands/regexp.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | |||
| /* regexp.c -- The regexp command.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <regex.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		 int argc, char **args) | ||||
| { | ||||
|   int argn = 0; | ||||
|   int matches = 0; | ||||
|   regex_t regex; | ||||
|   int ret; | ||||
|   grub_size_t s; | ||||
|   char *comperr; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   if (argc != 2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected"); | ||||
| 
 | ||||
|   ret = regcomp (®ex, args[0], RE_SYNTAX_GNU_AWK); | ||||
|   if (ret) | ||||
|     goto fail; | ||||
| 
 | ||||
|   ret = regexec (®ex, args[1], 0, 0, 0); | ||||
|   if (!ret) | ||||
|     { | ||||
|       regfree (®ex); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|  fail: | ||||
|   s = regerror (ret, ®ex, 0, 0); | ||||
|   comperr = grub_malloc (s); | ||||
|   if (!comperr) | ||||
|     { | ||||
|       regfree (®ex); | ||||
|       return grub_errno; | ||||
|     } | ||||
|   regerror (ret, ®ex, comperr, s); | ||||
|   err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr); | ||||
|   regfree (®ex); | ||||
|   grub_free (comperr); | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(regexp) | ||||
| { | ||||
|   cmd = grub_register_command ("regexp", grub_cmd_regexp, | ||||
| 			       N_("REGEXP STRING"), | ||||
| 			       N_("Test if REGEXP matches STRING.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(regexp) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										174
									
								
								grub-core/commands/search.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								grub-core/commands/search.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,174 @@ | |||
| /* search.c - search devices based on a file or a filesystem label */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/search.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| void | ||||
| FUNC_NAME (const char *key, const char *var, int no_floppy) | ||||
| { | ||||
|   int count = 0; | ||||
|   grub_fs_autoload_hook_t saved_autoload; | ||||
| 
 | ||||
|   auto int iterate_device (const char *name); | ||||
|   int iterate_device (const char *name) | ||||
|   { | ||||
|     int found = 0; | ||||
| 
 | ||||
|     /* Skip floppy drives when requested.  */ | ||||
|     if (no_floppy && | ||||
| 	name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') | ||||
|       return 0; | ||||
| 
 | ||||
| #ifdef DO_SEARCH_FILE | ||||
|       { | ||||
| 	char *buf; | ||||
| 	grub_file_t file; | ||||
| 
 | ||||
| 	buf = grub_xasprintf ("(%s)%s", name, key); | ||||
| 	if (! buf) | ||||
| 	  return 1; | ||||
| 
 | ||||
| 	file = grub_file_open (buf); | ||||
| 	if (file) | ||||
| 	  { | ||||
| 	    found = 1; | ||||
| 	    grub_file_close (file); | ||||
| 	  } | ||||
| 	grub_free (buf); | ||||
|       } | ||||
| #else | ||||
|       { | ||||
| 	/* SEARCH_FS_UUID or SEARCH_LABEL */ | ||||
| 	grub_device_t dev; | ||||
| 	grub_fs_t fs; | ||||
| 	char *quid; | ||||
| 
 | ||||
| 	dev = grub_device_open (name); | ||||
| 	if (dev) | ||||
| 	  { | ||||
| 	    fs = grub_fs_probe (dev); | ||||
| 
 | ||||
| #ifdef DO_SEARCH_FS_UUID | ||||
| #define compare_fn grub_strcasecmp | ||||
| #define read_fn uuid | ||||
| #else | ||||
| #define compare_fn grub_strcmp | ||||
| #define read_fn label | ||||
| #endif | ||||
| 
 | ||||
| 	    if (fs && fs->read_fn) | ||||
| 	      { | ||||
| 		fs->read_fn (dev, &quid); | ||||
| 
 | ||||
| 		if (grub_errno == GRUB_ERR_NONE && quid) | ||||
| 		  { | ||||
| 		    if (compare_fn (quid, key) == 0) | ||||
| 		      found = 1; | ||||
| 
 | ||||
| 		    grub_free (quid); | ||||
| 		  } | ||||
| 	      } | ||||
| 
 | ||||
| 	    grub_device_close (dev); | ||||
| 	  } | ||||
|       } | ||||
| #endif | ||||
| 
 | ||||
|     if (found) | ||||
|       { | ||||
| 	count++; | ||||
| 	if (var) | ||||
| 	  grub_env_set (var, name); | ||||
| 	else | ||||
| 	  grub_printf (" %s", name); | ||||
|       } | ||||
| 
 | ||||
|     grub_errno = GRUB_ERR_NONE; | ||||
|     return (found && var); | ||||
|   } | ||||
| 
 | ||||
|   /* First try without autoloading if we're setting variable. */ | ||||
|   if (var) | ||||
|     { | ||||
|       saved_autoload = grub_fs_autoload_hook; | ||||
|       grub_fs_autoload_hook = 0; | ||||
|       grub_device_iterate (iterate_device); | ||||
| 
 | ||||
|       /* Restore autoload hook.  */ | ||||
|       grub_fs_autoload_hook = saved_autoload; | ||||
| 
 | ||||
|       /* Retry with autoload if nothing found.  */ | ||||
|       if (grub_errno == GRUB_ERR_NONE && count == 0) | ||||
| 	grub_device_iterate (iterate_device); | ||||
|     } | ||||
|   else | ||||
|     grub_device_iterate (iterate_device); | ||||
| 
 | ||||
|   if (grub_errno == GRUB_ERR_NONE && count == 0) | ||||
|     grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc, | ||||
| 		    char **args) | ||||
| { | ||||
|   if (argc == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); | ||||
| 
 | ||||
|   FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0); | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| #ifdef DO_SEARCH_FILE | ||||
| GRUB_MOD_INIT(search_fs_file) | ||||
| #elif defined (DO_SEARCH_FS_UUID) | ||||
| GRUB_MOD_INIT(search_fs_uuid) | ||||
| #else | ||||
| GRUB_MOD_INIT(search_label) | ||||
| #endif | ||||
| { | ||||
|   cmd = | ||||
|     grub_register_command (COMMAND_NAME, grub_cmd_do_search, | ||||
| 			   N_("NAME [VARIABLE]"), | ||||
| 			   HELP_MESSAGE); | ||||
| } | ||||
| 
 | ||||
| #ifdef DO_SEARCH_FILE | ||||
| GRUB_MOD_FINI(search_fs_file) | ||||
| #elif defined (DO_SEARCH_FS_UUID) | ||||
| GRUB_MOD_FINI(search_fs_uuid) | ||||
| #else | ||||
| GRUB_MOD_FINI(search_label) | ||||
| #endif | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										6
									
								
								grub-core/commands/search_file.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								grub-core/commands/search_file.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| #define DO_SEARCH_FILE 1 | ||||
| #define FUNC_NAME grub_search_fs_file | ||||
| #define COMMAND_NAME "search.file" | ||||
| #define SEARCH_TARGET "file" | ||||
| #define HELP_MESSAGE N_("Search devices by file. If VARIABLE is specified, the first device found is set to a variable.") | ||||
| #include "search.c" | ||||
							
								
								
									
										6
									
								
								grub-core/commands/search_label.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								grub-core/commands/search_label.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| #define DO_SEARCH_FS_LABEL 1 | ||||
| #define FUNC_NAME grub_search_label | ||||
| #define COMMAND_NAME "search.fs_label" | ||||
| #define SEARCH_TARGET "filesystem label" | ||||
| #define HELP_MESSAGE N_("Search devices by label. If VARIABLE is specified, the first device found is set to a variable.") | ||||
| #include "search.c" | ||||
							
								
								
									
										6
									
								
								grub-core/commands/search_uuid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								grub-core/commands/search_uuid.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| #define DO_SEARCH_FS_UUID 1 | ||||
| #define FUNC_NAME grub_search_fs_uuid | ||||
| #define COMMAND_NAME "search.fs_uuid" | ||||
| #define SEARCH_TARGET "filesystem UUID" | ||||
| #define HELP_MESSAGE N_("Search devices by UUID. If VARIABLE is specified, the first device found is set to a variable.") | ||||
| #include "search.c" | ||||
							
								
								
									
										95
									
								
								grub-core/commands/search_wrap.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								grub-core/commands/search_wrap.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| /* search.c - search devices based on a file or a filesystem label */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/search.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"file",		'f', 0, N_("Search devices by a file."), 0, 0}, | ||||
|     {"label",		'l', 0, N_("Search devices by a filesystem label."), | ||||
|      0, 0}, | ||||
|     {"fs-uuid",		'u', 0, N_("Search devices by a filesystem UUID."), | ||||
|      0, 0}, | ||||
|     {"set",		's', GRUB_ARG_OPTION_OPTIONAL, | ||||
|      N_("Set a variable to the first device found."), "VAR", ARG_TYPE_STRING}, | ||||
|     {"no-floppy",	'n', 0, N_("Do not probe any floppy drive."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| enum options | ||||
|   { | ||||
|     SEARCH_FILE, | ||||
|     SEARCH_LABEL, | ||||
|     SEARCH_FS_UUID, | ||||
|     SEARCH_SET, | ||||
|     SEARCH_NO_FLOPPY, | ||||
|  }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_search (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   const char *var = 0; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); | ||||
| 
 | ||||
|   if (state[SEARCH_SET].set) | ||||
|     var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root"; | ||||
| 
 | ||||
|   if (state[SEARCH_LABEL].set) | ||||
|     grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set); | ||||
|   else if (state[SEARCH_FS_UUID].set) | ||||
|     grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set); | ||||
|   else if (state[SEARCH_FILE].set) | ||||
|     grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set); | ||||
|   else | ||||
|     return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(search) | ||||
| { | ||||
|   cmd = | ||||
|     grub_register_extcmd ("search", grub_cmd_search, | ||||
| 			  GRUB_COMMAND_FLAG_BOTH, | ||||
| 			  N_("search [-f|-l|-u|-s|-n] NAME"), | ||||
| 			  N_("Search devices by file, filesystem label" | ||||
| 			     " or filesystem UUID." | ||||
| 			     " If --set is specified, the first device found is" | ||||
| 			     " set to a variable. If no variable name is" | ||||
| 			     " specified, \"root\" is used."), | ||||
| 			  options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(search) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										341
									
								
								grub-core/commands/setpci.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								grub-core/commands/setpci.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,341 @@ | |||
| /* lspci.c - List PCI devices.  */ | ||||
| /*
 | ||||
|  *  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/pci.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| struct pci_register | ||||
| { | ||||
|   const char *name; | ||||
|   grub_uint16_t addr; | ||||
|   unsigned size; | ||||
| }; | ||||
| 
 | ||||
| struct pci_register pci_registers[] = | ||||
|   { | ||||
|     {"VENDOR_ID",       GRUB_PCI_REG_VENDOR      , 2}, | ||||
|     {"DEVICE_ID",       GRUB_PCI_REG_DEVICE      , 2}, | ||||
|     {"COMMAND",         GRUB_PCI_REG_COMMAND     , 2}, | ||||
|     {"STATUS",          GRUB_PCI_REG_STATUS      , 2}, | ||||
|     {"REVISION",        GRUB_PCI_REG_REVISION    , 1}, | ||||
|     {"CLASS_PROG",      GRUB_PCI_REG_CLASS + 1   , 1}, | ||||
|     {"CLASS_DEVICE",    GRUB_PCI_REG_CLASS + 2   , 2}, | ||||
|     {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE   , 1}, | ||||
|     {"LATENCY_TIMER",   GRUB_PCI_REG_LAT_TIMER   , 1}, | ||||
|     {"HEADER_TYPE",     GRUB_PCI_REG_HEADER_TYPE , 1}, | ||||
|     {"BIST",            GRUB_PCI_REG_BIST        , 1}, | ||||
|     {"BASE_ADDRESS_0",  GRUB_PCI_REG_ADDRESS_REG0, 4}, | ||||
|     {"BASE_ADDRESS_1",  GRUB_PCI_REG_ADDRESS_REG1, 4}, | ||||
|     {"BASE_ADDRESS_2",  GRUB_PCI_REG_ADDRESS_REG2, 4}, | ||||
|     {"BASE_ADDRESS_3",  GRUB_PCI_REG_ADDRESS_REG3, 4}, | ||||
|     {"BASE_ADDRESS_4",  GRUB_PCI_REG_ADDRESS_REG4, 4}, | ||||
|     {"BASE_ADDRESS_5",  GRUB_PCI_REG_ADDRESS_REG5, 4}, | ||||
|     {"CARDBUS_CIS",     GRUB_PCI_REG_CIS_POINTER , 4}, | ||||
|     {"SUBVENDOR_ID",    GRUB_PCI_REG_SUBVENDOR   , 2}, | ||||
|     {"SUBSYSTEM_ID",    GRUB_PCI_REG_SUBSYSTEM   , 2}, | ||||
|     {"ROM_ADDRESS",     GRUB_PCI_REG_ROM_ADDRESS , 4}, | ||||
|     {"CAP_POINTER",     GRUB_PCI_REG_CAP_POINTER , 1}, | ||||
|     {"INTERRUPT_LINE",  GRUB_PCI_REG_IRQ_LINE    , 1}, | ||||
|     {"INTERRUPT_PIN",   GRUB_PCI_REG_IRQ_PIN     , 1}, | ||||
|     {"MIN_GNT",         GRUB_PCI_REG_MIN_GNT     , 1}, | ||||
|     {"MAX_LAT",         GRUB_PCI_REG_MIN_GNT     , 1}, | ||||
|   }; | ||||
| 
 | ||||
| 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, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static grub_uint32_t pciid_check_mask, pciid_check_value; | ||||
| static int bus, device, function; | ||||
| static int check_bus, check_device, check_function; | ||||
| static grub_uint32_t write_mask, regwrite; | ||||
| static int regsize; | ||||
| static grub_uint16_t regaddr; | ||||
| static const char *varname; | ||||
| 
 | ||||
| static int NESTED_FUNC_ATTR | ||||
| grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) | ||||
| { | ||||
|   grub_uint32_t regval = 0; | ||||
|   grub_pci_address_t addr; | ||||
| 
 | ||||
|   if ((pciid & pciid_check_mask) != pciid_check_value) | ||||
|     return 0; | ||||
| 
 | ||||
|   if (check_bus && grub_pci_get_bus (dev) != bus) | ||||
|     return 0; | ||||
| 
 | ||||
|   if (check_device && grub_pci_get_device (dev) != device) | ||||
|     return 0; | ||||
| 
 | ||||
|   if (check_function && grub_pci_get_function (dev) != function) | ||||
|     return 0; | ||||
| 
 | ||||
|   addr = grub_pci_make_address (dev, regaddr); | ||||
| 
 | ||||
|   switch (regsize) | ||||
|     { | ||||
|     case 1: | ||||
|       regval = grub_pci_read_byte (addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 2: | ||||
|       regval = grub_pci_read_word (addr); | ||||
|       break; | ||||
| 
 | ||||
|     case 4: | ||||
|       regval = grub_pci_read (addr); | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   if (varname) | ||||
|     { | ||||
|       char buf[sizeof ("XXXXXXXX")]; | ||||
|       grub_snprintf (buf, sizeof (buf), "%x", regval); | ||||
|       grub_env_set (varname, buf); | ||||
|       return 1; | ||||
|     } | ||||
| 
 | ||||
|   if (!write_mask) | ||||
|     { | ||||
|       grub_printf ("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), | ||||
| 		   regval); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   regval = (regval & ~write_mask) | regwrite; | ||||
| 
 | ||||
|   switch (regsize) | ||||
|     { | ||||
|     case 1: | ||||
|       grub_pci_write_byte (addr, regval); | ||||
|       break; | ||||
| 
 | ||||
|     case 2: | ||||
|       grub_pci_write_word (addr, regval); | ||||
|       break; | ||||
| 
 | ||||
|     case 4: | ||||
|       grub_pci_write (addr, regval); | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) | ||||
| { | ||||
|   const char *ptr; | ||||
|   unsigned i; | ||||
| 
 | ||||
|   pciid_check_value = 0; | ||||
|   pciid_check_mask = 0; | ||||
| 
 | ||||
|   if (cmd->state[0].set) | ||||
|     { | ||||
|       ptr = cmd->state[0].arg; | ||||
|       pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff); | ||||
|       if (grub_errno == GRUB_ERR_BAD_NUMBER) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  ptr = cmd->state[0].arg; | ||||
| 	} | ||||
|       else | ||||
| 	pciid_check_mask |= 0xffff; | ||||
|       if (grub_errno) | ||||
| 	return grub_errno; | ||||
|       if (*ptr != ':') | ||||
| 	return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected."); | ||||
|       ptr++; | ||||
|       pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff) | ||||
| 	<< 16; | ||||
|       if (grub_errno == GRUB_ERR_BAD_NUMBER) | ||||
| 	grub_errno = GRUB_ERR_NONE; | ||||
|       else | ||||
| 	pciid_check_mask |= 0xffff0000; | ||||
|     } | ||||
| 
 | ||||
|   pciid_check_value &= pciid_check_mask; | ||||
| 
 | ||||
|   check_bus = check_device = check_function = 0; | ||||
| 
 | ||||
|   if (cmd->state[1].set) | ||||
|     { | ||||
|       const char *optr; | ||||
|        | ||||
|       ptr = cmd->state[1].arg; | ||||
|       optr = ptr; | ||||
|       bus = grub_strtoul (ptr, (char **) &ptr, 16); | ||||
|       if (grub_errno == GRUB_ERR_BAD_NUMBER) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  ptr = optr; | ||||
| 	} | ||||
|       else | ||||
| 	check_bus = 1; | ||||
|       if (grub_errno) | ||||
| 	return grub_errno; | ||||
|       if (*ptr != ':') | ||||
| 	return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected."); | ||||
|       ptr++; | ||||
|       optr = ptr; | ||||
|       device = grub_strtoul (ptr, (char **) &ptr, 16); | ||||
|       if (grub_errno == GRUB_ERR_BAD_NUMBER) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  ptr = optr; | ||||
| 	} | ||||
|       else | ||||
| 	check_device = 1; | ||||
|       if (*ptr == '.') | ||||
| 	{ | ||||
| 	  ptr++; | ||||
| 	  function = grub_strtoul (ptr, (char **) &ptr, 16); | ||||
| 	  if (grub_errno) | ||||
| 	    return grub_errno; | ||||
| 	  check_function = 1; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   if (cmd->state[2].set) | ||||
|     varname = cmd->state[2].arg; | ||||
|   else | ||||
|     varname = NULL; | ||||
| 
 | ||||
|   write_mask = 0; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Command expected."); | ||||
| 
 | ||||
|   if (argc > 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one command is supported."); | ||||
| 
 | ||||
|   ptr = argv[0]; | ||||
| 
 | ||||
|   for (i = 0; i < ARRAY_SIZE (pci_registers); i++) | ||||
|     { | ||||
|       if (grub_strncmp (ptr, pci_registers[i].name, | ||||
| 			grub_strlen (pci_registers[i].name)) == 0) | ||||
| 	break; | ||||
|     } | ||||
|   if (i == ARRAY_SIZE (pci_registers)) | ||||
|     { | ||||
|       regsize = 0; | ||||
|       regaddr = grub_strtoul (ptr, (char **) &ptr, 16); | ||||
|       if (grub_errno) | ||||
| 	return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown register"); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       regaddr = pci_registers[i].addr; | ||||
|       regsize = pci_registers[i].size; | ||||
|       ptr += grub_strlen (pci_registers[i].name); | ||||
|     } | ||||
| 
 | ||||
|   if (grub_errno) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (*ptr == '+') | ||||
|     { | ||||
|       ptr++; | ||||
|       regaddr += grub_strtoul (ptr, (char **) &ptr, 16); | ||||
|       if (grub_errno) | ||||
| 	return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) == 0 | ||||
|       || grub_memcmp (ptr, ".l", sizeof (".l") - 1) == 0) | ||||
|     { | ||||
|       regsize = 4; | ||||
|       ptr += sizeof (".l") - 1; | ||||
|     } | ||||
|   else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) == 0 | ||||
|       || grub_memcmp (ptr, ".w", sizeof (".w") - 1) == 0) | ||||
|     { | ||||
|       regsize = 2; | ||||
|       ptr += sizeof (".w") - 1; | ||||
|     } | ||||
|   else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) == 0 | ||||
|       || grub_memcmp (ptr, ".b", sizeof (".b") - 1) == 0) | ||||
|     { | ||||
|       regsize = 1; | ||||
|       ptr += sizeof (".b") - 1; | ||||
|     } | ||||
| 
 | ||||
|   if (!regsize) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 		       "Unknown register size."); | ||||
| 
 | ||||
|   write_mask = 0; | ||||
|   if (*ptr == '=') | ||||
|     { | ||||
|       ptr++; | ||||
|       regwrite = grub_strtoul (ptr, (char **) &ptr, 16); | ||||
|       if (grub_errno) | ||||
| 	return grub_errno; | ||||
|       write_mask = 0xffffffff; | ||||
|       if (*ptr == ':') | ||||
| 	{ | ||||
| 	  ptr++; | ||||
| 	  write_mask = grub_strtoul (ptr, (char **) &ptr, 16); | ||||
| 	  if (grub_errno) | ||||
| 	    return grub_errno; | ||||
| 	  write_mask = 0xffffffff; | ||||
| 	} | ||||
|       regwrite &= write_mask; | ||||
|     } | ||||
| 
 | ||||
|   if (write_mask && varname) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
| 		       "Option -v isn't valid for writes."); | ||||
| 
 | ||||
|   grub_pci_iterate (grub_setpci_iter); | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(setpci) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[-s POSITION] [-d DEVICE] [-v VAR] " | ||||
| 				 "[REGISTER][=VALUE[:MASK]]"), | ||||
| 			      N_("Manipulate PCI devices."), options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(setpci) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										113
									
								
								grub-core/commands/sleep.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								grub-core/commands/sleep.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | |||
| /* sleep.c - Command to wait a specified number of seconds.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/time.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"verbose", 'v', 0, N_("Verbose countdown."), 0, 0}, | ||||
|     {"interruptible", 'i', 0, N_("Interruptible with ESC."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| static grub_uint16_t *pos; | ||||
| 
 | ||||
| static void | ||||
| do_print (int n) | ||||
| { | ||||
|   grub_term_restore_pos (pos); | ||||
|   /* NOTE: Do not remove the trailing space characters.
 | ||||
|      They are required to clear the line.  */ | ||||
|   grub_printf ("%d    ", n); | ||||
| } | ||||
| 
 | ||||
| /* Based on grub_millisleep() from kern/generic/millisleep.c.  */ | ||||
| static int | ||||
| grub_interruptible_millisleep (grub_uint32_t ms) | ||||
| { | ||||
|   grub_uint64_t start; | ||||
| 
 | ||||
|   start = grub_get_time_ms (); | ||||
| 
 | ||||
|   while (grub_get_time_ms () - start < ms) | ||||
|     if (grub_checkkey () >= 0 && | ||||
| 	GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC) | ||||
|       return 1; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = cmd->state; | ||||
|   int n; | ||||
| 
 | ||||
|   if (argc != 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing operand"); | ||||
| 
 | ||||
|   n = grub_strtoul (args[0], 0, 10); | ||||
| 
 | ||||
|   if (n == 0) | ||||
|     { | ||||
|       /* Either `0' or broken input.  */ | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   pos = grub_term_save_pos (); | ||||
| 
 | ||||
|   for (; n; n--) | ||||
|     { | ||||
|       if (state[0].set) | ||||
| 	do_print (n); | ||||
| 
 | ||||
|       if (state[1].set) | ||||
| 	{ | ||||
| 	  if (grub_interruptible_millisleep (1000)) | ||||
| 	    return 1; | ||||
| 	} | ||||
|       else | ||||
| 	grub_millisleep (1000); | ||||
|     } | ||||
|   if (state[0].set) | ||||
|     do_print (0); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
|  | ||||
| GRUB_MOD_INIT(sleep) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("sleep", grub_cmd_sleep, GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("NUMBER_OF_SECONDS"), | ||||
| 			      N_("Wait for a specified number of seconds."), | ||||
| 			      options); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(sleep) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
| } | ||||
							
								
								
									
										255
									
								
								grub-core/commands/terminal.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								grub-core/commands/terminal.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,255 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/mm.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <grub/misc.h> | ||||
| 
 | ||||
| struct grub_term_autoload *grub_term_input_autoload = NULL; | ||||
| struct grub_term_autoload *grub_term_output_autoload = NULL; | ||||
| 
 | ||||
| struct abstract_terminal | ||||
| { | ||||
|   struct abstract_terminal *next; | ||||
|   const char *name; | ||||
|   grub_err_t (*init) (struct abstract_terminal *term); | ||||
|   grub_err_t (*fini) (struct abstract_terminal *term); | ||||
| }; | ||||
| 
 | ||||
| static grub_err_t | ||||
| handle_command (int argc, char **args, struct abstract_terminal **enabled, | ||||
|                struct abstract_terminal **disabled, | ||||
|                struct grub_term_autoload *autoloads, | ||||
|                const char *active_str, | ||||
|                const char *available_str) | ||||
| { | ||||
|   int i; | ||||
|   struct abstract_terminal *term; | ||||
|   struct grub_term_autoload *aut; | ||||
| 
 | ||||
|   if (argc == 0) | ||||
|     { | ||||
|       grub_puts_ (active_str); | ||||
|       for (term = *enabled; term; term = term->next) | ||||
|        grub_printf ("%s ", term->name); | ||||
|       grub_printf ("\n"); | ||||
|       grub_puts_ (available_str); | ||||
|       for (term = *disabled; term; term = term->next) | ||||
|        grub_printf ("%s ", term->name); | ||||
|       /* This is quadratic but we don't expect mode than 30 terminal
 | ||||
|         modules ever.  */ | ||||
|       for (aut = autoloads; aut; aut = aut->next) | ||||
|        { | ||||
|          for (term = *disabled; term; term = term->next) | ||||
|            if (grub_strcmp (term->name, aut->name) == 0 | ||||
| 	       || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' | ||||
| 		   && grub_memcmp (term->name, aut->name, | ||||
| 				   grub_strlen (aut->name) - 1) == 0)) | ||||
|              break; | ||||
|          if (!term) | ||||
|            for (term = *enabled; term; term = term->next) | ||||
|              if (grub_strcmp (term->name, aut->name) == 0 | ||||
| 		 || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' | ||||
| 		     && grub_memcmp (term->name, aut->name, | ||||
| 				     grub_strlen (aut->name) - 1) == 0)) | ||||
|                break; | ||||
|          if (!term) | ||||
|            grub_printf ("%s ", aut->name); | ||||
|        } | ||||
|       grub_printf ("\n"); | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   i = 0; | ||||
| 
 | ||||
|   if (grub_strcmp (args[0], "--append") == 0 | ||||
|       || grub_strcmp (args[0], "--remove") == 0) | ||||
|     i++; | ||||
| 
 | ||||
|   if (i == argc) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified")); | ||||
| 
 | ||||
|   for (; i < argc; i++) | ||||
|     { | ||||
|       int again = 0; | ||||
|       while (1) | ||||
|        { | ||||
|          for (term = *disabled; term; term = term->next) | ||||
|            if (grub_strcmp (args[i], term->name) == 0) | ||||
|              break; | ||||
|          if (term == 0) | ||||
|            for (term = *enabled; term; term = term->next) | ||||
|              if (grub_strcmp (args[i], term->name) == 0) | ||||
|                break; | ||||
|          if (term) | ||||
|            break; | ||||
|          if (again) | ||||
|            return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", | ||||
|                               args[i]); | ||||
|          for (aut = autoloads; aut; aut = aut->next) | ||||
|            if (grub_strcmp (args[i], aut->name) == 0 | ||||
| 	       || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' | ||||
| 		   && grub_memcmp (args[i], aut->name, | ||||
| 				   grub_strlen (aut->name) - 1) == 0)) | ||||
|              { | ||||
|                grub_dl_t mod; | ||||
|                mod = grub_dl_load (aut->modname); | ||||
|                if (mod) | ||||
|                  grub_dl_ref (mod); | ||||
|                grub_errno = GRUB_ERR_NONE; | ||||
|                break; | ||||
|              } | ||||
|          if (!aut) | ||||
|            return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n", | ||||
|                               args[i]); | ||||
|          again = 1; | ||||
|        } | ||||
|     } | ||||
| 
 | ||||
|   if (grub_strcmp (args[0], "--append") == 0) | ||||
|     { | ||||
|       for (i = 1; i < argc; i++) | ||||
|        { | ||||
|          for (term = *disabled; term; term = term->next) | ||||
|            if (grub_strcmp (args[i], term->name) == 0) | ||||
|              break; | ||||
|          if (term) | ||||
|            { | ||||
|               if (term->init && term->init (term) != GRUB_ERR_NONE) | ||||
|                 return grub_errno; | ||||
| 
 | ||||
|              grub_list_remove (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); | ||||
|              grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); | ||||
|            } | ||||
|        } | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   if (grub_strcmp (args[0], "--remove") == 0) | ||||
|     { | ||||
|       for (i = 1; i < argc; i++) | ||||
|        { | ||||
|          for (term = *enabled; term; term = term->next) | ||||
|            if (grub_strcmp (args[i], term->name) == 0) | ||||
|              break; | ||||
|          if (term) | ||||
|            { | ||||
|              if (!term->next && term == *enabled) | ||||
|                return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
|                                   "can't remove the last terminal"); | ||||
|              grub_list_remove (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); | ||||
|              if (term->fini) | ||||
|                term->fini (term); | ||||
|              grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); | ||||
|            } | ||||
|        } | ||||
|       return GRUB_ERR_NONE; | ||||
|     } | ||||
|   for (i = 0; i < argc; i++) | ||||
|     { | ||||
|       for (term = *disabled; term; term = term->next) | ||||
|        if (grub_strcmp (args[i], term->name) == 0) | ||||
|          break; | ||||
|       if (term) | ||||
|        { | ||||
|          if (term->init && term->init (term) != GRUB_ERR_NONE) | ||||
|            return grub_errno; | ||||
| 
 | ||||
|          grub_list_remove (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); | ||||
|          grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); | ||||
|        }        | ||||
|     } | ||||
|    | ||||
|   { | ||||
|     struct abstract_terminal *next; | ||||
|     for (term = *enabled; term; term = next) | ||||
|       { | ||||
|        next = term->next; | ||||
|        for (i = 0; i < argc; i++) | ||||
|          if (grub_strcmp (args[i], term->name) == 0) | ||||
|            break; | ||||
|        if (i == argc) | ||||
|          { | ||||
|            if (!term->next && term == *enabled) | ||||
|              return grub_error (GRUB_ERR_BAD_ARGUMENT, | ||||
|                                 "can't remove the last terminal"); | ||||
|            grub_list_remove (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); | ||||
|            if (term->fini) | ||||
|              term->fini (term); | ||||
|            grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); | ||||
|          } | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)), | ||||
| 			 int argc, char **args) | ||||
| { | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next); | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name); | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init); | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini); | ||||
|   return handle_command (argc, args, | ||||
|                         (struct abstract_terminal **) &grub_term_inputs, | ||||
|                         (struct abstract_terminal **) &grub_term_inputs_disabled, | ||||
|                         grub_term_input_autoload, | ||||
|                         N_ ("Active input terminals:"), | ||||
|                         N_ ("Available input terminals:")); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)), | ||||
|                          int argc, char **args) | ||||
| { | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next); | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name); | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init); | ||||
|   (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini); | ||||
|   return handle_command (argc, args, (struct abstract_terminal **) &grub_term_outputs, | ||||
|                         (struct abstract_terminal **) &grub_term_outputs_disabled, | ||||
|                         grub_term_output_autoload, | ||||
|                         N_ ("Active output terminals:"), | ||||
|                         N_ ("Available output terminals:")); | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_terminal_input, cmd_terminal_output; | ||||
| 
 | ||||
| GRUB_MOD_INIT(terminal) | ||||
| { | ||||
|   cmd_terminal_input = | ||||
|     grub_register_command ("terminal_input", grub_cmd_terminal_input, | ||||
| 			   N_("[--append|--remove] " | ||||
| 			      "[TERMINAL1] [TERMINAL2] ..."), | ||||
| 			   N_("List or select an input terminal.")); | ||||
|   cmd_terminal_output = | ||||
|     grub_register_command ("terminal_output", grub_cmd_terminal_output, | ||||
| 			   N_("[--append|--remove] " | ||||
| 			      "[TERMINAL1] [TERMINAL2] ..."), | ||||
| 			   N_("List or select an output terminal.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(terminal) | ||||
| { | ||||
|   grub_unregister_command (cmd_terminal_input); | ||||
|   grub_unregister_command (cmd_terminal_output); | ||||
| } | ||||
							
								
								
									
										433
									
								
								grub-core/commands/test.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								grub-core/commands/test.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,433 @@ | |||
| /* test.c -- The test command..  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/fs.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| /* A simple implementation for signed numbers. */ | ||||
| static int | ||||
| grub_strtosl (char *arg, char **end, int base) | ||||
| { | ||||
|   if (arg[0] == '-') | ||||
|     return -grub_strtoul (arg + 1, end, base); | ||||
|   return grub_strtoul (arg, end, base); | ||||
| } | ||||
| 
 | ||||
| /* Parse a test expression starting from *argn. */ | ||||
| static int | ||||
| test_parse (char **args, int *argn, int argc) | ||||
| { | ||||
|   int ret = 0, discard = 0, invert = 0; | ||||
|   int file_exists; | ||||
|   struct grub_dirhook_info file_info; | ||||
| 
 | ||||
|   auto void update_val (int val); | ||||
|   auto void get_fileinfo (char *pathname); | ||||
| 
 | ||||
|   /* Take care of discarding and inverting. */ | ||||
|   void update_val (int val) | ||||
|   { | ||||
|     if (! discard) | ||||
|       ret = invert ? ! val : val; | ||||
|     invert = discard = 0; | ||||
|   } | ||||
| 
 | ||||
|   /* Check if file exists and fetch its information. */ | ||||
|   void get_fileinfo (char *path) | ||||
|   { | ||||
|     char *filename, *pathname; | ||||
|     char *device_name; | ||||
|     grub_fs_t fs; | ||||
|     grub_device_t dev; | ||||
| 
 | ||||
|     /* A hook for iterating directories. */ | ||||
|     auto int find_file (const char *cur_filename, | ||||
| 			const struct grub_dirhook_info *info); | ||||
|     int find_file (const char *cur_filename, | ||||
| 		   const struct grub_dirhook_info *info) | ||||
|     { | ||||
|       if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename) | ||||
| 	   : grub_strcmp (cur_filename, filename)) == 0) | ||||
| 	{ | ||||
| 	  file_info = *info; | ||||
| 	  file_exists = 1; | ||||
| 	  return 1; | ||||
| 	} | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|     file_exists = 0; | ||||
|     device_name = grub_file_get_device_name (path); | ||||
|     dev = grub_device_open (device_name); | ||||
|     if (! dev) | ||||
|       { | ||||
| 	grub_free (device_name); | ||||
| 	return; | ||||
|       } | ||||
| 
 | ||||
|     fs = grub_fs_probe (dev); | ||||
|     if (! fs) | ||||
|       { | ||||
| 	grub_free (device_name); | ||||
| 	grub_device_close (dev); | ||||
| 	return; | ||||
|       } | ||||
| 
 | ||||
|     pathname = grub_strchr (path, ')'); | ||||
|     if (! pathname) | ||||
|       pathname = path; | ||||
|     else | ||||
|       pathname++; | ||||
| 
 | ||||
|     /* Remove trailing '/'. */ | ||||
|     while (*pathname && pathname[grub_strlen (pathname) - 1] == '/') | ||||
|       pathname[grub_strlen (pathname) - 1] = 0; | ||||
| 
 | ||||
|     /* Split into path and filename. */ | ||||
|     filename = grub_strrchr (pathname, '/'); | ||||
|     if (! filename) | ||||
|       { | ||||
| 	path = grub_strdup ("/"); | ||||
| 	filename = pathname; | ||||
|       } | ||||
|     else | ||||
|       { | ||||
| 	filename++; | ||||
| 	path = grub_strdup (pathname); | ||||
| 	path[filename - pathname] = 0; | ||||
|       } | ||||
| 
 | ||||
|     /* It's the whole device. */ | ||||
|     if (! *pathname) | ||||
|       { | ||||
| 	file_exists = 1; | ||||
| 	grub_memset (&file_info, 0, sizeof (file_info)); | ||||
| 	/* Root is always a directory. */ | ||||
| 	file_info.dir = 1; | ||||
| 
 | ||||
| 	/* Fetch writing time. */ | ||||
| 	file_info.mtimeset = 0; | ||||
| 	if (fs->mtime) | ||||
| 	  { | ||||
| 	    if (! fs->mtime (dev, &file_info.mtime)) | ||||
| 	      file_info.mtimeset = 1; | ||||
| 	    grub_errno = GRUB_ERR_NONE; | ||||
| 	  } | ||||
|       } | ||||
|     else | ||||
|       (fs->dir) (dev, path, find_file); | ||||
| 
 | ||||
|     grub_device_close (dev); | ||||
|     grub_free (path); | ||||
|     grub_free (device_name); | ||||
|   } | ||||
| 
 | ||||
|   /* Here we have the real parsing. */ | ||||
|   while (*argn < argc) | ||||
|     { | ||||
|       /* First try 3 argument tests. */ | ||||
|       if (*argn + 2 < argc) | ||||
| 	{ | ||||
| 	  /* String tests. */ | ||||
| 	  if (grub_strcmp (args[*argn + 1], "=") == 0 | ||||
| 	      || grub_strcmp (args[*argn + 1], "==") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "!=") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* GRUB extension: lexicographical sorting. */ | ||||
| 	  if (grub_strcmp (args[*argn + 1], "<") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "<=") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], ">") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], ">=") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* Number tests. */ | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-eq") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strtosl (args[*argn], 0, 0) | ||||
| 			  == grub_strtosl (args[*argn + 2], 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-ge") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strtosl (args[*argn], 0, 0) | ||||
| 			  >= grub_strtosl (args[*argn + 2], 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-gt") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strtosl (args[*argn], 0, 0) | ||||
| 			  > grub_strtosl (args[*argn + 2], 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-le") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strtosl (args[*argn], 0, 0) | ||||
| 		      <= grub_strtosl (args[*argn + 2], 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-lt") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strtosl (args[*argn], 0, 0) | ||||
| 			  < grub_strtosl (args[*argn + 2], 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-ne") == 0) | ||||
| 	    { | ||||
| 	      update_val (grub_strtosl (args[*argn], 0, 0) | ||||
| 			  != grub_strtosl (args[*argn + 2], 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* GRUB extension: compare numbers skipping prefixes.
 | ||||
| 	     Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11. */ | ||||
| 	  if (grub_strcmp (args[*argn + 1], "-pgt") == 0 | ||||
| 	      || grub_strcmp (args[*argn + 1], "-plt") == 0) | ||||
| 	    { | ||||
| 	      int i; | ||||
| 	      /* Skip common prefix. */ | ||||
| 	      for (i = 0; args[*argn][i] == args[*argn + 2][i] | ||||
| 		     && args[*argn][i]; i++); | ||||
| 
 | ||||
| 	      /* Go the digits back. */ | ||||
| 	      i--; | ||||
| 	      while (grub_isdigit (args[*argn][i]) && i > 0) | ||||
| 		i--; | ||||
| 	      i++; | ||||
| 
 | ||||
| 	      if (grub_strcmp (args[*argn + 1], "-pgt") == 0) | ||||
| 		update_val (grub_strtoul (args[*argn] + i, 0, 0) | ||||
| 			    > grub_strtoul (args[*argn + 2] + i, 0, 0)); | ||||
| 	      else | ||||
| 		update_val (grub_strtoul (args[*argn] + i, 0, 0) | ||||
| 			    < grub_strtoul (args[*argn + 2] + i, 0, 0)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* -nt and -ot tests. GRUB extension: when doing -?t<bias> bias
 | ||||
| 	     will be added to the first mtime. */ | ||||
| 	  if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0 | ||||
| 	      || grub_memcmp (args[*argn + 1], "-ot", 3) == 0) | ||||
| 	    { | ||||
| 	      struct grub_dirhook_info file1; | ||||
| 	      int file1exists; | ||||
| 	      int bias = 0; | ||||
| 
 | ||||
| 	      /* Fetch fileinfo. */ | ||||
| 	      get_fileinfo (args[*argn]); | ||||
| 	      file1 = file_info; | ||||
| 	      file1exists = file_exists; | ||||
| 	      get_fileinfo (args[*argn + 2]); | ||||
| 
 | ||||
| 	      if (args[*argn + 1][3]) | ||||
| 		bias = grub_strtosl (args[*argn + 1] + 3, 0, 0); | ||||
| 
 | ||||
| 	      if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0) | ||||
| 		update_val ((file1exists && ! file_exists) | ||||
| 			    || (file1.mtimeset && file_info.mtimeset | ||||
| 				&& file1.mtime + bias > file_info.mtime)); | ||||
| 	      else | ||||
| 		update_val ((! file1exists && file_exists) | ||||
| 			    || (file1.mtimeset && file_info.mtimeset | ||||
| 				&& file1.mtime + bias < file_info.mtime)); | ||||
| 	      (*argn) += 3; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       /* Two-argument tests. */ | ||||
|       if (*argn + 1 < argc) | ||||
| 	{ | ||||
| 	  /* File tests. */ | ||||
| 	  if (grub_strcmp (args[*argn], "-d") == 0) | ||||
| 	    { | ||||
| 	      get_fileinfo (args[*argn + 1]); | ||||
| 	      update_val (file_exists && file_info.dir); | ||||
| 	      (*argn) += 2; | ||||
| 	      return ret; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn], "-e") == 0) | ||||
| 	    { | ||||
| 	      get_fileinfo (args[*argn + 1]); | ||||
| 	      update_val (file_exists); | ||||
| 	      (*argn) += 2; | ||||
| 	      return ret; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn], "-f") == 0) | ||||
| 	    { | ||||
| 	      get_fileinfo (args[*argn + 1]); | ||||
| 	      /* FIXME: check for other types. */ | ||||
| 	      update_val (file_exists && ! file_info.dir); | ||||
| 	      (*argn) += 2; | ||||
| 	      return ret; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (args[*argn], "-s") == 0) | ||||
| 	    { | ||||
| 	      grub_file_t file; | ||||
| 	      file = grub_file_open (args[*argn + 1]); | ||||
| 	      update_val (file && (grub_file_size (file) != 0)); | ||||
| 	      if (file) | ||||
| 		grub_file_close (file); | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	      (*argn) += 2; | ||||
| 	      return ret; | ||||
| 	    } | ||||
| 
 | ||||
| 	  /* String tests. */ | ||||
| 	  if (grub_strcmp (args[*argn], "-n") == 0) | ||||
| 	    { | ||||
| 	      update_val (args[*argn + 1][0]); | ||||
| 
 | ||||
| 	      (*argn) += 2; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 	  if (grub_strcmp (args[*argn], "-z") == 0) | ||||
| 	    { | ||||
| 	      update_val (! args[*argn + 1][0]); | ||||
| 	      (*argn) += 2; | ||||
| 	      continue; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       /* Special modifiers. */ | ||||
| 
 | ||||
|       /* End of expression. return to parent. */ | ||||
|       if (grub_strcmp (args[*argn], ")") == 0) | ||||
| 	{ | ||||
| 	  (*argn)++; | ||||
| 	  return ret; | ||||
| 	} | ||||
|       /* Recursively invoke if parenthesis. */ | ||||
|       if (grub_strcmp (args[*argn], "(") == 0) | ||||
| 	{ | ||||
| 	  (*argn)++; | ||||
| 	  update_val (test_parse (args, argn, argc)); | ||||
| 	  continue; | ||||
| 	} | ||||
| 
 | ||||
|       if (grub_strcmp (args[*argn], "!") == 0) | ||||
| 	{ | ||||
| 	  invert = ! invert; | ||||
| 	  (*argn)++; | ||||
| 	  continue; | ||||
| 	} | ||||
|       if (grub_strcmp (args[*argn], "-a") == 0) | ||||
| 	{ | ||||
| 	  /* If current value is 0 second value is to be discarded. */ | ||||
| 	  discard = ! ret; | ||||
| 	  (*argn)++; | ||||
| 	  continue; | ||||
| 	} | ||||
|       if (grub_strcmp (args[*argn], "-o") == 0) | ||||
| 	{ | ||||
| 	  /* If current value is 1 second value is to be discarded. */ | ||||
| 	  discard = ret; | ||||
| 	  (*argn)++; | ||||
| 	  continue; | ||||
| 	} | ||||
| 
 | ||||
|       /* No test found. Interpret if as just a string. */ | ||||
|       update_val (args[*argn][0]); | ||||
|       (*argn)++; | ||||
|     } | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_test (grub_command_t cmd __attribute__ ((unused)), | ||||
| 	       int argc, char **args) | ||||
| { | ||||
|   int argn = 0; | ||||
| 
 | ||||
|   if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0) | ||||
|     argc--; | ||||
| 
 | ||||
|   return test_parse (args, &argn, argc) ? GRUB_ERR_NONE | ||||
|     : grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_1, cmd_2; | ||||
|  | ||||
| GRUB_MOD_INIT(test) | ||||
| { | ||||
|   cmd_1 = grub_register_command ("[", grub_cmd_test, | ||||
| 				 N_("EXPRESSION ]"), N_("Evaluate an expression.")); | ||||
|   cmd_2 = grub_register_command ("test", grub_cmd_test, | ||||
| 				 N_("EXPRESSION"), N_("Evaluate an expression.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(test) | ||||
| { | ||||
|   grub_unregister_command (cmd_1); | ||||
|   grub_unregister_command (cmd_2); | ||||
| } | ||||
							
								
								
									
										57
									
								
								grub-core/commands/true.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								grub-core/commands/true.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,57 @@ | |||
| /* true.c - true and false commands.  */ | ||||
| /*
 | ||||
|  *  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/dl.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_true (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 	       int argc __attribute__ ((unused)), | ||||
| 	       char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_false (struct grub_command *cmd __attribute__ ((unused)), | ||||
| 		int argc __attribute__ ((unused)), | ||||
| 		char *argv[] __attribute__ ((unused))) | ||||
| { | ||||
|   return grub_error (GRUB_ERR_TEST_FAILURE, "false"); | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd_true, cmd_false; | ||||
| 
 | ||||
|  | ||||
| GRUB_MOD_INIT(true) | ||||
| { | ||||
|   cmd_true = | ||||
|     grub_register_command ("true", grub_cmd_true, | ||||
| 			   0, N_("Do nothing, successfully.")); | ||||
|   cmd_false = | ||||
|     grub_register_command ("false", grub_cmd_false, | ||||
| 			   0, N_("Do nothing, unsuccessfully.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(true) | ||||
| { | ||||
|   grub_unregister_command (cmd_true); | ||||
|   grub_unregister_command (cmd_false); | ||||
| } | ||||
							
								
								
									
										216
									
								
								grub-core/commands/usbtest.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								grub-core/commands/usbtest.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,216 @@ | |||
| /* usbtest.c - test module for USB */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/charset.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/usb.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| static const char *usb_classes[] = | ||||
|   { | ||||
|     "Unknown", | ||||
|     "Audio", | ||||
|     "Communication Interface", | ||||
|     "HID", | ||||
|     "Unknown", | ||||
|     "Physical", | ||||
|     "Image", | ||||
|     "Printer", | ||||
|     "Mass Storage", | ||||
|     "Hub", | ||||
|     "Data Interface", | ||||
|     "Smart Card", | ||||
|     "Content Security", | ||||
|     "Video" | ||||
|   }; | ||||
| 
 | ||||
| static const char *usb_endp_type[] = | ||||
|   { | ||||
|     "Control", | ||||
|     "Isochronous", | ||||
|     "Bulk", | ||||
|     "Interrupt" | ||||
|   }; | ||||
| 
 | ||||
| static const char *usb_devspeed[] = | ||||
|   { | ||||
|     "", | ||||
|     "Low", | ||||
|     "Full", | ||||
|     "High" | ||||
|   }; | ||||
| 
 | ||||
| static grub_usb_err_t | ||||
| grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, | ||||
| 		     char **string) | ||||
| { | ||||
|   struct grub_usb_desc_str descstr; | ||||
|   struct grub_usb_desc_str *descstrp; | ||||
|   grub_usb_err_t err; | ||||
| 
 | ||||
|   /* Only get the length.  */ | ||||
|   err = grub_usb_control_msg (dev, 1 << 7, | ||||
| 			      0x06, (3 << 8) | index, | ||||
| 			      langid, 1, (char *) &descstr); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   descstrp = grub_malloc (descstr.length); | ||||
|   if (! descstrp) | ||||
|     return GRUB_USB_ERR_INTERNAL; | ||||
|   err = grub_usb_control_msg (dev, 1 << 7, | ||||
| 			      0x06, (3 << 8) | index, | ||||
| 			      langid, descstr.length, (char *) descstrp); | ||||
| 
 | ||||
|   if (descstrp->length == 0) | ||||
|     { | ||||
|       grub_free (descstrp); | ||||
|       *string = grub_strdup (""); | ||||
|       if (! *string) | ||||
| 	return GRUB_USB_ERR_INTERNAL; | ||||
|       return GRUB_USB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   *string = grub_malloc (descstr.length * 2 + 1); | ||||
|   if (! *string) | ||||
|     { | ||||
|       grub_free (descstrp); | ||||
|       return GRUB_USB_ERR_INTERNAL; | ||||
|     } | ||||
| 
 | ||||
|   *grub_utf16_to_utf8 ((grub_uint8_t *) *string, descstrp->str, | ||||
| 		       descstrp->length / 2 - 1) = 0; | ||||
|   grub_free (descstrp); | ||||
| 
 | ||||
|   return GRUB_USB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| usb_print_str (const char *description, grub_usb_device_t dev, int idx) | ||||
| { | ||||
|   char *name; | ||||
|   grub_usb_err_t err; | ||||
|   /* XXX: LANGID  */ | ||||
| 
 | ||||
|   if (! idx) | ||||
|     return; | ||||
| 
 | ||||
|   err = grub_usb_get_string (dev, idx, 0x0409, &name); | ||||
|   if (err) | ||||
|     grub_printf ("Error %d retrieving %s\n", err, description); | ||||
|   else | ||||
|     { | ||||
|       grub_printf ("%s: `%s'\n", description, name); | ||||
|       grub_free (name); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| usb_iterate (grub_usb_device_t dev) | ||||
| { | ||||
|   struct grub_usb_desc_device *descdev; | ||||
|   int i; | ||||
| 
 | ||||
|   descdev = &dev->descdev; | ||||
| 
 | ||||
|   usb_print_str ("Product", dev, descdev->strprod); | ||||
|   usb_print_str ("Vendor", dev, descdev->strvendor); | ||||
|   usb_print_str ("Serial", dev, descdev->strserial); | ||||
| 
 | ||||
|   grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n", | ||||
| 	       descdev->class, descdev->class < ARRAY_SIZE (usb_classes) | ||||
| 	       ? usb_classes[descdev->class] : "Unknown", | ||||
| 	       descdev->subclass, descdev->protocol); | ||||
|   grub_printf ("USB version %d.%d, VendorID: 0x%02x, ProductID: 0x%02x, #conf: %d\n", | ||||
| 	       descdev->usbrel >> 8, (descdev->usbrel >> 4) & 0x0F, | ||||
| 	       descdev->vendorid, descdev->prodid, descdev->configcnt); | ||||
| 
 | ||||
|   grub_printf ("%s speed device\n", usb_devspeed[dev->speed]); | ||||
| 
 | ||||
|   for (i = 0; i < descdev->configcnt; i++) | ||||
|     { | ||||
|       struct grub_usb_desc_config *config; | ||||
| 
 | ||||
|       config = dev->config[i].descconf; | ||||
|       usb_print_str ("Configuration:", dev, config->strconfig); | ||||
|     } | ||||
| 
 | ||||
|   for (i = 0; i < dev->config[0].descconf->numif; i++) | ||||
|     { | ||||
|       int j; | ||||
|       struct grub_usb_desc_if *interf; | ||||
|       interf = dev->config[0].interf[i].descif; | ||||
| 
 | ||||
|       grub_printf ("Interface #%d: #Endpoints: %d   ", | ||||
| 		   i, interf->endpointcnt); | ||||
|       grub_printf ("Class: (0x%02x) %s, Subclass: 0x%02x, Protocol: 0x%02x\n", | ||||
| 		   interf->class, interf->class < ARRAY_SIZE (usb_classes) | ||||
| 		   ? usb_classes[interf->class] : "Unknown", | ||||
| 		   interf->subclass, interf->protocol); | ||||
| 
 | ||||
|       usb_print_str ("Interface", dev, interf->strif); | ||||
| 
 | ||||
|       for (j = 0; j < interf->endpointcnt; j++) | ||||
| 	{ | ||||
| 	  struct grub_usb_desc_endp *endp; | ||||
| 	  endp = &dev->config[0].interf[i].descendp[j]; | ||||
| 
 | ||||
| 	  grub_printf ("Endpoint #%d: %s, max packed size: %d, transfer type: %s, latency: %d\n", | ||||
| 		       endp->endp_addr & 15, | ||||
| 		       (endp->endp_addr & 128) ? "IN" : "OUT", | ||||
| 		       endp->maxpacket, usb_endp_type[endp->attrib & 3], | ||||
| 		       endp->interval); | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   grub_printf("\n"); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_usbtest (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		  int argc __attribute__ ((unused)), | ||||
| 		  char **args __attribute__ ((unused))) | ||||
| { | ||||
|   grub_usb_poll_devices (); | ||||
| 
 | ||||
|   grub_printf ("USB devices:\n\n"); | ||||
|   grub_usb_iterate (usb_iterate); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(usbtest) | ||||
| { | ||||
|   cmd = grub_register_command ("usb", grub_cmd_usbtest, | ||||
| 			       0, N_("Test USB support.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(usbtest) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										193
									
								
								grub-core/commands/videotest.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								grub-core/commands/videotest.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,193 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/video.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/font.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <grub/gfxmenu_view.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), | ||||
|                     int argc __attribute__ ((unused)), | ||||
|                     char **args __attribute__ ((unused))) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   grub_video_color_t color; | ||||
|   unsigned int x; | ||||
|   unsigned int y; | ||||
|   unsigned int width; | ||||
|   unsigned int height; | ||||
|   int i; | ||||
|   struct grub_video_render_target *text_layer; | ||||
|   grub_video_color_t palette[16]; | ||||
| 
 | ||||
|   err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   grub_video_get_viewport (&x, &y, &width, &height); | ||||
| 
 | ||||
|   { | ||||
|     const char *str; | ||||
|     int texty; | ||||
|     grub_font_t sansbig; | ||||
|     grub_font_t sans; | ||||
|     grub_font_t sanssmall; | ||||
|     grub_font_t fixed; | ||||
|     struct grub_font_glyph *glyph; | ||||
| 
 | ||||
|     grub_video_create_render_target (&text_layer, width, height, | ||||
| 				     GRUB_VIDEO_MODE_TYPE_RGB | ||||
| 				     | GRUB_VIDEO_MODE_TYPE_ALPHA); | ||||
| 
 | ||||
|     grub_video_set_active_render_target (text_layer); | ||||
| 
 | ||||
|     color = grub_video_map_rgb (0, 255, 255); | ||||
|     sansbig = grub_font_get ("Unknown Regular 16"); | ||||
|     sans = grub_font_get ("Unknown Regular 16"); | ||||
|     sanssmall = grub_font_get ("Unknown Regular 16"); | ||||
|     fixed = grub_font_get ("Fixed 20"); | ||||
|     if (! sansbig || ! sans || ! sanssmall || ! fixed) | ||||
|       return grub_error (GRUB_ERR_BAD_FONT, "no font loaded"); | ||||
| 
 | ||||
|     glyph = grub_font_get_glyph (fixed, '*'); | ||||
|     grub_font_draw_glyph (glyph, color, 200 ,0); | ||||
| 
 | ||||
|     color = grub_video_map_rgb (255, 255, 255); | ||||
| 
 | ||||
|     texty = 32; | ||||
|     grub_font_draw_string ("The quick brown fox jumped over the lazy dog.", | ||||
| 			   sans, color, 16, texty); | ||||
|     texty += grub_font_get_descent (sans) + grub_font_get_leading (sans); | ||||
| 
 | ||||
|     texty += grub_font_get_ascent (fixed); | ||||
|     grub_font_draw_string ("The quick brown fox jumped over the lazy dog.", | ||||
| 			   fixed, color, 16, texty); | ||||
|     texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed); | ||||
| 
 | ||||
|     /* To convert Unicode characters into UTF-8 for this test, the following
 | ||||
|        command is useful: | ||||
|        echo -ne '\x00\x00\x26\x3A' | iconv -f UTF-32BE -t UTF-8 | od -t x1 | ||||
|        This converts the Unicode character U+263A to UTF-8.  */ | ||||
| 
 | ||||
|     /* Characters used:
 | ||||
|        Code point  Description                    UTF-8 encoding | ||||
|        ----------- ------------------------------ -------------- | ||||
|        U+263A      unfilled smiley face           E2 98 BA | ||||
|        U+00A1      inverted exclamation point     C2 A1 | ||||
|        U+00A3      British pound currency symbol  C2 A3 | ||||
|        U+03C4      Greek tau                      CF 84 | ||||
|        U+00E4      lowercase letter a with umlaut C3 A4 | ||||
|        U+2124      set 'Z' symbol (integers)      E2 84 A4 | ||||
|        U+2287      subset symbol                  E2 8A 87 | ||||
|        U+211D      set 'R' symbol (real numbers)  E2 84 9D  */ | ||||
| 
 | ||||
|     str = | ||||
|       "Unicode test: happy\xE2\x98\xBA \xC2\xA3 5.00" | ||||
|       " \xC2\xA1\xCF\x84\xC3\xA4u! " | ||||
|       " \xE2\x84\xA4\xE2\x8A\x87\xE2\x84\x9D"; | ||||
|     color = grub_video_map_rgb (128, 128, 255); | ||||
| 
 | ||||
|     /* All characters in the string exist in the 'Fixed 20' (10x20) font.  */ | ||||
|     texty += grub_font_get_ascent(fixed); | ||||
|     grub_font_draw_string (str, fixed, color, 16, texty); | ||||
|     texty += grub_font_get_descent (fixed) + grub_font_get_leading (fixed); | ||||
| 
 | ||||
|     texty += grub_font_get_ascent(sansbig); | ||||
|     grub_font_draw_string (str, sansbig, color, 16, texty); | ||||
|     texty += grub_font_get_descent (sansbig) + grub_font_get_leading (sansbig); | ||||
| 
 | ||||
|     texty += grub_font_get_ascent(sans); | ||||
|     grub_font_draw_string (str, sans, color, 16, texty); | ||||
|     texty += grub_font_get_descent (sans) + grub_font_get_leading (sans); | ||||
| 
 | ||||
|     texty += grub_font_get_ascent(sanssmall); | ||||
|     grub_font_draw_string (str, sanssmall, color, 16, texty); | ||||
|     texty += (grub_font_get_descent (sanssmall) | ||||
| 	      + grub_font_get_leading (sanssmall)); | ||||
| 
 | ||||
|     glyph = grub_font_get_glyph (fixed, '*'); | ||||
| 
 | ||||
|     for (i = 0; i < 16; i++) | ||||
|       { | ||||
| 	color = grub_video_map_color (i); | ||||
| 	palette[i] = color; | ||||
| 	grub_font_draw_glyph (glyph, color, 16 + i * 16, 220); | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
|   grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); | ||||
| 
 | ||||
|   for (i = 0; i < 2; i++) | ||||
|     { | ||||
|       color = grub_video_map_rgb (0, 0, 0); | ||||
|       grub_video_fill_rect (color, 0, 0, width, height); | ||||
| 
 | ||||
|       color = grub_video_map_rgb (255, 0, 0); | ||||
|       grub_video_fill_rect (color, 0, 0, 100, 100); | ||||
| 
 | ||||
|       color = grub_video_map_rgb (0, 255, 255); | ||||
|       grub_video_fill_rect (color, 100, 100, 100, 100); | ||||
| 
 | ||||
|       grub_video_set_viewport (x + 150, y + 150, | ||||
| 			       width - 150 * 2, height - 150 * 2); | ||||
|       color = grub_video_map_rgb (77, 33, 77); | ||||
|       grub_video_fill_rect (color, 0, 0, width, height); | ||||
|       grub_video_swap_buffers (); | ||||
|     } | ||||
| 
 | ||||
|   for (i = 0; i < 5; i++) | ||||
|     { | ||||
|       color = grub_video_map_rgb (i, 33, 77); | ||||
|       grub_video_fill_rect (color, 0, 0, width, height); | ||||
|       grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, 0, 0, | ||||
|                                      0, 0, width, height); | ||||
|       grub_video_swap_buffers (); | ||||
|     } | ||||
| 
 | ||||
|   grub_getkey (); | ||||
| 
 | ||||
|   grub_video_delete_render_target (text_layer); | ||||
| 
 | ||||
|   grub_video_restore (); | ||||
| 
 | ||||
|   for (i = 0; i < 16; i++) | ||||
|     grub_printf("color %d: %08x\n", i, palette[i]); | ||||
| 
 | ||||
|   grub_errno = GRUB_ERR_NONE; | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(videotest) | ||||
| { | ||||
|   cmd = grub_register_command ("videotest", grub_cmd_videotest, | ||||
| 			       0, N_("Test video subsystem.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(videotest) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										100
									
								
								grub-core/commands/xnu_uuid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								grub-core/commands/xnu_uuid.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| /* xnu_uuid.c - transform 64-bit serial number
 | ||||
|    to 128-bit uuid suitable for xnu. */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 1995,1996,1998,1999,2001,2002, | ||||
|  *                2003, 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/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/device.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/fs.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/env.h> | ||||
| #include <grub/command.h> | ||||
| #include <grub/i18n.h> | ||||
| #include <grub/crypto.h> | ||||
| 
 | ||||
| /* This prefix is used by xnu and boot-132 to hash
 | ||||
|    together with volume serial. */ | ||||
| static grub_uint8_t hash_prefix[16] | ||||
|   = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, | ||||
|      0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), | ||||
| 		   int argc, char **args) | ||||
| { | ||||
|   grub_uint64_t serial; | ||||
|   grub_uint8_t *xnu_uuid; | ||||
|   char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; | ||||
|   char *ptr; | ||||
|   grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); | ||||
| 
 | ||||
|   serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); | ||||
| 
 | ||||
|   GRUB_MD_MD5->init (&ctx); | ||||
|   GRUB_MD_MD5->write (&ctx, hash_prefix, sizeof (hash_prefix)); | ||||
|   GRUB_MD_MD5->write (&ctx, &serial, sizeof (serial)); | ||||
|   GRUB_MD_MD5->final (&ctx); | ||||
|   xnu_uuid = GRUB_MD_MD5->read (&ctx); | ||||
| 
 | ||||
|   grub_snprintf (uuid_string, sizeof (uuid_string), | ||||
| 		"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | ||||
| 		(unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], | ||||
| 		(unsigned int) xnu_uuid[2], (unsigned int) xnu_uuid[3], | ||||
| 		(unsigned int) xnu_uuid[4], (unsigned int) xnu_uuid[5], | ||||
| 		(unsigned int) ((xnu_uuid[6] & 0xf) | 0x30), | ||||
| 		(unsigned int) xnu_uuid[7], | ||||
| 		(unsigned int) ((xnu_uuid[8] & 0x3f) | 0x80), | ||||
| 		(unsigned int) xnu_uuid[9], | ||||
| 		(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 (argc == 1) | ||||
|     grub_printf ("%s", uuid_string); | ||||
|   if (argc > 1) | ||||
|     grub_env_set (args[1], uuid_string); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_command_t cmd; | ||||
| 
 | ||||
| 
 | ||||
| GRUB_MOD_INIT (xnu_uuid) | ||||
| { | ||||
|   cmd = grub_register_command ("xnu_uuid", grub_cmd_xnu_uuid, | ||||
| 			       N_("GRUBUUID [VARNAME]"), | ||||
| 			       N_("Transform 64-bit UUID to format " | ||||
| 			       "suitable for XNU.")); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (xnu_uuid) | ||||
| { | ||||
|   grub_unregister_command (cmd); | ||||
| } | ||||
							
								
								
									
										917
									
								
								grub-core/disk/ata.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										917
									
								
								grub-core/disk/ata.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,917 @@ | |||
| /* ata.c - ATA disk access.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007, 2008, 2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/ata.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/time.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/scsi.h> | ||||
| #include <grub/cs5536.h> | ||||
| 
 | ||||
| /* At the moment, only two IDE ports are supported.  */ | ||||
| static const grub_port_t grub_ata_ioaddress[] = { GRUB_ATA_CH0_PORT1, | ||||
| 						  GRUB_ATA_CH1_PORT1 }; | ||||
| static const grub_port_t grub_ata_ioaddress2[] = { GRUB_ATA_CH0_PORT2,  | ||||
| 						   GRUB_ATA_CH1_PORT2 }; | ||||
| 
 | ||||
| static struct grub_ata_device *grub_ata_devices; | ||||
| 
 | ||||
| /* Wait for !BSY.  */ | ||||
| grub_err_t | ||||
| grub_ata_wait_not_busy (struct grub_ata_device *dev, int milliseconds) | ||||
| { | ||||
|   /* ATA requires 400ns (after a write to CMD register) or
 | ||||
|      1 PIO cycle (after a DRQ block transfer) before | ||||
|      first check of BSY.  */ | ||||
|   grub_millisleep (1); | ||||
| 
 | ||||
|   int i = 1; | ||||
|   grub_uint8_t sts; | ||||
|   while ((sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS)) | ||||
| 	 & GRUB_ATA_STATUS_BUSY) | ||||
|     { | ||||
|       if (i >= milliseconds) | ||||
|         { | ||||
| 	  grub_dprintf ("ata", "timeout: %dms, status=0x%x\n", | ||||
| 			milliseconds, sts); | ||||
| 	  return grub_error (GRUB_ERR_TIMEOUT, "ATA timeout"); | ||||
| 	} | ||||
| 
 | ||||
|       grub_millisleep (1); | ||||
|       i++; | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| grub_ata_wait (void) | ||||
| { | ||||
|   grub_millisleep (50); | ||||
| } | ||||
| 
 | ||||
| /* Wait for !BSY, DRQ.  */ | ||||
| grub_err_t | ||||
| grub_ata_wait_drq (struct grub_ata_device *dev, int rw, | ||||
| 		   int milliseconds) | ||||
| { | ||||
|   if (grub_ata_wait_not_busy (dev, milliseconds)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* !DRQ implies error condition.  */ | ||||
|   grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); | ||||
|   if ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) | ||||
|       != GRUB_ATA_STATUS_DRQ) | ||||
|     { | ||||
|       grub_dprintf ("ata", "ata error: status=0x%x, error=0x%x\n", | ||||
| 		    sts, grub_ata_regget (dev, GRUB_ATA_REG_ERROR)); | ||||
|       if (! rw) | ||||
|         return grub_error (GRUB_ERR_READ_ERROR, "ATA read error"); | ||||
|       else | ||||
|         return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error"); | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| /* Byteorder has to be changed before strings can be read.  */ | ||||
| static void | ||||
| grub_ata_strncpy (char *dst, char *src, grub_size_t len) | ||||
| { | ||||
|   grub_uint16_t *src16 = (grub_uint16_t *) src; | ||||
|   grub_uint16_t *dst16 = (grub_uint16_t *) dst; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   for (i = 0; i < len / 2; i++) | ||||
|     *(dst16++) = grub_be_to_cpu16 (*(src16++)); | ||||
|   dst[len] = '\0'; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_ata_pio_read (struct grub_ata_device *dev, char *buf, grub_size_t size) | ||||
| { | ||||
|   grub_uint16_t *buf16 = (grub_uint16_t *) buf; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   /* Read in the data, word by word.  */ | ||||
|   for (i = 0; i < size / 2; i++) | ||||
|     buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA)); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_ata_pio_write (struct grub_ata_device *dev, char *buf, grub_size_t size) | ||||
| { | ||||
|   grub_uint16_t *buf16 = (grub_uint16_t *) buf; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   /* Write the data, word by word.  */ | ||||
|   for (i = 0; i < size / 2; i++) | ||||
|     grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_ata_dumpinfo (struct grub_ata_device *dev, char *info) | ||||
| { | ||||
|   char text[41]; | ||||
| 
 | ||||
|   /* The device information was read, dump it for debugging.  */ | ||||
|   grub_ata_strncpy (text, info + 20, 20); | ||||
|   grub_dprintf ("ata", "Serial: %s\n", text); | ||||
|   grub_ata_strncpy (text, info + 46, 8); | ||||
|   grub_dprintf ("ata", "Firmware: %s\n", text); | ||||
|   grub_ata_strncpy (text, info + 54, 40); | ||||
|   grub_dprintf ("ata", "Model: %s\n", text); | ||||
| 
 | ||||
|   if (! dev->atapi) | ||||
|     { | ||||
|       grub_dprintf ("ata", "Addressing: %d\n", dev->addr); | ||||
|       grub_dprintf ("ata", "Sectors: %lld\n", (unsigned long long) dev->size); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_atapi_identify (struct grub_ata_device *dev) | ||||
| { | ||||
|   char *info; | ||||
| 
 | ||||
|   info = grub_malloc (GRUB_DISK_SECTOR_SIZE); | ||||
|   if (! info) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4); | ||||
|   grub_ata_wait (); | ||||
|   if (grub_ata_check_ready (dev)) | ||||
|     { | ||||
|       grub_free (info); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_PACKET_DEVICE); | ||||
|   grub_ata_wait (); | ||||
| 
 | ||||
|   if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD)) | ||||
|     { | ||||
|       grub_free (info); | ||||
|       return grub_errno; | ||||
|     } | ||||
|   grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE); | ||||
| 
 | ||||
|   dev->atapi = 1; | ||||
| 
 | ||||
|   grub_ata_dumpinfo (dev, info); | ||||
| 
 | ||||
|   grub_free (info); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_atapi_wait_drq (struct grub_ata_device *dev, | ||||
| 		     grub_uint8_t ireason, | ||||
| 		     int milliseconds) | ||||
| { | ||||
|   /* Wait for !BSY, DRQ, ireason */ | ||||
|   if (grub_ata_wait_not_busy (dev, milliseconds)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); | ||||
|   grub_uint8_t irs = grub_ata_regget (dev, GRUB_ATAPI_REG_IREASON); | ||||
| 
 | ||||
|   /* OK if DRQ is asserted and interrupt reason is as expected.  */ | ||||
|   if ((sts & GRUB_ATA_STATUS_DRQ) | ||||
|       && (irs & GRUB_ATAPI_IREASON_MASK) == ireason) | ||||
|     return GRUB_ERR_NONE; | ||||
| 
 | ||||
|   /* !DRQ implies error condition.  */ | ||||
|   grub_dprintf ("ata", "atapi error: status=0x%x, ireason=0x%x, error=0x%x\n", | ||||
| 	        sts, irs, grub_ata_regget (dev, GRUB_ATA_REG_ERROR)); | ||||
| 
 | ||||
|   if (! (sts & GRUB_ATA_STATUS_DRQ) | ||||
|       && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_ERROR) | ||||
|     { | ||||
|       if (ireason == GRUB_ATAPI_IREASON_CMD_OUT) | ||||
| 	return grub_error (GRUB_ERR_READ_ERROR, "ATA PACKET command error"); | ||||
|       else | ||||
| 	return grub_error (GRUB_ERR_READ_ERROR, "ATAPI read error"); | ||||
|     } | ||||
| 
 | ||||
|   return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error"); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_atapi_packet (struct grub_ata_device *dev, char *packet, | ||||
| 		   grub_size_t size) | ||||
| { | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); | ||||
|   if (grub_ata_check_ready (dev)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* Send ATA PACKET command.  */ | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_FEATURES, 0); | ||||
|   grub_ata_regset (dev, GRUB_ATAPI_REG_IREASON, 0); | ||||
|   grub_ata_regset (dev, GRUB_ATAPI_REG_CNTHIGH, size >> 8); | ||||
|   grub_ata_regset (dev, GRUB_ATAPI_REG_CNTLOW, size & 0xFF); | ||||
| 
 | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_PACKET); | ||||
| 
 | ||||
|   /* Wait for !BSY, DRQ, !I/O, C/D.  */ | ||||
|   if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_CMD_OUT, GRUB_ATA_TOUT_STD)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* Write the packet.  */ | ||||
|   grub_ata_pio_write (dev, packet, 12); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_identify (struct grub_ata_device *dev) | ||||
| { | ||||
|   char *info; | ||||
|   grub_uint16_t *info16; | ||||
| 
 | ||||
|   info = grub_malloc (GRUB_DISK_SECTOR_SIZE); | ||||
|   if (! info) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   info16 = (grub_uint16_t *) info; | ||||
| 
 | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | dev->device << 4); | ||||
|   grub_ata_wait (); | ||||
|   if (grub_ata_check_ready (dev)) | ||||
|     { | ||||
|       grub_free (info); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_CMD, GRUB_ATA_CMD_IDENTIFY_DEVICE); | ||||
|   grub_ata_wait (); | ||||
| 
 | ||||
|   if (grub_ata_wait_drq (dev, 0, GRUB_ATA_TOUT_STD)) | ||||
|     { | ||||
|       grub_free (info); | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|       grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); | ||||
| 
 | ||||
|       if ((sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | ||||
| 	  | GRUB_ATA_STATUS_ERR)) == GRUB_ATA_STATUS_ERR | ||||
| 	  && (grub_ata_regget (dev, GRUB_ATA_REG_ERROR) & 0x04 /* ABRT */)) | ||||
| 	/* Device without ATA IDENTIFY, try ATAPI.  */ | ||||
| 	return grub_atapi_identify (dev); | ||||
| 
 | ||||
|       else if (sts == 0x00) | ||||
| 	/* No device, return error but don't print message.  */ | ||||
| 	return GRUB_ERR_UNKNOWN_DEVICE; | ||||
| 
 | ||||
|       else | ||||
| 	/* Other Error.  */ | ||||
| 	return grub_error (GRUB_ERR_UNKNOWN_DEVICE, | ||||
| 			   "device cannot be identified"); | ||||
|     } | ||||
| 
 | ||||
|   grub_ata_pio_read (dev, info, GRUB_DISK_SECTOR_SIZE); | ||||
| 
 | ||||
|   /* Re-check status to avoid bogus identify data due to stuck DRQ.  */ | ||||
|   grub_uint8_t sts = grub_ata_regget (dev, GRUB_ATA_REG_STATUS); | ||||
|   if (sts & (GRUB_ATA_STATUS_BUSY | GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) | ||||
|     { | ||||
|       grub_dprintf ("ata", "bad status=0x%x\n", sts); | ||||
|       grub_free (info); | ||||
|       /* No device, return error but don't print message.  */ | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|       return GRUB_ERR_UNKNOWN_DEVICE; | ||||
|     } | ||||
| 
 | ||||
|   /* Now it is certain that this is not an ATAPI device.  */ | ||||
|   dev->atapi = 0; | ||||
| 
 | ||||
|   /* CHS is always supported.  */ | ||||
|   dev->addr = GRUB_ATA_CHS; | ||||
| 
 | ||||
|   /* Check if LBA is supported.  */ | ||||
|   if (info16[49] & (1 << 9)) | ||||
|     { | ||||
|       /* Check if LBA48 is supported.  */ | ||||
|       if (info16[83] & (1 << 10)) | ||||
| 	dev->addr = GRUB_ATA_LBA48; | ||||
|       else | ||||
| 	dev->addr = GRUB_ATA_LBA; | ||||
|     } | ||||
| 
 | ||||
|   /* Determine the amount of sectors.  */ | ||||
|   if (dev->addr != GRUB_ATA_LBA48) | ||||
|     dev->size = grub_le_to_cpu32(*((grub_uint32_t *) &info16[60])); | ||||
|   else | ||||
|     dev->size = grub_le_to_cpu64(*((grub_uint64_t *) &info16[100])); | ||||
| 
 | ||||
|   /* Read CHS information.  */ | ||||
|   dev->cylinders = info16[1]; | ||||
|   dev->heads = info16[3]; | ||||
|   dev->sectors_per_track = info16[6]; | ||||
| 
 | ||||
|   grub_ata_dumpinfo (dev, info); | ||||
| 
 | ||||
|   grub_free(info); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| check_device (struct grub_ata_device *dev) | ||||
| { | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); | ||||
|   grub_ata_wait (); | ||||
| 
 | ||||
|   /* Try to detect if the port is in use by writing to it,
 | ||||
|      waiting for a while and reading it again.  If the value | ||||
|      was preserved, there is a device connected.  */ | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A); | ||||
|   grub_ata_wait (); | ||||
|   grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS); | ||||
|   grub_dprintf ("ata", "sectors=0x%x\n", sec); | ||||
|   if (sec != 0x5A) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected"); | ||||
| 
 | ||||
|   /* The above test may detect a second (slave) device
 | ||||
|      connected to a SATA controller which supports only one | ||||
|      (master) device.  It is not safe to use the status register | ||||
|      READY bit to check for controller channel existence.  Some | ||||
|      ATAPI commands (RESET, DIAGNOSTIC) may clear this bit.  */ | ||||
| 
 | ||||
|   /* Use the IDENTIFY DEVICE command to query the device.  */ | ||||
|   return grub_ata_identify (dev); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_device_initialize (int port, int device, int addr, int addr2) | ||||
| { | ||||
|   struct grub_ata_device *dev; | ||||
|   struct grub_ata_device **devp; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n", | ||||
| 		port, device, addr, addr2); | ||||
| 
 | ||||
|   dev = grub_malloc (sizeof(*dev)); | ||||
|   if (! dev) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* Setup the device information.  */ | ||||
|   dev->port = port; | ||||
|   dev->device = device; | ||||
|   dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE; | ||||
|   dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE; | ||||
|   dev->next = NULL; | ||||
| 
 | ||||
|   /* Register the device.  */ | ||||
|   for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next); | ||||
|   *devp = dev; | ||||
| 
 | ||||
|   err = check_device (dev); | ||||
|   if (err) | ||||
|     grub_print_error (); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int NESTED_FUNC_ATTR | ||||
| grub_ata_pciinit (grub_pci_device_t dev, | ||||
| 		  grub_pci_id_t pciid) | ||||
| { | ||||
|   static int compat_use[2] = { 0 }; | ||||
|   grub_pci_address_t addr; | ||||
|   grub_uint32_t class; | ||||
|   grub_uint32_t bar1; | ||||
|   grub_uint32_t bar2; | ||||
|   int rega; | ||||
|   int regb; | ||||
|   int i; | ||||
|   static int controller = 0; | ||||
|   int cs5536 = 0; | ||||
|   int nports = 2; | ||||
| 
 | ||||
|   /* Read class.  */ | ||||
|   addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); | ||||
|   class = grub_pci_read (addr); | ||||
| 
 | ||||
|   /* AMD CS5536 Southbridge.  */ | ||||
|   if (pciid == GRUB_CS5536_PCIID) | ||||
|     { | ||||
|       cs5536 = 1; | ||||
|       nports = 1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if this class ID matches that of a PCI IDE Controller.  */ | ||||
|   if (!cs5536 && (class >> 16 != 0x0101)) | ||||
|     return 0; | ||||
| 
 | ||||
|   for (i = 0; i < nports; i++) | ||||
|     { | ||||
|       /* Set to 0 when the channel operated in compatibility mode.  */ | ||||
|       int compat; | ||||
| 
 | ||||
|       /* We don't support non-compatibility mode for CS5536.  */ | ||||
|       if (cs5536) | ||||
| 	compat = 0; | ||||
|       else | ||||
| 	compat = (class >> (8 + 2 * i)) & 1; | ||||
| 
 | ||||
|       rega = 0; | ||||
|       regb = 0; | ||||
| 
 | ||||
|       /* If the channel is in compatibility mode, just assign the
 | ||||
| 	 default registers.  */ | ||||
|       if (compat == 0 && !compat_use[i]) | ||||
| 	{ | ||||
| 	  rega = grub_ata_ioaddress[i]; | ||||
| 	  regb = grub_ata_ioaddress2[i]; | ||||
| 	  compat_use[i] = 1; | ||||
| 	} | ||||
|       else if (compat) | ||||
| 	{ | ||||
| 	  /* Read the BARs, which either contain a mmapped IO address
 | ||||
| 	     or the IO port address.  */ | ||||
| 	  addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES | ||||
| 					+ sizeof (grub_uint64_t) * i); | ||||
| 	  bar1 = grub_pci_read (addr); | ||||
| 	  addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES | ||||
| 					+ sizeof (grub_uint64_t) * i | ||||
| 					+ sizeof (grub_uint32_t)); | ||||
| 	  bar2 = grub_pci_read (addr); | ||||
| 
 | ||||
| 	  /* Check if the BARs describe an IO region.  */ | ||||
| 	  if ((bar1 & 1) && (bar2 & 1)) | ||||
| 	    { | ||||
| 	      rega = bar1 & ~3; | ||||
| 	      regb = bar2 & ~3; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       grub_dprintf ("ata", | ||||
| 		    "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n", | ||||
| 		    grub_pci_get_bus (dev), grub_pci_get_device (dev), | ||||
| 		    grub_pci_get_function (dev), compat, rega, regb); | ||||
| 
 | ||||
|       if (rega && regb) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  grub_ata_device_initialize (controller * 2 + i, 0, rega, regb); | ||||
| 
 | ||||
| 	  /* Most errors raised by grub_ata_device_initialize() are harmless.
 | ||||
| 	     They just indicate this particular drive is not responding, most | ||||
| 	     likely because it doesn't exist.  We might want to ignore specific | ||||
| 	     error types here, instead of printing them.  */ | ||||
| 	  if (grub_errno) | ||||
| 	    { | ||||
| 	      grub_print_error (); | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	    } | ||||
| 
 | ||||
| 	  grub_ata_device_initialize (controller * 2 + i, 1, rega, regb); | ||||
| 
 | ||||
| 	  /* Likewise.  */ | ||||
| 	  if (grub_errno) | ||||
| 	    { | ||||
| 	      grub_print_error (); | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   controller++; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_initialize (void) | ||||
| { | ||||
|   grub_pci_iterate (grub_ata_pciinit); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_ata_setlba (struct grub_ata_device *dev, grub_disk_addr_t sector, | ||||
| 		 grub_size_t size) | ||||
| { | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, size); | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_LBALOW, sector & 0xFF); | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_LBAMID, (sector >> 8) & 0xFF); | ||||
|   grub_ata_regset (dev, GRUB_ATA_REG_LBAHIGH, (sector >> 16) & 0xFF); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_setaddress (struct grub_ata_device *dev, | ||||
| 		     grub_ata_addressing_t addressing, | ||||
| 		     grub_disk_addr_t sector, | ||||
| 		     grub_size_t size) | ||||
| { | ||||
|   switch (addressing) | ||||
|     { | ||||
|     case GRUB_ATA_CHS: | ||||
|       { | ||||
| 	unsigned int cylinder; | ||||
| 	unsigned int head; | ||||
| 	unsigned int sect; | ||||
| 
 | ||||
| 	/* Calculate the sector, cylinder and head to use.  */ | ||||
| 	sect = ((grub_uint32_t) sector % dev->sectors_per_track) + 1; | ||||
| 	cylinder = (((grub_uint32_t) sector / dev->sectors_per_track) | ||||
| 		    / dev->heads); | ||||
| 	head = ((grub_uint32_t) sector / dev->sectors_per_track) % dev->heads; | ||||
| 
 | ||||
| 	if (sect > dev->sectors_per_track | ||||
| 	    || cylinder > dev->cylinders | ||||
| 	    || head > dev->heads) | ||||
| 	  return grub_error (GRUB_ERR_OUT_OF_RANGE, | ||||
| 			     "sector %d cannot be addressed " | ||||
| 			     "using CHS addressing", sector); | ||||
| 
 | ||||
| 	grub_ata_regset (dev, GRUB_ATA_REG_DISK, (dev->device << 4) | head); | ||||
| 	if (grub_ata_check_ready (dev)) | ||||
| 	  return grub_errno; | ||||
| 
 | ||||
| 	grub_ata_regset (dev, GRUB_ATA_REG_SECTNUM, sect); | ||||
| 	grub_ata_regset (dev, GRUB_ATA_REG_CYLLSB, cylinder & 0xFF); | ||||
| 	grub_ata_regset (dev, GRUB_ATA_REG_CYLMSB, cylinder >> 8); | ||||
| 
 | ||||
| 	break; | ||||
|       } | ||||
| 
 | ||||
|     case GRUB_ATA_LBA: | ||||
|       if (size == 256) | ||||
| 	size = 0; | ||||
|       grub_ata_regset (dev, GRUB_ATA_REG_DISK, | ||||
| 		       0xE0 | (dev->device << 4) | ((sector >> 24) & 0x0F)); | ||||
|       if (grub_ata_check_ready (dev)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       grub_ata_setlba (dev, sector, size); | ||||
|       break; | ||||
| 
 | ||||
|     case GRUB_ATA_LBA48: | ||||
|       if (size == 65536) | ||||
| 	size = 0; | ||||
| 
 | ||||
|       grub_ata_regset (dev, GRUB_ATA_REG_DISK, 0xE0 | (dev->device << 4)); | ||||
|       if (grub_ata_check_ready (dev)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       /* Set "Previous".  */ | ||||
|       grub_ata_setlba (dev, sector >> 24, size >> 8); | ||||
|       /* Set "Current".  */ | ||||
|       grub_ata_setlba (dev, sector, size); | ||||
| 
 | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		    grub_size_t size, char *buf, int rw) | ||||
| { | ||||
|   struct grub_ata_device *dev = (struct grub_ata_device *) disk->data; | ||||
| 
 | ||||
|   grub_dprintf("ata", "grub_ata_readwrite (size=%llu, rw=%d)\n", (unsigned long long) size, rw); | ||||
| 
 | ||||
|   grub_ata_addressing_t addressing = dev->addr; | ||||
|   grub_size_t batch; | ||||
|   int cmd, cmd_write; | ||||
| 
 | ||||
|   if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0) | ||||
|     { | ||||
|       batch = 65536; | ||||
|       cmd = GRUB_ATA_CMD_READ_SECTORS_EXT; | ||||
|       cmd_write = GRUB_ATA_CMD_WRITE_SECTORS_EXT; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       if (addressing == GRUB_ATA_LBA48) | ||||
| 	addressing = GRUB_ATA_LBA; | ||||
|       batch = 256; | ||||
|       cmd = GRUB_ATA_CMD_READ_SECTORS; | ||||
|       cmd_write = GRUB_ATA_CMD_WRITE_SECTORS; | ||||
|     } | ||||
| 
 | ||||
|   grub_size_t nsectors = 0; | ||||
|   while (nsectors < size) | ||||
|     { | ||||
|       if (size - nsectors < batch) | ||||
| 	batch = size - nsectors; | ||||
| 
 | ||||
|       grub_dprintf("ata", "rw=%d, sector=%llu, batch=%llu\n", rw, (unsigned long long) sector, (unsigned long long) batch); | ||||
| 
 | ||||
|       /* Send read/write command.  */ | ||||
|       if (grub_ata_setaddress (dev, addressing, sector, batch)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       grub_ata_regset (dev, GRUB_ATA_REG_CMD, (! rw ? cmd : cmd_write)); | ||||
| 
 | ||||
|       unsigned sect; | ||||
|       for (sect = 0; sect < batch; sect++) | ||||
| 	{ | ||||
| 	  /* Wait for !BSY, DRQ.  */ | ||||
| 	  if (grub_ata_wait_drq (dev, rw, GRUB_ATA_TOUT_DATA)) | ||||
| 	    return grub_errno; | ||||
| 
 | ||||
| 	  /* Transfer data.  */ | ||||
| 	  if (! rw) | ||||
| 	    grub_ata_pio_read (dev, buf, GRUB_DISK_SECTOR_SIZE); | ||||
| 	  else | ||||
| 	    grub_ata_pio_write (dev, buf, GRUB_DISK_SECTOR_SIZE); | ||||
| 
 | ||||
| 	  buf += GRUB_DISK_SECTOR_SIZE; | ||||
| 	} | ||||
| 
 | ||||
|       if (rw) | ||||
|         { | ||||
| 	  /* Check for write error.  */ | ||||
| 	  if (grub_ata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) | ||||
| 	    return grub_errno; | ||||
| 
 | ||||
| 	  if (grub_ata_regget (dev, GRUB_ATA_REG_STATUS) | ||||
| 	      & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) | ||||
| 	    return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error"); | ||||
| 	} | ||||
| 
 | ||||
|       sector += batch; | ||||
|       nsectors += batch; | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| static int | ||||
| grub_ata_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   struct grub_ata_device *dev; | ||||
| 
 | ||||
|   for (dev = grub_ata_devices; dev; dev = dev->next) | ||||
|     { | ||||
|       char devname[10]; | ||||
|       grub_err_t err; | ||||
| 
 | ||||
|       err = check_device (dev); | ||||
|       if (err) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  continue; | ||||
| 	} | ||||
| 
 | ||||
|       if (dev->atapi) | ||||
| 	continue; | ||||
| 
 | ||||
|       grub_snprintf (devname, sizeof (devname),  | ||||
| 		     "ata%d", dev->port * 2 + dev->device); | ||||
| 
 | ||||
|       if (hook (devname)) | ||||
| 	return 1; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   struct grub_ata_device *dev; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   for (dev = grub_ata_devices; dev; dev = dev->next) | ||||
|     { | ||||
|       char devname[10]; | ||||
|       grub_snprintf (devname, sizeof (devname), | ||||
| 		     "ata%d", dev->port * 2 + dev->device); | ||||
|       if (grub_strcmp (name, devname) == 0) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   if (! dev) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); | ||||
| 
 | ||||
|   if (dev->atapi) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk"); | ||||
| 
 | ||||
|   err = check_device (dev); | ||||
| 
 | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   disk->total_sectors = dev->size; | ||||
| 
 | ||||
|   disk->id = (unsigned long) dev; | ||||
| 
 | ||||
|   disk->has_partitions = 1; | ||||
|   disk->data = dev; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_ata_close (grub_disk_t disk __attribute__((unused))) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 	       grub_size_t size, char *buf) | ||||
| { | ||||
|   return grub_ata_readwrite (disk, sector, size, buf, 0); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ata_write (grub_disk_t disk, | ||||
| 		grub_disk_addr_t sector, | ||||
| 		grub_size_t size, | ||||
| 		const char *buf) | ||||
| { | ||||
|   return grub_ata_readwrite (disk, sector, size, (char *) buf, 1); | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_atadisk_dev = | ||||
|   { | ||||
|     .name = "ATA", | ||||
|     .id = GRUB_DISK_DEVICE_ATA_ID, | ||||
|     .iterate = grub_ata_iterate, | ||||
|     .open = grub_ata_open, | ||||
|     .close = grub_ata_close, | ||||
|     .read = grub_ata_read, | ||||
|     .write = grub_ata_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| /* ATAPI code.  */ | ||||
| 
 | ||||
| static int | ||||
| grub_atapi_iterate (int (*hook) (int bus, int luns)) | ||||
| { | ||||
|   struct grub_ata_device *dev; | ||||
| 
 | ||||
|   for (dev = grub_ata_devices; dev; dev = dev->next) | ||||
|     { | ||||
|       grub_err_t err; | ||||
| 
 | ||||
|       err = check_device (dev); | ||||
|       if (err) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  continue; | ||||
| 	} | ||||
| 
 | ||||
|       if (! dev->atapi) | ||||
| 	continue; | ||||
| 
 | ||||
|       if (hook (dev->port * 2 + dev->device, 1)) | ||||
| 	return 1; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_atapi_read (struct grub_scsi *scsi, | ||||
| 		 grub_size_t cmdsize __attribute__((unused)), | ||||
| 		 char *cmd, grub_size_t size, char *buf) | ||||
| { | ||||
|   struct grub_ata_device *dev = (struct grub_ata_device *) scsi->data; | ||||
| 
 | ||||
|   grub_dprintf("ata", "grub_atapi_read (size=%llu)\n", (unsigned long long) size); | ||||
| 
 | ||||
|   if (grub_atapi_packet (dev, cmd, size)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_size_t nread = 0; | ||||
|   while (nread < size) | ||||
|     { | ||||
|       /* Wait for !BSY, DRQ, I/O, !C/D.  */ | ||||
|       if (grub_atapi_wait_drq (dev, GRUB_ATAPI_IREASON_DATA_IN, GRUB_ATA_TOUT_DATA)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       /* Get byte count for this DRQ assertion.  */ | ||||
|       unsigned cnt = grub_ata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8 | ||||
| 		   | grub_ata_regget (dev, GRUB_ATAPI_REG_CNTLOW); | ||||
|       grub_dprintf("ata", "DRQ count=%u\n", cnt); | ||||
| 
 | ||||
|       /* Count of last transfer may be uneven.  */ | ||||
|       if (! (0 < cnt && cnt <= size - nread && (! (cnt & 1) || cnt == size - nread))) | ||||
| 	return grub_error (GRUB_ERR_READ_ERROR, "invalid ATAPI transfer count"); | ||||
| 
 | ||||
|       /* Read the data.  */ | ||||
|       grub_ata_pio_read (dev, buf + nread, cnt); | ||||
| 
 | ||||
|       if (cnt & 1) | ||||
| 	buf[nread + cnt - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress + GRUB_ATA_REG_DATA)); | ||||
| 
 | ||||
|       nread += cnt; | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_atapi_write (struct grub_scsi *scsi __attribute__((unused)), | ||||
| 		  grub_size_t cmdsize __attribute__((unused)), | ||||
| 		  char *cmd __attribute__((unused)), | ||||
| 		  grub_size_t size __attribute__((unused)), | ||||
| 		  char *buf __attribute__((unused))) | ||||
| { | ||||
|   // XXX: scsi.mod does not use write yet.
 | ||||
|   return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "ATAPI write not implemented"); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_atapi_open (int devnum, struct grub_scsi *scsi) | ||||
| { | ||||
|   struct grub_ata_device *dev; | ||||
|   struct grub_ata_device *devfnd = 0; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   for (dev = grub_ata_devices; dev; dev = dev->next) | ||||
|     { | ||||
|       if (dev->port * 2 + dev->device == devnum) | ||||
| 	{ | ||||
| 	  devfnd = dev; | ||||
| 	  break; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("ata", "opening ATAPI dev `ata%d'\n", devnum); | ||||
| 
 | ||||
|   if (! devfnd) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); | ||||
| 
 | ||||
|   err = check_device (devfnd); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   if (! devfnd->atapi) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); | ||||
| 
 | ||||
|   scsi->data = devfnd; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct grub_scsi_dev grub_atapi_dev = | ||||
|   { | ||||
|     .name = "ata", | ||||
|     .id = GRUB_SCSI_SUBSYSTEM_ATAPI, | ||||
|     .iterate = grub_atapi_iterate, | ||||
|     .open = grub_atapi_open, | ||||
|     .read = grub_atapi_read, | ||||
|     .write = grub_atapi_write | ||||
|   }; | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| GRUB_MOD_INIT(ata) | ||||
| { | ||||
|   /* To prevent two drivers operating on the same disks.  */ | ||||
|   grub_disk_firmware_is_tainted = 1; | ||||
|   if (grub_disk_firmware_fini) | ||||
|     { | ||||
|       grub_disk_firmware_fini (); | ||||
|       grub_disk_firmware_fini = NULL; | ||||
|     } | ||||
| 
 | ||||
|   /* ATA initialization.  */ | ||||
|   grub_ata_initialize (); | ||||
| 
 | ||||
|   grub_disk_dev_register (&grub_atadisk_dev); | ||||
| 
 | ||||
|   /* ATAPI devices are handled by scsi.mod.  */ | ||||
|   grub_scsi_dev_register (&grub_atapi_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(ata) | ||||
| { | ||||
|   grub_scsi_dev_unregister (&grub_atapi_dev); | ||||
|   grub_disk_dev_unregister (&grub_atadisk_dev); | ||||
| } | ||||
							
								
								
									
										107
									
								
								grub-core/disk/ata_pthru.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								grub-core/disk/ata_pthru.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| /* 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> | ||||
| 
 | ||||
| 
 | ||||
| /* 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; | ||||
| } | ||||
							
								
								
									
										169
									
								
								grub-core/disk/dmraid_nvidia.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								grub-core/disk/dmraid_nvidia.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,169 @@ | |||
| /* dmraid_nvidia.c - module to handle Nvidia fakeraid.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/raid.h> | ||||
| 
 | ||||
| #define NV_SIGNATURES		4 | ||||
| 
 | ||||
| #define NV_IDLE			0 | ||||
| #define NV_SCDB_INIT_RAID	2 | ||||
| #define NV_SCDB_REBUILD_RAID	3 | ||||
| #define NV_SCDB_UPGRADE_RAID	4 | ||||
| #define NV_SCDB_SYNC_RAID	5 | ||||
| 
 | ||||
| #define NV_LEVEL_UNKNOWN	0x00 | ||||
| #define NV_LEVEL_JBOD		0xFF | ||||
| #define NV_LEVEL_0		0x80 | ||||
| #define NV_LEVEL_1		0x81 | ||||
| #define NV_LEVEL_3		0x83 | ||||
| #define NV_LEVEL_5		0x85 | ||||
| #define NV_LEVEL_10		0x8a | ||||
| #define NV_LEVEL_1_0		0x8180 | ||||
| 
 | ||||
| #define NV_ARRAY_FLAG_BOOT		1 /* BIOS use only.  */ | ||||
| #define NV_ARRAY_FLAG_ERROR		2 /* Degraded or offline.  */ | ||||
| #define NV_ARRAY_FLAG_PARITY_VALID	4 /* RAID-3/5 parity valid.  */ | ||||
| 
 | ||||
| struct grub_nv_array | ||||
| { | ||||
|   grub_uint32_t version; | ||||
|   grub_uint32_t signature[NV_SIGNATURES]; | ||||
|   grub_uint8_t raid_job_code; | ||||
|   grub_uint8_t stripe_width; | ||||
|   grub_uint8_t total_volumes; | ||||
|   grub_uint8_t original_width; | ||||
|   grub_uint32_t raid_level; | ||||
|   grub_uint32_t stripe_block_size; | ||||
|   grub_uint32_t stripe_block_size_bytes; | ||||
|   grub_uint32_t stripe_block_size_log2; | ||||
|   grub_uint32_t stripe_mask; | ||||
|   grub_uint32_t stripe_size; | ||||
|   grub_uint32_t stripe_size_bytes; | ||||
|   grub_uint32_t raid_job_mask; | ||||
|   grub_uint32_t original_capacity; | ||||
|   grub_uint32_t flags; | ||||
| }; | ||||
| 
 | ||||
| #define NV_ID_LEN		8 | ||||
| #define NV_ID_STRING		"NVIDIA" | ||||
| #define NV_VERSION		100 | ||||
| 
 | ||||
| #define	NV_PRODID_LEN		16 | ||||
| #define	NV_PRODREV_LEN		4 | ||||
| 
 | ||||
| struct grub_nv_super | ||||
| { | ||||
|   char vendor[NV_ID_LEN];	/* 0x00 - 0x07 ID string.  */ | ||||
|   grub_uint32_t size;		/* 0x08 - 0x0B Size of metadata in dwords.  */ | ||||
|   grub_uint32_t chksum;		/* 0x0C - 0x0F Checksum of this struct.  */ | ||||
|   grub_uint16_t version;	/* 0x10 - 0x11 NV version.  */ | ||||
|   grub_uint8_t unit_number;	/* 0x12 Disk index in array.  */ | ||||
|   grub_uint8_t reserved;	/* 0x13.  */ | ||||
|   grub_uint32_t capacity;	/* 0x14 - 0x17 Array capacity in sectors.  */ | ||||
|   grub_uint32_t sector_size;	/* 0x18 - 0x1B Sector size.  */ | ||||
|   char prodid[NV_PRODID_LEN];	/* 0x1C - 0x2B Array product ID.  */ | ||||
|   char prodrev[NV_PRODREV_LEN];	/* 0x2C - 0x2F Array product revision */ | ||||
|   grub_uint32_t unit_flags;	/* 0x30 - 0x33 Flags for this disk */ | ||||
|   struct grub_nv_array array;	/* Array information */ | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array, | ||||
|                        grub_disk_addr_t *start_sector) | ||||
| { | ||||
|   grub_disk_addr_t sector; | ||||
|   struct grub_nv_super sb; | ||||
| 
 | ||||
|   if (disk->partition) | ||||
|     return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition"); | ||||
| 
 | ||||
|   sector = grub_disk_get_size (disk) - 2; | ||||
| 
 | ||||
|   if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (grub_memcmp (sb.vendor, NV_ID_STRING, 6)) | ||||
|     return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); | ||||
| 
 | ||||
|   if (sb.version != NV_VERSION) | ||||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
|                        "unknown version: %d.%d", sb.version); | ||||
| 
 | ||||
|   switch (sb.array.raid_level) | ||||
|     { | ||||
|     case NV_LEVEL_0: | ||||
|       array->level = 0; | ||||
|       array->disk_size = sb.capacity / sb.array.total_volumes; | ||||
|       break; | ||||
| 
 | ||||
|     case NV_LEVEL_1: | ||||
|       array->level = 1; | ||||
|       array->disk_size = sb.capacity; | ||||
|       break; | ||||
| 
 | ||||
|     case NV_LEVEL_5: | ||||
|       array->level = 5; | ||||
|       array->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC; | ||||
|       array->disk_size = sb.capacity / (sb.array.total_volumes - 1); | ||||
|       break; | ||||
| 
 | ||||
|     default: | ||||
|       return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
|                          "unsupported RAID level: %d", sb.array.raid_level); | ||||
|     } | ||||
| 
 | ||||
|   array->name = NULL; | ||||
|   array->number = 0; | ||||
|   array->total_devs = sb.array.total_volumes; | ||||
|   array->chunk_size = sb.array.stripe_block_size; | ||||
|   array->index = sb.unit_number; | ||||
|   array->uuid_len = sizeof (sb.array.signature); | ||||
|   array->uuid = grub_malloc (sizeof (sb.array.signature)); | ||||
|   if (! array->uuid) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_memcpy (array->uuid, (char *) &sb.array.signature, | ||||
|                sizeof (sb.array.signature)); | ||||
| 
 | ||||
|   *start_sector = 0; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static struct grub_raid grub_dmraid_nv_dev = | ||||
| { | ||||
|   .name = "dmraid_nv", | ||||
|   .detect = grub_dmraid_nv_detect, | ||||
|   .next = 0 | ||||
| }; | ||||
| 
 | ||||
| GRUB_MOD_INIT(dm_nv) | ||||
| { | ||||
|   grub_raid_register (&grub_dmraid_nv_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(dm_nv) | ||||
| { | ||||
|   grub_raid_unregister (&grub_dmraid_nv_dev); | ||||
| } | ||||
							
								
								
									
										851
									
								
								grub-core/disk/efi/efidisk.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										851
									
								
								grub-core/disk/efi/efidisk.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,851 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/disk.h> | ||||
| #include <grub/partition.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/term.h> | ||||
| #include <grub/efi/api.h> | ||||
| #include <grub/efi/efi.h> | ||||
| #include <grub/efi/disk.h> | ||||
| 
 | ||||
| struct grub_efidisk_data | ||||
| { | ||||
|   grub_efi_handle_t handle; | ||||
|   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; | ||||
| static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID; | ||||
| 
 | ||||
| static struct grub_efidisk_data *fd_devices; | ||||
| static struct grub_efidisk_data *hd_devices; | ||||
| static struct grub_efidisk_data *cd_devices; | ||||
| 
 | ||||
| /* Duplicate a device path.  */ | ||||
| static grub_efi_device_path_t * | ||||
| duplicate_device_path (const grub_efi_device_path_t *dp) | ||||
| { | ||||
|   grub_efi_device_path_t *p; | ||||
|   grub_size_t total_size = 0; | ||||
| 
 | ||||
|   for (p = (grub_efi_device_path_t *) dp; | ||||
|        ; | ||||
|        p = GRUB_EFI_NEXT_DEVICE_PATH (p)) | ||||
|     { | ||||
|       total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); | ||||
|       if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   p = grub_malloc (total_size); | ||||
|   if (! p) | ||||
|     return 0; | ||||
| 
 | ||||
|   grub_memcpy (p, dp, total_size); | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| /* Return the device path node right before the end node.  */ | ||||
| static grub_efi_device_path_t * | ||||
| find_last_device_path (const grub_efi_device_path_t *dp) | ||||
| { | ||||
|   grub_efi_device_path_t *next, *p; | ||||
| 
 | ||||
|   if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) | ||||
|     return 0; | ||||
| 
 | ||||
|   for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); | ||||
|        ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); | ||||
|        p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) | ||||
|     ; | ||||
| 
 | ||||
|   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) | ||||
| { | ||||
|   grub_efi_uintn_t num_handles; | ||||
|   grub_efi_handle_t *handles; | ||||
|   grub_efi_handle_t *handle; | ||||
|   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, | ||||
| 				    0, &num_handles); | ||||
|   if (! handles) | ||||
|     return 0; | ||||
| 
 | ||||
|   /* Make a linked list of devices.  */ | ||||
|   for (handle = handles; num_handles--; handle++) | ||||
|     { | ||||
|       grub_efi_device_path_t *dp; | ||||
|       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) | ||||
| 	continue; | ||||
| 
 | ||||
|       ldp = find_last_device_path (dp); | ||||
|       if (! ldp) | ||||
| 	/* This is empty. Why?  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       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) | ||||
| 	/* This should not happen... Why?  */ | ||||
| 	continue; | ||||
| 
 | ||||
|       d = grub_malloc (sizeof (*d)); | ||||
|       if (! d) | ||||
| 	{ | ||||
| 	  /* Uggh.  */ | ||||
| 	  grub_free (handles); | ||||
| 	  return 0; | ||||
| 	} | ||||
| 
 | ||||
|       d->handle = *handle; | ||||
|       d->device_path = dp; | ||||
|       d->last_device_path = ldp; | ||||
|       d->block_io = bio; | ||||
|       d->disk_io = dio; | ||||
|       d->next = devices; | ||||
|       devices = d; | ||||
|     } | ||||
| 
 | ||||
|   grub_free (handles); | ||||
| 
 | ||||
|   return devices; | ||||
| } | ||||
| 
 | ||||
| /* Find the parent device.  */ | ||||
| static struct grub_efidisk_data * | ||||
| find_parent_device (struct grub_efidisk_data *devices, | ||||
| 		    struct grub_efidisk_data *d) | ||||
| { | ||||
|   grub_efi_device_path_t *dp, *ldp; | ||||
|   struct grub_efidisk_data *parent; | ||||
| 
 | ||||
|   dp = duplicate_device_path (d->device_path); | ||||
|   if (! dp) | ||||
|     return 0; | ||||
| 
 | ||||
|   ldp = find_last_device_path (dp); | ||||
|   ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | ||||
|   ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | ||||
|   ldp->length[0] = sizeof (*ldp); | ||||
|   ldp->length[1] = 0; | ||||
| 
 | ||||
|   for (parent = devices; parent; parent = parent->next) | ||||
|     { | ||||
|       /* Ignore itself.  */ | ||||
|       if (parent == d) | ||||
| 	continue; | ||||
| 
 | ||||
|       if (compare_device_paths (parent->device_path, dp) == 0) | ||||
| 	{ | ||||
| 	  /* Found.  */ | ||||
| 	  if (! parent->last_device_path) | ||||
| 	    parent = 0; | ||||
| 
 | ||||
| 	  break; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   grub_free (dp); | ||||
|   return parent; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| iterate_child_devices (struct grub_efidisk_data *devices, | ||||
| 		       struct grub_efidisk_data *d, | ||||
| 		       int (*hook) (struct grub_efidisk_data *child)) | ||||
| { | ||||
|   struct grub_efidisk_data *p; | ||||
| 
 | ||||
|   for (p = devices; p; p = p->next) | ||||
|     { | ||||
|       grub_efi_device_path_t *dp, *ldp; | ||||
| 
 | ||||
|       dp = duplicate_device_path (p->device_path); | ||||
|       if (! dp) | ||||
| 	return 0; | ||||
| 
 | ||||
|       ldp = find_last_device_path (dp); | ||||
|       ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | ||||
|       ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | ||||
|       ldp->length[0] = sizeof (*ldp); | ||||
|       ldp->length[1] = 0; | ||||
| 
 | ||||
|       if (compare_device_paths (dp, d->device_path) == 0) | ||||
| 	if (hook (p)) | ||||
| 	  { | ||||
| 	    grub_free (dp); | ||||
| 	    return 1; | ||||
| 	  } | ||||
| 
 | ||||
|       grub_free (dp); | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* Add a device into a list of devices in an ascending order.  */ | ||||
| static void | ||||
| add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d) | ||||
| { | ||||
|   struct grub_efidisk_data **p; | ||||
|   struct grub_efidisk_data *n; | ||||
| 
 | ||||
|   for (p = devices; *p; p = &((*p)->next)) | ||||
|     { | ||||
|       int ret; | ||||
| 
 | ||||
|       ret = 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); | ||||
|       if (ret == 0) | ||||
| 	return; | ||||
|       else if (ret > 0) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   n = grub_malloc (sizeof (*n)); | ||||
|   if (! n) | ||||
|     return; | ||||
| 
 | ||||
|   grub_memcpy (n, d, sizeof (*n)); | ||||
|   n->next = (*p); | ||||
|   (*p) = n; | ||||
| } | ||||
| 
 | ||||
| /* Name the devices.  */ | ||||
| static void | ||||
| name_devices (struct grub_efidisk_data *devices) | ||||
| { | ||||
|   struct grub_efidisk_data *d; | ||||
| 
 | ||||
|   /* First, identify devices by media device paths.  */ | ||||
|   for (d = devices; d; d = d->next) | ||||
|     { | ||||
|       grub_efi_device_path_t *dp; | ||||
| 
 | ||||
|       dp = d->last_device_path; | ||||
|       if (! dp) | ||||
| 	continue; | ||||
| 
 | ||||
|       if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE) | ||||
| 	{ | ||||
| 	  int is_hard_drive = 0; | ||||
| 
 | ||||
| 	  switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)) | ||||
| 	    { | ||||
| 	    case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE: | ||||
| 	      is_hard_drive = 1; | ||||
| 	      /* Fall through by intention.  */ | ||||
| 	    case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE: | ||||
| 	      { | ||||
| 		struct grub_efidisk_data *parent; | ||||
| 
 | ||||
| 		parent = find_parent_device (devices, d); | ||||
| 		if (parent) | ||||
| 		  { | ||||
| 		    if (is_hard_drive) | ||||
| 		      { | ||||
| #if 0 | ||||
| 			grub_printf ("adding a hard drive by a partition: "); | ||||
| 			grub_print_device_path (parent->device_path); | ||||
| #endif | ||||
| 			add_device (&hd_devices, parent); | ||||
| 		      } | ||||
| 		    else | ||||
| 		      { | ||||
| #if 0 | ||||
| 			grub_printf ("adding a cdrom by a partition: "); | ||||
| 			grub_print_device_path (parent->device_path); | ||||
| #endif | ||||
| 			add_device (&cd_devices, parent); | ||||
| 		      } | ||||
| 
 | ||||
| 		    /* Mark the parent as used.  */ | ||||
| 		    parent->last_device_path = 0; | ||||
| 		  } | ||||
| 	      } | ||||
| 	      /* Mark itself as used.  */ | ||||
| 	      d->last_device_path = 0; | ||||
| 	      break; | ||||
| 
 | ||||
| 	    default: | ||||
| 	      /* For now, ignore the others.  */ | ||||
| 	      break; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   /* Let's see what can be added more.  */ | ||||
|   for (d = devices; d; d = d->next) | ||||
|     { | ||||
|       grub_efi_device_path_t *dp; | ||||
|       grub_efi_block_io_media_t *m; | ||||
| 
 | ||||
|       dp = d->last_device_path; | ||||
|       if (! dp) | ||||
| 	continue; | ||||
| 
 | ||||
|       m = d->block_io->media; | ||||
|       if (m->logical_partition) | ||||
| 	{ | ||||
| 	  /* Only one partition in a non-media device. Assume that this
 | ||||
| 	     is a floppy drive.  */ | ||||
| #if 0 | ||||
| 	  grub_printf ("adding a floppy by guessing: "); | ||||
| 	  grub_print_device_path (d->device_path); | ||||
| #endif | ||||
| 	  add_device (&fd_devices, d); | ||||
| 	} | ||||
|       else if (m->read_only && m->block_size > GRUB_DISK_SECTOR_SIZE) | ||||
| 	{ | ||||
| 	  /* This check is too heuristic, but assume that this is a
 | ||||
| 	     CDROM drive.  */ | ||||
| #if 0 | ||||
| 	  grub_printf ("adding a cdrom by guessing: "); | ||||
| 	  grub_print_device_path (d->device_path); | ||||
| #endif | ||||
| 	  add_device (&cd_devices, d); | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  /* The default is a hard drive.  */ | ||||
| #if 0 | ||||
| 	  grub_printf ("adding a hard drive by guessing: "); | ||||
| 	  grub_print_device_path (d->device_path); | ||||
| #endif | ||||
| 	  add_device (&hd_devices, d); | ||||
| 	} | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| free_devices (struct grub_efidisk_data *devices) | ||||
| { | ||||
|   struct grub_efidisk_data *p, *q; | ||||
| 
 | ||||
|   for (p = devices; p; p = q) | ||||
|     { | ||||
|       q = p->next; | ||||
|       grub_free (p); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Enumerate all disks to name devices.  */ | ||||
| static void | ||||
| enumerate_disks (void) | ||||
| { | ||||
|   struct grub_efidisk_data *devices; | ||||
| 
 | ||||
|   devices = make_devices (); | ||||
|   if (! devices) | ||||
|     return; | ||||
| 
 | ||||
|   name_devices (devices); | ||||
|   free_devices (devices); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_efidisk_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   struct grub_efidisk_data *d; | ||||
|   char buf[16]; | ||||
|   int count; | ||||
| 
 | ||||
|   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; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| get_drive_number (const char *name) | ||||
| { | ||||
|   unsigned long drive; | ||||
| 
 | ||||
|   if ((name[0] != 'f' && name[0] != 'h' && name[0] != 'c') || name[1] != 'd') | ||||
|     goto fail; | ||||
| 
 | ||||
|   drive = grub_strtoul (name + 2, 0, 10); | ||||
|   if (grub_errno != GRUB_ERR_NONE) | ||||
|     goto fail; | ||||
| 
 | ||||
|   return (int) drive ; | ||||
| 
 | ||||
|  fail: | ||||
|   grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a efidisk"); | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| static struct grub_efidisk_data * | ||||
| get_device (struct grub_efidisk_data *devices, int num) | ||||
| { | ||||
|   struct grub_efidisk_data *d; | ||||
| 
 | ||||
|   for (d = devices; d && num; d = d->next, num--) | ||||
|     ; | ||||
| 
 | ||||
|   if (num == 0) | ||||
|     return d; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_efidisk_open (const char *name, struct grub_disk *disk) | ||||
| { | ||||
|   int num; | ||||
|   struct grub_efidisk_data *d = 0; | ||||
|   grub_efi_block_io_media_t *m; | ||||
| 
 | ||||
|   grub_dprintf ("efidisk", "opening %s\n", name); | ||||
| 
 | ||||
|   num = get_drive_number (name); | ||||
|   if (num < 0) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   switch (name[0]) | ||||
|     { | ||||
|     case 'f': | ||||
|       disk->has_partitions = 0; | ||||
|       d = get_device (fd_devices, num); | ||||
|       break; | ||||
|     case 'c': | ||||
|       /* FIXME: a CDROM should have partitions, but not implemented yet.  */ | ||||
|       disk->has_partitions = 0; | ||||
|       d = get_device (cd_devices, num); | ||||
|       break; | ||||
|     case 'h': | ||||
|       disk->has_partitions = 1; | ||||
|       d = get_device (hd_devices, num); | ||||
|       break; | ||||
|     default: | ||||
|       /* Never reach here.  */ | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   if (! d) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device"); | ||||
| 
 | ||||
|   disk->id = ((num << 8) | name[0]); | ||||
|   m = d->block_io->media; | ||||
|   /* FIXME: Probably it is better to store the block size in the 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->data = d; | ||||
| 
 | ||||
|   grub_dprintf ("efidisk", "opening %s succeeded\n", name); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_efidisk_close (struct grub_disk *disk __attribute__ ((unused))) | ||||
| { | ||||
|   /* EFI disks do not allocate extra memory, so nothing to do here.  */ | ||||
|   grub_dprintf ("efidisk", "closing %s\n", disk->name); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector, | ||||
| 		   grub_size_t size, char *buf) | ||||
| { | ||||
|   /* 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); | ||||
|   if (status != GRUB_EFI_SUCCESS) | ||||
|     return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error"); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector, | ||||
| 		    grub_size_t size, const char *buf) | ||||
| { | ||||
|   /* 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, | ||||
| 		       (void *) buf); | ||||
|   if (status != GRUB_EFI_SUCCESS) | ||||
|     return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error"); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_efidisk_dev = | ||||
|   { | ||||
|     .name = "efidisk", | ||||
|     .id = GRUB_DISK_DEVICE_EFIDISK_ID, | ||||
|     .iterate = grub_efidisk_iterate, | ||||
|     .open = grub_efidisk_open, | ||||
|     .close = grub_efidisk_close, | ||||
|     .read = grub_efidisk_read, | ||||
|     .write = grub_efidisk_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| void | ||||
| grub_efidisk_init (void) | ||||
| { | ||||
|   enumerate_disks (); | ||||
|   grub_disk_dev_register (&grub_efidisk_dev); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_efidisk_fini (void) | ||||
| { | ||||
|   free_devices (fd_devices); | ||||
|   free_devices (hd_devices); | ||||
|   free_devices (cd_devices); | ||||
|   grub_disk_dev_unregister (&grub_efidisk_dev); | ||||
| } | ||||
| 
 | ||||
| /* Some utility functions to map GRUB devices with EFI devices.  */ | ||||
| grub_efi_handle_t | ||||
| grub_efidisk_get_device_handle (grub_disk_t disk) | ||||
| { | ||||
|   struct grub_efidisk_data *d; | ||||
|   char type; | ||||
| 
 | ||||
|   if (disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID) | ||||
|     return 0; | ||||
| 
 | ||||
|   d = disk->data; | ||||
|   type = disk->name[0]; | ||||
| 
 | ||||
|   switch (type) | ||||
|     { | ||||
|     case 'f': | ||||
|       /* This is the simplest case.  */ | ||||
|       return d->handle; | ||||
| 
 | ||||
|     case 'c': | ||||
|       /* FIXME: probably this is not correct.  */ | ||||
|       return d->handle; | ||||
| 
 | ||||
|     case 'h': | ||||
|       /* If this is the whole disk, just return its own data.  */ | ||||
|       if (! disk->partition) | ||||
| 	return d->handle; | ||||
| 
 | ||||
|       /* Otherwise, we must query the corresponding device to the firmware.  */ | ||||
|       { | ||||
| 	struct grub_efidisk_data *devices; | ||||
| 	grub_efi_handle_t handle = 0; | ||||
| 	auto int find_partition (struct grub_efidisk_data *c); | ||||
| 
 | ||||
| 	int find_partition (struct grub_efidisk_data *c) | ||||
| 	  { | ||||
| 	    grub_efi_hard_drive_device_path_t hd; | ||||
| 
 | ||||
| 	    grub_memcpy (&hd, c->last_device_path, sizeof (hd)); | ||||
| 
 | ||||
| 	    if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path) | ||||
| 		 == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE) | ||||
| 		&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path) | ||||
| 		    == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE) | ||||
| 		&& (grub_partition_get_start (disk->partition) | ||||
| 		    == hd.partition_start) | ||||
| 		&& (grub_partition_get_len (disk->partition) | ||||
| 		    == hd.partition_size)) | ||||
| 	      { | ||||
| 		handle = c->handle; | ||||
| 		return 1; | ||||
| 	      } | ||||
| 
 | ||||
| 	    return 0; | ||||
| 	  } | ||||
| 
 | ||||
| 	devices = make_devices (); | ||||
| 	iterate_child_devices (devices, d, find_partition); | ||||
| 	free_devices (devices); | ||||
| 
 | ||||
| 	if (handle != 0) | ||||
| 	  return handle; | ||||
|       } | ||||
|       break; | ||||
| 
 | ||||
|     default: | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| char * | ||||
| grub_efidisk_get_device_name (grub_efi_handle_t *handle) | ||||
| { | ||||
|   grub_efi_device_path_t *dp, *ldp; | ||||
| 
 | ||||
|   dp = grub_efi_get_device_path (handle); | ||||
|   if (! dp) | ||||
|     return 0; | ||||
| 
 | ||||
|   ldp = find_last_device_path (dp); | ||||
|   if (! ldp) | ||||
|     return 0; | ||||
| 
 | ||||
|   if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE | ||||
|       && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) | ||||
| 	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)) | ||||
|     { | ||||
|       /* This is a hard disk partition.  */ | ||||
|       grub_disk_t parent = 0; | ||||
|       char *partition_name = 0; | ||||
|       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) | ||||
| 	{ | ||||
| 	  if (grub_partition_get_start (part) == hd.partition_start | ||||
| 	      && grub_partition_get_len (part) == hd.partition_size) | ||||
| 	    { | ||||
| 	      partition_name = grub_partition_get_name (part); | ||||
| 	      return 1; | ||||
| 	    } | ||||
| 
 | ||||
| 	  return 0; | ||||
| 	} | ||||
| 
 | ||||
|       /* It is necessary to duplicate the device path so that GRUB
 | ||||
| 	 can overwrite it.  */ | ||||
|       dup_dp = duplicate_device_path (dp); | ||||
|       if (! dup_dp) | ||||
| 	return 0; | ||||
| 
 | ||||
|       dup_ldp = find_last_device_path (dup_dp); | ||||
|       dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; | ||||
|       dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; | ||||
|       dup_ldp->length[0] = sizeof (*dup_ldp); | ||||
|       dup_ldp->length[1] = 0; | ||||
| 
 | ||||
|       grub_efidisk_iterate (find_parent_disk); | ||||
|       grub_free (dup_dp); | ||||
| 
 | ||||
|       if (! parent) | ||||
| 	return 0; | ||||
| 
 | ||||
|       /* Find a partition which matches the hard drive device path.  */ | ||||
|       grub_memcpy (&hd, ldp, sizeof (hd)); | ||||
|       grub_partition_iterate (parent, find_partition); | ||||
| 
 | ||||
|       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; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       /* This should be an entire disk.  */ | ||||
|       auto int find_disk (const char *name); | ||||
|       char *device_name = 0; | ||||
| 
 | ||||
|       int find_disk (const char *name) | ||||
| 	{ | ||||
| 	  grub_disk_t disk; | ||||
| 
 | ||||
| 	  disk = grub_disk_open (name); | ||||
| 	  if (! disk) | ||||
| 	    return 1; | ||||
| 
 | ||||
| 	  if (disk->dev->id == GRUB_DISK_DEVICE_EFIDISK_ID) | ||||
| 	    { | ||||
| 	      struct grub_efidisk_data *d; | ||||
| 
 | ||||
| 	      d = disk->data; | ||||
| 	      if (compare_device_paths (d->device_path, dp) == 0) | ||||
| 		{ | ||||
| 		  device_name = grub_strdup (disk->name); | ||||
| 		  grub_disk_close (disk); | ||||
| 		  return 1; | ||||
| 		} | ||||
| 	    } | ||||
| 
 | ||||
| 	  grub_disk_close (disk); | ||||
| 	  return 0; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
|       grub_efidisk_iterate (find_disk); | ||||
|       return device_name; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										96
									
								
								grub-core/disk/host.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								grub-core/disk/host.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| /* host.c - Dummy disk driver to provide access to the hosts filesystem  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| /* When using the disk, make a reference to this module.  Otherwise
 | ||||
|    the user will end up with a useless module :-).  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/misc.h> | ||||
| 
 | ||||
| int grub_disk_host_i_want_a_reference; | ||||
| 
 | ||||
| static int | ||||
| grub_host_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   if (hook ("host")) | ||||
|     return 1; | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_host_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   if (grub_strcmp (name, "host")) | ||||
|       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a host disk"); | ||||
| 
 | ||||
|   disk->total_sectors = 0; | ||||
|   disk->id = (unsigned long) "host"; | ||||
| 
 | ||||
|   disk->has_partitions = 0; | ||||
|   disk->data = 0; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_host_close (grub_disk_t disk __attribute((unused))) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_host_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_host_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_host_dev = | ||||
|   { | ||||
|     /* The only important line in this file :-) */ | ||||
|     .name = "host", | ||||
|     .id = GRUB_DISK_DEVICE_HOST_ID, | ||||
|     .iterate = grub_host_iterate, | ||||
|     .open = grub_host_open, | ||||
|     .close = grub_host_close, | ||||
|     .read = grub_host_read, | ||||
|     .write = grub_host_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| GRUB_MOD_INIT(host) | ||||
| { | ||||
|   grub_disk_dev_register (&grub_host_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(host) | ||||
| { | ||||
|   grub_disk_dev_unregister (&grub_host_dev); | ||||
| } | ||||
							
								
								
									
										629
									
								
								grub-core/disk/i386/pc/biosdisk.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										629
									
								
								grub-core/disk/i386/pc/biosdisk.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,629 @@ | |||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/machine/biosdisk.h> | ||||
| #include <grub/machine/memory.h> | ||||
| #include <grub/machine/kernel.h> | ||||
| #include <grub/machine/int.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/types.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/term.h> | ||||
| 
 | ||||
| static int cd_drive = 0; | ||||
| static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap); | ||||
| 
 | ||||
| static int grub_biosdisk_get_num_floppies (void) | ||||
| { | ||||
|   struct grub_bios_int_registers regs; | ||||
|   int drive; | ||||
| 
 | ||||
|   /* reset the disk system first */ | ||||
|   regs.eax = 0; | ||||
|   regs.edx = 0; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
| 
 | ||||
|   grub_bios_interrupt (0x13, ®s); | ||||
| 
 | ||||
|   for (drive = 0; drive < 2; drive++) | ||||
|     { | ||||
|       regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT | GRUB_CPU_INT_FLAGS_CARRY; | ||||
|       regs.edx = drive; | ||||
| 
 | ||||
|       /* call GET DISK TYPE */ | ||||
|       regs.eax = 0x1500; | ||||
|       grub_bios_interrupt (0x13, ®s); | ||||
|       if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) | ||||
| 	break; | ||||
| 
 | ||||
|       /* check if this drive exists */ | ||||
|       if (!(regs.eax & 0x300)) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   return drive; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *   Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP | ||||
|  *   is passed for disk address packet. If an error occurs, return | ||||
|  *   non-zero, otherwise zero. | ||||
|  */ | ||||
| 
 | ||||
| static int  | ||||
| grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) | ||||
| { | ||||
|   struct grub_bios_int_registers regs; | ||||
|   regs.eax = ah << 8; | ||||
|   /* compute the address of disk_address_packet */ | ||||
|   regs.ds = (((grub_addr_t) dap) & 0xffff0000) >> 4; | ||||
|   regs.esi = (((grub_addr_t) dap) & 0xffff); | ||||
|   regs.edx = drive; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
| 
 | ||||
|   grub_bios_interrupt (0x13, ®s); | ||||
|   return (regs.eax >> 8) & 0xff; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *   Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write | ||||
|  *   NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs, | ||||
|  *   return non-zero, otherwise zero. | ||||
|  */ | ||||
| static int  | ||||
| grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, | ||||
| 			   int soff, int nsec, int segment) | ||||
| { | ||||
|   int ret, i; | ||||
| 
 | ||||
|   /* Try 3 times.  */ | ||||
|   for (i = 0; i < 3; i++) | ||||
|     { | ||||
|       struct grub_bios_int_registers regs; | ||||
| 
 | ||||
|       /* set up CHS information */ | ||||
|       /* set %ch to low eight bits of cylinder */ | ||||
|       regs.ecx = (coff << 8) & 0xff00; | ||||
|       /* set bits 6-7 of %cl to high two bits of cylinder */ | ||||
|       regs.ecx |= (coff >> 2) & 0xc0; | ||||
|       /* set bits 0-5 of %cl to sector */ | ||||
|       regs.ecx |= soff & 0x3f; | ||||
| 
 | ||||
|       /* set %dh to head and %dl to drive */   | ||||
|       regs.edx = (drive & 0xff) | ((hoff << 8) & 0xff00); | ||||
|       /* set %ah to AH */ | ||||
|       regs.eax = (ah << 8) & 0xff00; | ||||
|       /* set %al to NSEC */ | ||||
|       regs.eax |= nsec & 0xff; | ||||
| 
 | ||||
|       regs.ebx = 0; | ||||
|       regs.es = segment; | ||||
| 
 | ||||
|       regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
| 
 | ||||
|       grub_bios_interrupt (0x13, ®s); | ||||
|       /* check if successful */ | ||||
|       if (!(regs.flags & GRUB_CPU_INT_FLAGS_CARRY)) | ||||
| 	return 0; | ||||
| 
 | ||||
|       /* save return value */ | ||||
|       ret = regs.eax >> 8; | ||||
| 
 | ||||
|       /* if fail, reset the disk system */ | ||||
|       regs.eax = 0; | ||||
|       regs.edx = (drive & 0xff); | ||||
|       regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|       grub_bios_interrupt (0x13, ®s); | ||||
|     } | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *   Check if LBA is supported for DRIVE. If it is supported, then return | ||||
|  *   the major version of extensions, otherwise zero. | ||||
|  */ | ||||
| static int | ||||
| grub_biosdisk_check_int13_extensions (int drive) | ||||
| { | ||||
|   struct grub_bios_int_registers regs; | ||||
| 
 | ||||
|   regs.edx = drive & 0xff; | ||||
|   regs.eax = 0x4100; | ||||
|   regs.ebx = 0x55aa; | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x13, ®s); | ||||
|    | ||||
|   if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) | ||||
|     return 0; | ||||
| 
 | ||||
|   if ((regs.ebx & 0xffff) != 0xaa55) | ||||
|     return 0; | ||||
| 
 | ||||
|   /* check if AH=0x42 is supported */ | ||||
|   if (!(regs.ecx & 1)) | ||||
|     return 0; | ||||
| 
 | ||||
|   return (regs.eax >> 8) & 0xff; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *   Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an | ||||
|  *   error occurs, then return non-zero, otherwise zero. | ||||
|  */ | ||||
| static int  | ||||
| grub_biosdisk_get_diskinfo_standard (int drive, | ||||
| 				     unsigned long *cylinders, | ||||
| 				     unsigned long *heads, | ||||
| 				     unsigned long *sectors) | ||||
| { | ||||
|   struct grub_bios_int_registers regs; | ||||
| 
 | ||||
|   regs.eax = 0x0800; | ||||
|   regs.edx = drive & 0xff; | ||||
| 
 | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x13, ®s); | ||||
| 
 | ||||
|   /* Check if unsuccessful. Ignore return value if carry isn't set to 
 | ||||
|      workaround some buggy BIOSes. */ | ||||
|   if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0)) | ||||
|     return (regs.eax & 0xff00) >> 8; | ||||
| 
 | ||||
|   /* bogus BIOSes may not return an error number */   | ||||
|   /* 0 sectors means no disk */ | ||||
|   if (!(regs.ecx & 0x3f)) | ||||
|     /* XXX 0x60 is one of the unused error numbers */ | ||||
|     return 0x60; | ||||
| 
 | ||||
|   /* the number of heads is counted from zero */ | ||||
|   *heads = ((regs.edx >> 8) & 0xff) + 1; | ||||
|   *cylinders = (((regs.ecx >> 8) & 0xff) | ((regs.ecx << 2) & 0x0300)) + 1; | ||||
|   *sectors = regs.ecx & 0x3f; | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_biosdisk_get_diskinfo_real (int drive, void *drp, grub_uint16_t ax) | ||||
| { | ||||
|   struct grub_bios_int_registers regs; | ||||
| 
 | ||||
|   regs.eax = ax; | ||||
| 
 | ||||
|   /* compute the address of drive parameters */ | ||||
|   regs.esi = ((grub_addr_t) drp) & 0xf; | ||||
|   regs.ds = ((grub_addr_t) drp) >> 4; | ||||
|   regs.edx = drive & 0xff; | ||||
| 
 | ||||
|   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; | ||||
|   grub_bios_interrupt (0x13, ®s); | ||||
| 
 | ||||
|   /* Check if unsuccessful. Ignore return value if carry isn't set to 
 | ||||
|      workaround some buggy BIOSes. */ | ||||
|   if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0)) | ||||
|     return (regs.eax & 0xff00) >> 8; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *   Return the cdrom information of DRIVE in CDRP. If an error occurs, | ||||
|  *   then return non-zero, otherwise zero. | ||||
|  */ | ||||
| static int | ||||
| grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp) | ||||
| { | ||||
|   return grub_biosdisk_get_diskinfo_real (drive, cdrp, 0x4b01); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *   Return the geometry of DRIVE in a drive parameters, DRP. If an error | ||||
|  *   occurs, then return non-zero, otherwise zero. | ||||
|  */ | ||||
| static int | ||||
| grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp) | ||||
| { | ||||
|   return grub_biosdisk_get_diskinfo_real (drive, drp, 0x4800); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_biosdisk_get_drive (const char *name) | ||||
| { | ||||
|   unsigned long drive; | ||||
| 
 | ||||
|   if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd') | ||||
|     goto fail; | ||||
| 
 | ||||
|   drive = grub_strtoul (name + 2, 0, 10); | ||||
|   if (grub_errno != GRUB_ERR_NONE) | ||||
|     goto fail; | ||||
| 
 | ||||
|   if (name[0] == 'h') | ||||
|     drive += 0x80; | ||||
| 
 | ||||
|   return (int) drive ; | ||||
| 
 | ||||
|  fail: | ||||
|   grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a biosdisk"); | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_biosdisk_call_hook (int (*hook) (const char *name), int drive) | ||||
| { | ||||
|   char name[10]; | ||||
| 
 | ||||
|   grub_snprintf (name, sizeof (name), | ||||
| 		 (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); | ||||
|   return hook (name); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_biosdisk_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   int drive; | ||||
|   int num_floppies; | ||||
| 
 | ||||
|   /* For hard disks, attempt to read the MBR.  */ | ||||
|   for (drive = 0x80; drive < 0x90; drive++) | ||||
|     { | ||||
|       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; | ||||
|     } | ||||
| 
 | ||||
|   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; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_biosdisk_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   grub_uint64_t total_sectors = 0; | ||||
|   int drive; | ||||
|   struct grub_biosdisk_data *data; | ||||
| 
 | ||||
|   drive = grub_biosdisk_get_drive (name); | ||||
|   if (drive < 0) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   disk->has_partitions = 1; | ||||
|   disk->id = drive; | ||||
| 
 | ||||
|   data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data)); | ||||
|   if (! data) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   data->drive = drive; | ||||
| 
 | ||||
|   if ((cd_drive) && (drive == cd_drive)) | ||||
|     { | ||||
|       data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; | ||||
|       data->sectors = 32; | ||||
|       /* TODO: get the correct size.  */ | ||||
|       total_sectors = GRUB_DISK_SIZE_UNKNOWN; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       /* HDD */ | ||||
|       int version; | ||||
| 
 | ||||
|       version = grub_biosdisk_check_int13_extensions (drive); | ||||
|       if (version) | ||||
| 	{ | ||||
| 	  struct grub_biosdisk_drp *drp | ||||
| 	    = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; | ||||
| 
 | ||||
| 	  /* Clear out the DRP.  */ | ||||
| 	  grub_memset (drp, 0, sizeof (*drp)); | ||||
| 	  drp->size = sizeof (*drp); | ||||
| 	  if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp)) | ||||
| 	    { | ||||
| 	      data->flags = GRUB_BIOSDISK_FLAG_LBA; | ||||
| 
 | ||||
| 	      if (drp->total_sectors) | ||||
| 		total_sectors = drp->total_sectors; | ||||
| 	      else | ||||
|                 /* Some buggy BIOSes doesn't return the total sectors
 | ||||
|                    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 (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM)) | ||||
|     { | ||||
|       if (grub_biosdisk_get_diskinfo_standard (drive, | ||||
| 					       &data->cylinders, | ||||
| 					       &data->heads, | ||||
| 					       &data->sectors) != 0) | ||||
|         { | ||||
| 	  if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA)) | ||||
| 	    { | ||||
| 	      data->sectors = 63; | ||||
| 	      data->heads = 255; | ||||
| 	      data->cylinders | ||||
| 		= grub_divmod64 (total_sectors | ||||
| 				 + data->heads * data->sectors - 1, | ||||
| 				 data->heads * data->sectors, 0); | ||||
| 	    } | ||||
| 	  else | ||||
| 	    { | ||||
| 	      grub_free (data); | ||||
| 	      return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name); | ||||
| 	    } | ||||
|         } | ||||
| 
 | ||||
|       if (! total_sectors) | ||||
|         total_sectors = data->cylinders * data->heads * data->sectors; | ||||
|     } | ||||
| 
 | ||||
|   disk->total_sectors = total_sectors; | ||||
|   disk->data = data; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_biosdisk_close (grub_disk_t disk) | ||||
| { | ||||
|   grub_free (disk->data); | ||||
| } | ||||
| 
 | ||||
| /* For readability.  */ | ||||
| #define GRUB_BIOSDISK_READ	0 | ||||
| #define GRUB_BIOSDISK_WRITE	1 | ||||
| 
 | ||||
| #define GRUB_BIOSDISK_CDROM_RETRY_COUNT 3 | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_biosdisk_rw (int cmd, grub_disk_t disk, | ||||
| 		  grub_disk_addr_t sector, grub_size_t size, | ||||
| 		  unsigned segment) | ||||
| { | ||||
|   struct grub_biosdisk_data *data = disk->data; | ||||
| 
 | ||||
|   if (data->flags & GRUB_BIOSDISK_FLAG_LBA) | ||||
|     { | ||||
|       struct grub_biosdisk_dap *dap; | ||||
| 
 | ||||
|       dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR | ||||
| 					  + (data->sectors | ||||
| 					     << GRUB_DISK_SECTOR_BITS)); | ||||
|       dap->length = sizeof (*dap); | ||||
|       dap->reserved = 0; | ||||
|       dap->blocks = size; | ||||
|       dap->buffer = segment << 16;	/* The format SEGMENT:ADDRESS.  */ | ||||
|       dap->block = sector; | ||||
| 
 | ||||
|       if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) | ||||
|         { | ||||
| 	  int i; | ||||
| 
 | ||||
| 	  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; | ||||
| 
 | ||||
| 	  if (i == GRUB_BIOSDISK_CDROM_RETRY_COUNT) | ||||
| 	    return grub_error (GRUB_ERR_READ_ERROR, "cdrom read error"); | ||||
| 	} | ||||
|       else | ||||
|         if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap)) | ||||
| 	  { | ||||
| 	    /* Fall back to the CHS mode.  */ | ||||
| 	    data->flags &= ~GRUB_BIOSDISK_FLAG_LBA; | ||||
| 	    disk->total_sectors = data->cylinders * data->heads * data->sectors; | ||||
| 	    return grub_biosdisk_rw (cmd, disk, sector, size, segment); | ||||
| 	  } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       unsigned coff, hoff, soff; | ||||
|       unsigned head; | ||||
| 
 | ||||
|       /* It is impossible to reach over 8064 MiB (a bit less than LBA24) with
 | ||||
| 	 the traditional CHS access.  */ | ||||
|       if (sector > | ||||
| 	  1024 /* cylinders */ * | ||||
| 	  256 /* heads */ * | ||||
| 	  63 /* spt */) | ||||
| 	return grub_error (GRUB_ERR_OUT_OF_RANGE, "%s out of disk", disk->name); | ||||
| 
 | ||||
|       soff = ((grub_uint32_t) sector) % data->sectors + 1; | ||||
|       head = ((grub_uint32_t) sector) / data->sectors; | ||||
|       hoff = head % data->heads; | ||||
|       coff = head / data->heads; | ||||
| 
 | ||||
|       if (coff >= data->cylinders) | ||||
| 	return grub_error (GRUB_ERR_OUT_OF_RANGE, "%s out of disk", disk->name); | ||||
| 
 | ||||
|       if (grub_biosdisk_rw_standard (cmd + 0x02, data->drive, | ||||
| 				     coff, hoff, soff, size, segment)) | ||||
| 	{ | ||||
| 	  switch (cmd) | ||||
| 	    { | ||||
| 	    case GRUB_BIOSDISK_READ: | ||||
| 	      return grub_error (GRUB_ERR_READ_ERROR, "%s read error", disk->name); | ||||
| 	    case GRUB_BIOSDISK_WRITE: | ||||
| 	      return grub_error (GRUB_ERR_WRITE_ERROR, "%s write error", disk->name); | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| /* 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) | ||||
| { | ||||
|   grub_size_t size; | ||||
|   grub_uint32_t offset; | ||||
| 
 | ||||
|   /* OFFSET = SECTOR % SECTORS */ | ||||
|   grub_divmod64 (sector, sectors, &offset); | ||||
| 
 | ||||
|   size = sectors - offset; | ||||
| 
 | ||||
|   /* Limit the max to 0x7f because of Phoenix EDD.  */ | ||||
|   if (size > 0x7f) | ||||
|     size = 0x7f; | ||||
| 
 | ||||
|   return size; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	} | ||||
| 
 | ||||
|       if (len > size) | ||||
| 	len = size; | ||||
| 
 | ||||
|       if (grub_biosdisk_rw (GRUB_BIOSDISK_READ, disk, sector, len, | ||||
| 			    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; | ||||
|       sector += len; | ||||
|       size -= len; | ||||
|     } | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		     grub_size_t size, const char *buf) | ||||
| { | ||||
|   struct grub_biosdisk_data *data = disk->data; | ||||
| 
 | ||||
|   if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) | ||||
|     return grub_error (GRUB_ERR_IO, "can't write to CDROM"); | ||||
| 
 | ||||
|   while (size) | ||||
|     { | ||||
|       grub_size_t len; | ||||
| 
 | ||||
|       len = get_safe_sectors (sector, data->sectors); | ||||
|       if (len > size) | ||||
| 	len = size; | ||||
| 
 | ||||
|       grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf, | ||||
| 		   len << GRUB_DISK_SECTOR_BITS); | ||||
| 
 | ||||
|       if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len, | ||||
| 			    GRUB_MEMORY_MACHINE_SCRATCH_SEG)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       buf += len << GRUB_DISK_SECTOR_BITS; | ||||
|       sector += len; | ||||
|       size -= len; | ||||
|     } | ||||
| 
 | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_biosdisk_dev = | ||||
|   { | ||||
|     .name = "biosdisk", | ||||
|     .id = GRUB_DISK_DEVICE_BIOSDISK_ID, | ||||
|     .iterate = grub_biosdisk_iterate, | ||||
|     .open = grub_biosdisk_open, | ||||
|     .close = grub_biosdisk_close, | ||||
|     .read = grub_biosdisk_read, | ||||
|     .write = grub_biosdisk_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| static void | ||||
| grub_disk_biosdisk_fini (void) | ||||
| { | ||||
|   grub_disk_dev_unregister (&grub_biosdisk_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_INIT(biosdisk) | ||||
| { | ||||
|   struct grub_biosdisk_cdrp *cdrp | ||||
|         = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; | ||||
| 
 | ||||
|   if (grub_disk_firmware_is_tainted) | ||||
|     { | ||||
|       grub_printf ("Firmware is marked as tainted, refusing to initialize.\n"); | ||||
|       return; | ||||
|     } | ||||
|   grub_disk_firmware_fini = grub_disk_biosdisk_fini; | ||||
| 
 | ||||
|   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)) | ||||
|     cd_drive = cdrp->drive_no; | ||||
| 
 | ||||
|   grub_disk_dev_register (&grub_biosdisk_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(biosdisk) | ||||
| { | ||||
|   grub_disk_biosdisk_fini (); | ||||
| } | ||||
							
								
								
									
										215
									
								
								grub-core/disk/ieee1275/nand.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								grub-core/disk/ieee1275/nand.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,215 @@ | |||
| /* nand.c - NAND flash disk access.  */ | ||||
| /*
 | ||||
|  *  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/misc.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/ieee1275/ieee1275.h> | ||||
| 
 | ||||
| struct grub_nand_data | ||||
| { | ||||
|   grub_ieee1275_ihandle_t handle; | ||||
|   grub_uint32_t block_size; | ||||
| }; | ||||
| 
 | ||||
| static int | ||||
| grub_nand_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   auto int dev_iterate (struct grub_ieee1275_devalias *alias); | ||||
|   int dev_iterate (struct grub_ieee1275_devalias *alias) | ||||
|     { | ||||
|       if (! grub_strcmp (alias->name, "nand")) | ||||
|         { | ||||
|           hook (alias->name); | ||||
|           return 1; | ||||
|         } | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   return grub_devalias_iterate (dev_iterate); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_nand_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
|                 grub_size_t size, char *buf); | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_nand_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   grub_ieee1275_ihandle_t dev_ihandle = 0; | ||||
|   struct grub_nand_data *data = 0; | ||||
|   struct size_args | ||||
|     { | ||||
|       struct grub_ieee1275_common_hdr common; | ||||
|       grub_ieee1275_cell_t method; | ||||
|       grub_ieee1275_cell_t ihandle; | ||||
|       grub_ieee1275_cell_t result; | ||||
|       grub_ieee1275_cell_t size1; | ||||
|       grub_ieee1275_cell_t size2; | ||||
|     } args; | ||||
| 
 | ||||
|   if (! grub_strstr (name, "nand")) | ||||
|     return  grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a NAND device"); | ||||
| 
 | ||||
|   data = grub_malloc (sizeof (*data)); | ||||
|   if (! data) | ||||
|     goto fail; | ||||
| 
 | ||||
|   grub_ieee1275_open (name, &dev_ihandle); | ||||
|   if (! dev_ihandle) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   data->handle = dev_ihandle; | ||||
| 
 | ||||
|   INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 2); | ||||
|   args.method = (grub_ieee1275_cell_t) "block-size"; | ||||
|   args.ihandle = dev_ihandle; | ||||
|   args.result = 1; | ||||
| 
 | ||||
|   if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't get block size"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   data->block_size = (args.size1 >> GRUB_DISK_SECTOR_BITS); | ||||
| 
 | ||||
|   INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 3); | ||||
|   args.method = (grub_ieee1275_cell_t) "size"; | ||||
|   args.ihandle = dev_ihandle; | ||||
|   args.result = 1; | ||||
| 
 | ||||
|   if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't get disk size"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   disk->total_sectors = args.size1; | ||||
|   disk->total_sectors <<= 32; | ||||
|   disk->total_sectors += args.size2; | ||||
|   disk->total_sectors >>= GRUB_DISK_SECTOR_BITS; | ||||
| 
 | ||||
|   disk->id = dev_ihandle; | ||||
| 
 | ||||
|   disk->has_partitions = 0; | ||||
|   disk->data = data; | ||||
| 
 | ||||
|   return 0; | ||||
| 
 | ||||
| fail: | ||||
|   if (dev_ihandle) | ||||
|     grub_ieee1275_close (dev_ihandle); | ||||
|   grub_free (data); | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_nand_close (grub_disk_t disk) | ||||
| { | ||||
|   grub_ieee1275_close (((struct grub_nand_data *) disk->data)->handle); | ||||
|   grub_free (disk->data); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_nand_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
|                 grub_size_t size, char *buf) | ||||
| { | ||||
|   struct grub_nand_data *data = disk->data; | ||||
|   grub_size_t bsize, ofs; | ||||
| 
 | ||||
|   struct read_args | ||||
|     { | ||||
|       struct grub_ieee1275_common_hdr common; | ||||
|       grub_ieee1275_cell_t method; | ||||
|       grub_ieee1275_cell_t ihandle; | ||||
|       grub_ieee1275_cell_t ofs; | ||||
|       grub_ieee1275_cell_t page; | ||||
|       grub_ieee1275_cell_t len; | ||||
|       grub_ieee1275_cell_t buf; | ||||
|       grub_ieee1275_cell_t result; | ||||
|     } args; | ||||
| 
 | ||||
|   INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 1); | ||||
|   args.method = (grub_ieee1275_cell_t) "pio-read"; | ||||
|   args.ihandle = data->handle; | ||||
|   args.buf = (grub_ieee1275_cell_t) buf; | ||||
|   args.page = (grub_ieee1275_cell_t) ((grub_size_t) sector / data->block_size); | ||||
| 
 | ||||
|   ofs = ((grub_size_t) sector % data->block_size) << GRUB_DISK_SECTOR_BITS; | ||||
|   size <<= GRUB_DISK_SECTOR_BITS; | ||||
|   bsize = (data->block_size << GRUB_DISK_SECTOR_BITS); | ||||
| 
 | ||||
|   do | ||||
|     { | ||||
|       grub_size_t len; | ||||
| 
 | ||||
|       len = (ofs + size > bsize) ? (bsize - ofs) : size; | ||||
| 
 | ||||
|       args.len = (grub_ieee1275_cell_t) len; | ||||
|       args.ofs = (grub_ieee1275_cell_t) ofs; | ||||
|       args.result = 1; | ||||
| 
 | ||||
|       if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result)) | ||||
|         return grub_error (GRUB_ERR_READ_ERROR, "read error"); | ||||
| 
 | ||||
|       ofs = 0; | ||||
|       size -= len; | ||||
|       args.buf += len; | ||||
|       args.page++; | ||||
|     } while (size); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_nand_write (grub_disk_t disk __attribute ((unused)), | ||||
|                  grub_disk_addr_t sector __attribute ((unused)), | ||||
|                  grub_size_t size __attribute ((unused)), | ||||
|                  const char *buf __attribute ((unused))) | ||||
| { | ||||
|   return GRUB_ERR_NOT_IMPLEMENTED_YET; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_nand_dev = | ||||
|   { | ||||
|     .name = "nand", | ||||
|     .id = GRUB_DISK_DEVICE_NAND_ID, | ||||
|     .iterate = grub_nand_iterate, | ||||
|     .open = grub_nand_open, | ||||
|     .close = grub_nand_close, | ||||
|     .read = grub_nand_read, | ||||
|     .write = grub_nand_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| GRUB_MOD_INIT(nand) | ||||
| { | ||||
|   grub_disk_dev_register (&grub_nand_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(nand) | ||||
| { | ||||
|   grub_disk_dev_unregister (&grub_nand_dev); | ||||
| } | ||||
							
								
								
									
										285
									
								
								grub-core/disk/ieee1275/ofdisk.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								grub-core/disk/ieee1275/ofdisk.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,285 @@ | |||
| /* ofdisk.c - Open Firmware disk access.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2004,2006,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/misc.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/ieee1275/ieee1275.h> | ||||
| #include <grub/ieee1275/ofdisk.h> | ||||
| 
 | ||||
| struct ofdisk_hash_ent | ||||
| { | ||||
|   char *devpath; | ||||
|   struct ofdisk_hash_ent *next; | ||||
| }; | ||||
| 
 | ||||
| #define OFDISK_HASH_SZ	8 | ||||
| static struct ofdisk_hash_ent *ofdisk_hash[OFDISK_HASH_SZ]; | ||||
| 
 | ||||
| static int | ||||
| ofdisk_hash_fn (const char *devpath) | ||||
| { | ||||
|   int hash = 0; | ||||
|   while (*devpath) | ||||
|     hash ^= *devpath++; | ||||
|   return (hash & (OFDISK_HASH_SZ - 1)); | ||||
| } | ||||
| 
 | ||||
| static struct ofdisk_hash_ent * | ||||
| ofdisk_hash_find (const char *devpath) | ||||
| { | ||||
|   struct ofdisk_hash_ent *p = ofdisk_hash[ofdisk_hash_fn(devpath)]; | ||||
| 
 | ||||
|   while (p) | ||||
|     { | ||||
|       if (!grub_strcmp (p->devpath, devpath)) | ||||
| 	break; | ||||
|       p = p->next; | ||||
|     } | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| static struct ofdisk_hash_ent * | ||||
| ofdisk_hash_add (char *devpath) | ||||
| { | ||||
|   struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; | ||||
|   struct ofdisk_hash_ent *p = grub_malloc(sizeof (*p)); | ||||
| 
 | ||||
|   if (p) | ||||
|     { | ||||
|       p->devpath = devpath; | ||||
|       p->next = *head; | ||||
|       *head = p; | ||||
|     } | ||||
|   return p; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_ofdisk_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   auto int dev_iterate (struct grub_ieee1275_devalias *alias); | ||||
| 
 | ||||
|   int dev_iterate (struct grub_ieee1275_devalias *alias) | ||||
|     { | ||||
|       int ret = 0; | ||||
| 
 | ||||
|       grub_dprintf ("disk", "disk name = %s\n", alias->name); | ||||
| 
 | ||||
|       if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY)) | ||||
| 	{ | ||||
| 	  grub_ieee1275_phandle_t dev; | ||||
| 	  char tmp[8]; | ||||
| 
 | ||||
| 	  if (grub_ieee1275_finddevice (alias->path, &dev)) | ||||
| 	    { | ||||
| 	      grub_dprintf ("disk", "finddevice (%s) failed\n", alias->path); | ||||
| 	      return 0; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_ieee1275_get_property (dev, "iconname", tmp, | ||||
| 					  sizeof tmp, 0)) | ||||
| 	    { | ||||
| 	      grub_dprintf ("disk", "get iconname failed\n"); | ||||
| 	      return 0; | ||||
| 	    } | ||||
| 
 | ||||
| 	  if (grub_strcmp (tmp, "sdmmc")) | ||||
| 	    { | ||||
| 	      grub_dprintf ("disk", "device is not an SD card\n"); | ||||
| 	      return 0; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       if (! grub_strcmp (alias->type, "block") && | ||||
| 	  grub_strncmp (alias->name, "cdrom", 5)) | ||||
| 	ret = hook (alias->name); | ||||
|       return ret; | ||||
|     } | ||||
| 
 | ||||
|   return grub_devalias_iterate (dev_iterate); | ||||
| } | ||||
| 
 | ||||
| static char * | ||||
| compute_dev_path (const char *name) | ||||
| { | ||||
|   char *devpath = grub_malloc (grub_strlen (name) + 3); | ||||
|   char *p, c; | ||||
| 
 | ||||
|   if (!devpath) | ||||
|     return NULL; | ||||
| 
 | ||||
|   /* Un-escape commas. */ | ||||
|   p = devpath; | ||||
|   while ((c = *name++) != '\0') | ||||
|     { | ||||
|       if (c == '\\' && *name == ',') | ||||
| 	{ | ||||
| 	  *p++ = ','; | ||||
| 	  name++; | ||||
| 	} | ||||
|       else | ||||
| 	*p++ = c; | ||||
|     } | ||||
| 
 | ||||
|   if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0)) | ||||
|     { | ||||
|       *p++ = ':'; | ||||
|       *p++ = '0'; | ||||
|     } | ||||
|   *p++ = '\0'; | ||||
| 
 | ||||
|   return devpath; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ofdisk_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   grub_ieee1275_phandle_t dev; | ||||
|   grub_ieee1275_ihandle_t dev_ihandle = 0; | ||||
|   struct ofdisk_hash_ent *op; | ||||
|   char *devpath; | ||||
|   /* XXX: This should be large enough for any possible case.  */ | ||||
|   char prop[64]; | ||||
|   grub_ssize_t actual; | ||||
| 
 | ||||
|   devpath = compute_dev_path (name); | ||||
|   if (! devpath) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   op = ofdisk_hash_find (devpath); | ||||
|   if (!op) | ||||
|     op = ofdisk_hash_add (devpath); | ||||
| 
 | ||||
|   grub_free (devpath); | ||||
|   if (!op) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_dprintf ("disk", "Opening `%s'.\n", op->devpath); | ||||
| 
 | ||||
|   if (grub_ieee1275_finddevice (op->devpath, &dev)) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), | ||||
| 				  &actual)) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   if (grub_strcmp (prop, "block")) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   grub_ieee1275_open (op->devpath, &dev_ihandle); | ||||
|   if (! dev_ihandle) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("disk", "Opened `%s' as handle %p.\n", op->devpath, | ||||
| 		(void *) (unsigned long) dev_ihandle); | ||||
| 
 | ||||
|   /* XXX: There is no property to read the number of blocks.  There
 | ||||
|      should be a property `#blocks', but it is not there.  Perhaps it | ||||
|      is possible to use seek for this.  */ | ||||
|   disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; | ||||
| 
 | ||||
|   disk->id = (unsigned long) op; | ||||
| 
 | ||||
|   /* XXX: Read this, somehow.  */ | ||||
|   disk->has_partitions = 1; | ||||
|   disk->data = (void *) (unsigned long) dev_ihandle; | ||||
|   return 0; | ||||
| 
 | ||||
|  fail: | ||||
|   if (dev_ihandle) | ||||
|     grub_ieee1275_close (dev_ihandle); | ||||
|   return grub_errno; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_ofdisk_close (grub_disk_t disk) | ||||
| { | ||||
|   grub_dprintf ("disk", "Closing handle %p.\n", | ||||
| 		(void *) disk->data); | ||||
|   grub_ieee1275_close ((grub_ieee1275_ihandle_t) (unsigned long) disk->data); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		  grub_size_t size, char *buf) | ||||
| { | ||||
|   grub_ssize_t status, actual; | ||||
|   unsigned long long pos; | ||||
| 
 | ||||
|   pos = sector * 512UL; | ||||
| 
 | ||||
|   grub_ieee1275_seek ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, | ||||
| 		      pos, &status); | ||||
|   if (status < 0) | ||||
|     return grub_error (GRUB_ERR_READ_ERROR, | ||||
| 		       "seek error, can't seek block %llu", | ||||
| 		       (long long) sector); | ||||
|   grub_ieee1275_read ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, | ||||
| 		      buf, size * 512UL, &actual); | ||||
|   if (actual != (grub_ssize_t) (size * 512UL)) | ||||
|     return grub_error (GRUB_ERR_READ_ERROR, "read error on block: %llu", | ||||
| 		       (long long) sector); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_ofdisk_write (grub_disk_t disk __attribute ((unused)), | ||||
| 		   grub_disk_addr_t sector __attribute ((unused)), | ||||
| 		   grub_size_t size __attribute ((unused)), | ||||
| 		   const char *buf __attribute ((unused))) | ||||
| { | ||||
|   return GRUB_ERR_NOT_IMPLEMENTED_YET; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_ofdisk_dev = | ||||
|   { | ||||
|     .name = "ofdisk", | ||||
|     .id = GRUB_DISK_DEVICE_OFDISK_ID, | ||||
|     .iterate = grub_ofdisk_iterate, | ||||
|     .open = grub_ofdisk_open, | ||||
|     .close = grub_ofdisk_close, | ||||
|     .read = grub_ofdisk_read, | ||||
|     .write = grub_ofdisk_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| void | ||||
| grub_ofdisk_init (void) | ||||
| { | ||||
|   grub_disk_dev_register (&grub_ofdisk_dev); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_ofdisk_fini (void) | ||||
| { | ||||
|   grub_disk_dev_unregister (&grub_ofdisk_dev); | ||||
| } | ||||
							
								
								
									
										241
									
								
								grub-core/disk/loopback.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								grub-core/disk/loopback.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,241 @@ | |||
| /* loopback.c - command to add loopback devices.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2005,2006,2007  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/file.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/extcmd.h> | ||||
| #include <grub/i18n.h> | ||||
| 
 | ||||
| struct grub_loopback | ||||
| { | ||||
|   char *devname; | ||||
|   grub_file_t file; | ||||
|   int has_partitions; | ||||
|   struct grub_loopback *next; | ||||
| }; | ||||
| 
 | ||||
| static struct grub_loopback *loopback_list; | ||||
| 
 | ||||
| static const struct grub_arg_option options[] = | ||||
|   { | ||||
|     {"delete", 'd', 0, N_("Delete the loopback device entry."), 0, 0}, | ||||
|     {"partitions", 'p', 0, N_("Simulate a hard drive with partitions."), 0, 0}, | ||||
|     {0, 0, 0, 0, 0, 0} | ||||
|   }; | ||||
| 
 | ||||
| /* Delete the loopback device NAME.  */ | ||||
| static grub_err_t | ||||
| delete_loopback (const char *name) | ||||
| { | ||||
|   struct grub_loopback *dev; | ||||
|   struct grub_loopback **prev; | ||||
| 
 | ||||
|   /* Search for the device.  */ | ||||
|   for (dev = loopback_list, prev = &loopback_list; | ||||
|        dev; | ||||
|        prev = &dev->next, dev = dev->next) | ||||
|     if (grub_strcmp (dev->devname, name) == 0) | ||||
|       break; | ||||
| 
 | ||||
|   if (! dev) | ||||
|     return grub_error (GRUB_ERR_BAD_DEVICE, "device not found"); | ||||
| 
 | ||||
|   /* Remove the device from the list.  */ | ||||
|   *prev = dev->next; | ||||
| 
 | ||||
|   grub_free (dev->devname); | ||||
|   grub_file_close (dev->file); | ||||
|   grub_free (dev); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* The command to add and remove loopback devices.  */ | ||||
| static grub_err_t | ||||
| grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) | ||||
| { | ||||
|   struct grub_arg_list *state = state = cmd->state; | ||||
|   grub_file_t file; | ||||
|   struct grub_loopback *newdev; | ||||
|   grub_err_t ret; | ||||
| 
 | ||||
|   if (argc < 1) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); | ||||
| 
 | ||||
|   /* Check if `-d' was used.  */ | ||||
|   if (state[0].set) | ||||
|       return delete_loopback (args[0]); | ||||
| 
 | ||||
|   if (argc < 2) | ||||
|     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); | ||||
| 
 | ||||
|   file = grub_file_open (args[1]); | ||||
|   if (! file) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* First try to replace the old device.  */ | ||||
|   for (newdev = loopback_list; newdev; newdev = newdev->next) | ||||
|     if (grub_strcmp (newdev->devname, args[0]) == 0) | ||||
|       break; | ||||
| 
 | ||||
|   if (newdev) | ||||
|     { | ||||
|       char *newname = grub_strdup (args[1]); | ||||
|       if (! newname) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       grub_file_close (newdev->file); | ||||
|       newdev->file = file; | ||||
| 
 | ||||
|       /* Set has_partitions when `--partitions' was used.  */ | ||||
|       newdev->has_partitions = state[1].set; | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   /* Unable to replace it, make a new entry.  */ | ||||
|   newdev = grub_malloc (sizeof (struct grub_loopback)); | ||||
|   if (! newdev) | ||||
|     goto fail; | ||||
| 
 | ||||
|   newdev->devname = grub_strdup (args[0]); | ||||
|   if (! newdev->devname) | ||||
|     { | ||||
|       grub_free (newdev); | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   newdev->file = file; | ||||
| 
 | ||||
|   /* Set has_partitions when `--partitions' was used.  */ | ||||
|   newdev->has_partitions = state[1].set; | ||||
| 
 | ||||
|   /* Add the new entry to the list.  */ | ||||
|   newdev->next = loopback_list; | ||||
|   loopback_list = newdev; | ||||
| 
 | ||||
|   return 0; | ||||
| 
 | ||||
| fail: | ||||
|   ret = grub_errno; | ||||
|   grub_file_close (file); | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| static int | ||||
| grub_loopback_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   struct grub_loopback *d; | ||||
|   for (d = loopback_list; d; d = d->next) | ||||
|     { | ||||
|       if (hook (d->devname)) | ||||
| 	return 1; | ||||
|     } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_loopback_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   struct grub_loopback *dev; | ||||
| 
 | ||||
|   for (dev = loopback_list; dev; dev = dev->next) | ||||
|     if (grub_strcmp (dev->devname, name) == 0) | ||||
|       break; | ||||
| 
 | ||||
|   if (! dev) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); | ||||
| 
 | ||||
|   /* Use the filesize for the disk size, round up to a complete sector.  */ | ||||
|   disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) | ||||
| 			 / GRUB_DISK_SECTOR_SIZE); | ||||
|   disk->id = (unsigned long) dev; | ||||
| 
 | ||||
|   disk->has_partitions = dev->has_partitions; | ||||
|   disk->data = dev->file; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		    grub_size_t size, char *buf) | ||||
| { | ||||
|   grub_file_t file = (grub_file_t) disk->data; | ||||
|   grub_off_t pos; | ||||
| 
 | ||||
|   grub_file_seek (file, sector << GRUB_DISK_SECTOR_BITS); | ||||
| 
 | ||||
|   grub_file_read (file, buf, size << GRUB_DISK_SECTOR_BITS); | ||||
|   if (grub_errno) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* In case there is more data read than there is available, in case
 | ||||
|      of files that are not a multiple of GRUB_DISK_SECTOR_SIZE, fill | ||||
|      the rest with zeros.  */ | ||||
|   pos = (sector + size) << GRUB_DISK_SECTOR_BITS; | ||||
|   if (pos > file->size) | ||||
|     { | ||||
|       grub_size_t amount = pos - file->size; | ||||
|       grub_memset (buf + (size << GRUB_DISK_SECTOR_BITS) - amount, 0, amount); | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_loopback_write (grub_disk_t disk __attribute ((unused)), | ||||
| 		     grub_disk_addr_t sector __attribute ((unused)), | ||||
| 		     grub_size_t size __attribute ((unused)), | ||||
| 		     const char *buf __attribute ((unused))) | ||||
| { | ||||
|   return GRUB_ERR_NOT_IMPLEMENTED_YET; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_loopback_dev = | ||||
|   { | ||||
|     .name = "loopback", | ||||
|     .id = GRUB_DISK_DEVICE_LOOPBACK_ID, | ||||
|     .iterate = grub_loopback_iterate, | ||||
|     .open = grub_loopback_open, | ||||
|     .read = grub_loopback_read, | ||||
|     .write = grub_loopback_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| static grub_extcmd_t cmd; | ||||
| 
 | ||||
| GRUB_MOD_INIT(loopback) | ||||
| { | ||||
|   cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, | ||||
| 			      GRUB_COMMAND_FLAG_BOTH, | ||||
| 			      N_("[-d|-p] DEVICENAME FILE."), | ||||
| 			      N_("Make a device of a file."), options); | ||||
|   grub_disk_dev_register (&grub_loopback_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(loopback) | ||||
| { | ||||
|   grub_unregister_extcmd (cmd); | ||||
|   grub_disk_dev_unregister (&grub_loopback_dev); | ||||
| } | ||||
							
								
								
									
										693
									
								
								grub-core/disk/lvm.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										693
									
								
								grub-core/disk/lvm.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,693 @@ | |||
| /* lvm.c - module to read Logical Volumes.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/lvm.h> | ||||
| 
 | ||||
| #ifdef GRUB_UTIL | ||||
| #include <grub/emu/misc.h> | ||||
| #endif | ||||
| 
 | ||||
| static struct grub_lvm_vg *vg_list; | ||||
| static int lv_count; | ||||
| 
 | ||||
|  | ||||
| /* Go the string STR and return the number after STR.  *P will point
 | ||||
|    at the number.  In case STR is not found, *P will be NULL and the | ||||
|    return value will be 0.  */ | ||||
| static int | ||||
| grub_lvm_getvalue (char **p, char *str) | ||||
| { | ||||
|   *p = grub_strstr (*p, str); | ||||
|   if (! *p) | ||||
|     return 0; | ||||
|   *p += grub_strlen (str); | ||||
|   return grub_strtoul (*p, NULL, 10); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_lvm_checkvalue (char **p, char *str, char *tmpl) | ||||
| { | ||||
|   int tmpllen = grub_strlen (tmpl); | ||||
|   *p = grub_strstr (*p, str); | ||||
|   if (! *p) | ||||
|     return 0; | ||||
|   *p += grub_strlen (str); | ||||
|   if (**p != '"') | ||||
|     return 0; | ||||
|   return (grub_memcmp (*p + 1, tmpl, tmpllen) == 0 && (*p)[tmpllen + 1] == '"'); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_lvm_check_flag (char *p, char *str, char *flag) | ||||
| { | ||||
|   int len_str = grub_strlen (str), len_flag = grub_strlen (flag); | ||||
|   while (1) | ||||
|     { | ||||
|       char *q; | ||||
|       p = grub_strstr (p, str); | ||||
|       if (! p) | ||||
| 	return 0; | ||||
|       p += len_str; | ||||
|       if (grub_memcmp (p, " = [", sizeof (" = [") - 1) != 0) | ||||
| 	continue; | ||||
|       q = p + sizeof (" = [") - 1; | ||||
|       while (1) | ||||
| 	{ | ||||
| 	  while (grub_isspace (*q)) | ||||
| 	    q++; | ||||
| 	  if (*q != '"') | ||||
| 	    return 0; | ||||
| 	  q++; | ||||
| 	  if (grub_memcmp (q, flag, len_flag) == 0 && q[len_flag] == '"') | ||||
| 	    return 1; | ||||
| 	  while (*q != '"') | ||||
| 	    q++; | ||||
| 	  q++; | ||||
| 	  if (*q == ']') | ||||
| 	    return 0; | ||||
| 	  q++; | ||||
| 	} | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_lvm_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   struct grub_lvm_vg *vg; | ||||
|   for (vg = vg_list; vg; vg = vg->next) | ||||
|     { | ||||
|       struct grub_lvm_lv *lv; | ||||
|       if (vg->lvs) | ||||
| 	for (lv = vg->lvs; lv; lv = lv->next) | ||||
| 	  if (hook (lv->name)) | ||||
| 	    return 1; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef GRUB_UTIL | ||||
| static grub_disk_memberlist_t | ||||
| grub_lvm_memberlist (grub_disk_t disk) | ||||
| { | ||||
|   struct grub_lvm_lv *lv = disk->data; | ||||
|   grub_disk_memberlist_t list = NULL, tmp; | ||||
|   struct grub_lvm_pv *pv; | ||||
| 
 | ||||
|   if (lv->vg->pvs) | ||||
|     for (pv = lv->vg->pvs; pv; pv = pv->next) | ||||
|       { | ||||
| 	if (!pv->disk) | ||||
| 	  grub_util_error ("Couldn't find PV %s. Check your device.map", | ||||
| 			   pv->name); | ||||
| 	tmp = grub_malloc (sizeof (*tmp)); | ||||
| 	tmp->disk = pv->disk; | ||||
| 	tmp->next = list; | ||||
| 	list = tmp; | ||||
|       } | ||||
| 
 | ||||
|   return list; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_lvm_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   struct grub_lvm_vg *vg; | ||||
|   struct grub_lvm_lv *lv = NULL; | ||||
|   for (vg = vg_list; vg; vg = vg->next) | ||||
|     { | ||||
|       if (vg->lvs) | ||||
| 	for (lv = vg->lvs; lv; lv = lv->next) | ||||
| 	  if (! grub_strcmp (lv->name, name)) | ||||
| 	    break; | ||||
| 
 | ||||
|       if (lv) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   if (! lv) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name); | ||||
| 
 | ||||
|   disk->has_partitions = 0; | ||||
|   disk->id = lv->number; | ||||
|   disk->data = lv; | ||||
|   disk->total_sectors = lv->size; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_lvm_close (grub_disk_t disk __attribute ((unused))) | ||||
| { | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		grub_size_t size, char *buf) | ||||
| { | ||||
|   grub_err_t err = 0; | ||||
|   struct grub_lvm_lv *lv = disk->data; | ||||
|   struct grub_lvm_vg *vg = lv->vg; | ||||
|   struct grub_lvm_segment *seg = lv->segments; | ||||
|   struct grub_lvm_pv *pv; | ||||
|   grub_uint64_t offset; | ||||
|   grub_uint64_t extent; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   extent = grub_divmod64 (sector, vg->extent_size, NULL); | ||||
| 
 | ||||
|   /* Find the right segment.  */ | ||||
|   for (i = 0; i < lv->segment_count; i++) | ||||
|     { | ||||
|       if ((seg->start_extent <= extent) | ||||
| 	  && ((seg->start_extent + seg->extent_count) > extent)) | ||||
| 	{ | ||||
| 	  break; | ||||
| 	} | ||||
| 
 | ||||
|       seg++; | ||||
|     } | ||||
| 
 | ||||
|   if (seg->stripe_count == 1) | ||||
|     { | ||||
|       /* This segment is linear, so that's easy.  We just need to find
 | ||||
| 	 out the offset in the physical volume and read SIZE bytes | ||||
| 	 from that.  */ | ||||
|       struct grub_lvm_stripe *stripe = seg->stripes; | ||||
|       grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */ | ||||
| 
 | ||||
|       pv = stripe->pv; | ||||
|       seg_offset = ((grub_uint64_t) stripe->start | ||||
| 		    * (grub_uint64_t) vg->extent_size) + pv->start; | ||||
| 
 | ||||
|       offset = sector - ((grub_uint64_t) seg->start_extent | ||||
| 			 * (grub_uint64_t) vg->extent_size) + seg_offset; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       /* This is a striped segment. We have to find the right PV
 | ||||
| 	 similar to RAID0. */ | ||||
|       struct grub_lvm_stripe *stripe = seg->stripes; | ||||
|       grub_uint32_t a, b; | ||||
|       grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */ | ||||
|       unsigned int stripenr; | ||||
| 
 | ||||
|       offset = sector - ((grub_uint64_t) seg->start_extent | ||||
| 			 * (grub_uint64_t) vg->extent_size); | ||||
| 
 | ||||
|       a = grub_divmod64 (offset, seg->stripe_size, NULL); | ||||
|       grub_divmod64 (a, seg->stripe_count, &stripenr); | ||||
| 
 | ||||
|       a = grub_divmod64 (offset, seg->stripe_size * seg->stripe_count, NULL); | ||||
|       grub_divmod64 (offset, seg->stripe_size, &b); | ||||
|       offset = a * seg->stripe_size + b; | ||||
| 
 | ||||
|       stripe += stripenr; | ||||
|       pv = stripe->pv; | ||||
| 
 | ||||
|       seg_offset = ((grub_uint64_t) stripe->start | ||||
| 		    * (grub_uint64_t) vg->extent_size) + pv->start; | ||||
| 
 | ||||
|       offset += seg_offset; | ||||
|     } | ||||
| 
 | ||||
|   /* Check whether we actually know the physical volume we want to
 | ||||
|      read from.  */ | ||||
|   if (pv->disk) | ||||
|     err = grub_disk_read (pv->disk, offset, 0, | ||||
| 			  size << GRUB_DISK_SECTOR_BITS, buf); | ||||
|   else | ||||
|     err = grub_error (GRUB_ERR_UNKNOWN_DEVICE, | ||||
| 		      "physical volume %s not found", pv->name); | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_lvm_write (grub_disk_t disk __attribute ((unused)), | ||||
| 		 grub_disk_addr_t sector __attribute ((unused)), | ||||
| 		 grub_size_t size __attribute ((unused)), | ||||
| 		 const char *buf __attribute ((unused))) | ||||
| { | ||||
|   return GRUB_ERR_NOT_IMPLEMENTED_YET; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_lvm_scan_device (const char *name) | ||||
| { | ||||
|   grub_err_t err; | ||||
|   grub_disk_t disk; | ||||
|   grub_uint64_t da_offset, da_size, mda_offset, mda_size; | ||||
|   char buf[GRUB_LVM_LABEL_SIZE]; | ||||
|   char vg_id[GRUB_LVM_ID_STRLEN+1]; | ||||
|   char pv_id[GRUB_LVM_ID_STRLEN+1]; | ||||
|   char *metadatabuf, *p, *q, *vgname; | ||||
|   struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf; | ||||
|   struct grub_lvm_pv_header *pvh; | ||||
|   struct grub_lvm_disk_locn *dlocn; | ||||
|   struct grub_lvm_mda_header *mdah; | ||||
|   struct grub_lvm_raw_locn *rlocn; | ||||
|   unsigned int i, j, vgname_len; | ||||
|   struct grub_lvm_vg *vg; | ||||
|   struct grub_lvm_pv *pv; | ||||
| 
 | ||||
|   disk = grub_disk_open (name); | ||||
|   if (!disk) | ||||
|     return 0; | ||||
| 
 | ||||
|   /* Search for label. */ | ||||
|   for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) | ||||
|     { | ||||
|       err = grub_disk_read (disk, i, 0, sizeof(buf), buf); | ||||
|       if (err) | ||||
| 	goto fail; | ||||
| 
 | ||||
|       if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID, | ||||
| 			   sizeof (lh->id))) | ||||
| 	  && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL, | ||||
| 			      sizeof (lh->type)))) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   /* Return if we didn't find a label. */ | ||||
|   if (i == GRUB_LVM_LABEL_SCAN_SECTORS) | ||||
|     goto fail; | ||||
| 
 | ||||
|   pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl)); | ||||
| 
 | ||||
|   for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++) | ||||
|     { | ||||
|       pv_id[j++] = pvh->pv_uuid[i]; | ||||
|       if ((i != 1) && (i != 29) && (i % 4 == 1)) | ||||
| 	pv_id[j++] = '-'; | ||||
|     } | ||||
|   pv_id[j] = '\0'; | ||||
| 
 | ||||
|   dlocn = pvh->disk_areas_xl; | ||||
|   da_offset = grub_le_to_cpu64 (dlocn->offset); | ||||
|   da_size = grub_le_to_cpu64 (dlocn->size); | ||||
| 
 | ||||
|   dlocn++; | ||||
|   /* Is it possible to have multiple data/metadata areas? I haven't
 | ||||
|      seen devices that have it. */ | ||||
|   if (dlocn->offset) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		  "we don't support multiple LVM data areas"); | ||||
| 
 | ||||
|       goto fail; | ||||
|     } | ||||
| 
 | ||||
|   dlocn++; | ||||
|   mda_offset = grub_le_to_cpu64 (dlocn->offset); | ||||
|   mda_size = grub_le_to_cpu64 (dlocn->size); | ||||
| 
 | ||||
|   /* It's possible to have multiple copies of metadata areas, we just use the
 | ||||
|      first one.  */ | ||||
| 
 | ||||
|   /* Allocate buffer space for the circular worst-case scenario. */ | ||||
|   metadatabuf = grub_malloc (2 * mda_size); | ||||
|   if (! metadatabuf) | ||||
|     goto fail; | ||||
| 
 | ||||
|   err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf); | ||||
|   if (err) | ||||
|     goto fail2; | ||||
| 
 | ||||
|   mdah = (struct grub_lvm_mda_header *) metadatabuf; | ||||
|   if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC, | ||||
| 		     sizeof (mdah->magic))) | ||||
|       || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION)) | ||||
|     { | ||||
|       grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		  "unknown LVM metadata header"); | ||||
|       goto fail2; | ||||
|     } | ||||
| 
 | ||||
|   rlocn = mdah->raw_locns; | ||||
|   if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) > | ||||
|       grub_le_to_cpu64 (mdah->size)) | ||||
|     { | ||||
|       /* Metadata is circular. Copy the wrap in place. */ | ||||
|       grub_memcpy (metadatabuf + mda_size, | ||||
|                    metadatabuf + GRUB_LVM_MDA_HEADER_SIZE, | ||||
|                    grub_le_to_cpu64 (rlocn->offset) + | ||||
|                    grub_le_to_cpu64 (rlocn->size) - | ||||
|                    grub_le_to_cpu64 (mdah->size)); | ||||
|     } | ||||
|   p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset); | ||||
| 
 | ||||
|   while (*q != ' ' && q < metadatabuf + mda_size) | ||||
|     q++; | ||||
| 
 | ||||
|   if (q == metadatabuf + mda_size) | ||||
|     goto fail2; | ||||
| 
 | ||||
|   vgname_len = q - p; | ||||
|   vgname = grub_malloc (vgname_len + 1); | ||||
|   if (!vgname) | ||||
|     goto fail2; | ||||
| 
 | ||||
|   grub_memcpy (vgname, p, vgname_len); | ||||
|   vgname[vgname_len] = '\0'; | ||||
| 
 | ||||
|   p = grub_strstr (q, "id = \""); | ||||
|   if (p == NULL) | ||||
|     goto fail3; | ||||
|   p += sizeof ("id = \"") - 1; | ||||
|   grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN); | ||||
|   vg_id[GRUB_LVM_ID_STRLEN] = '\0'; | ||||
| 
 | ||||
|   for (vg = vg_list; vg; vg = vg->next) | ||||
|     { | ||||
|       if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN)) | ||||
| 	break; | ||||
|     } | ||||
| 
 | ||||
|   if (! vg) | ||||
|     { | ||||
|       /* First time we see this volume group. We've to create the
 | ||||
| 	 whole volume group structure. */ | ||||
|       vg = grub_malloc (sizeof (*vg)); | ||||
|       if (! vg) | ||||
| 	goto fail3; | ||||
|       vg->name = vgname; | ||||
|       grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1); | ||||
| 
 | ||||
|       vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); | ||||
|       if (p == NULL) | ||||
| 	goto fail4; | ||||
| 
 | ||||
|       vg->lvs = NULL; | ||||
|       vg->pvs = NULL; | ||||
| 
 | ||||
|       p = grub_strstr (p, "physical_volumes {"); | ||||
|       if (p) | ||||
| 	{ | ||||
| 	  p += sizeof ("physical_volumes {") - 1; | ||||
| 
 | ||||
| 	  /* Add all the pvs to the volume group. */ | ||||
| 	  while (1) | ||||
| 	    { | ||||
| 	      int s; | ||||
| 	      while (grub_isspace (*p)) | ||||
| 		p++; | ||||
| 
 | ||||
| 	      if (*p == '}') | ||||
| 		break; | ||||
| 
 | ||||
| 	      pv = grub_malloc (sizeof (*pv)); | ||||
| 	      q = p; | ||||
| 	      while (*q != ' ') | ||||
| 		q++; | ||||
| 
 | ||||
| 	      s = q - p; | ||||
| 	      pv->name = grub_malloc (s + 1); | ||||
| 	      grub_memcpy (pv->name, p, s); | ||||
| 	      pv->name[s] = '\0'; | ||||
| 
 | ||||
| 	      p = grub_strstr (p, "id = \""); | ||||
| 	      if (p == NULL) | ||||
| 		goto pvs_fail; | ||||
| 	      p += sizeof("id = \"") - 1; | ||||
| 
 | ||||
| 	      grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN); | ||||
| 	      pv->id[GRUB_LVM_ID_STRLEN] = '\0'; | ||||
| 
 | ||||
| 	      pv->start = grub_lvm_getvalue (&p, "pe_start = "); | ||||
| 	      if (p == NULL) | ||||
| 		goto pvs_fail; | ||||
| 
 | ||||
| 	      p = grub_strchr (p, '}'); | ||||
| 	      if (p == NULL) | ||||
| 		goto pvs_fail; | ||||
| 	      p++; | ||||
| 
 | ||||
| 	      pv->disk = NULL; | ||||
| 	      pv->next = vg->pvs; | ||||
| 	      vg->pvs = pv; | ||||
| 
 | ||||
| 	      continue; | ||||
| 	    pvs_fail: | ||||
| 	      grub_free (pv->name); | ||||
| 	      grub_free (pv); | ||||
| 	      goto fail4; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       p = grub_strstr (p, "logical_volumes"); | ||||
|       if (p) | ||||
| 	{ | ||||
| 	  p += 18; | ||||
| 
 | ||||
| 	  /* And add all the lvs to the volume group. */ | ||||
| 	  while (1) | ||||
| 	    { | ||||
| 	      int s; | ||||
| 	      int skip_lv = 0; | ||||
| 	      struct grub_lvm_lv *lv; | ||||
| 	      struct grub_lvm_segment *seg; | ||||
| 
 | ||||
| 	      while (grub_isspace (*p)) | ||||
| 		p++; | ||||
| 
 | ||||
| 	      if (*p == '}') | ||||
| 		break; | ||||
| 
 | ||||
| 	      lv = grub_malloc (sizeof (*lv)); | ||||
| 
 | ||||
| 	      q = p; | ||||
| 	      while (*q != ' ') | ||||
| 		q++; | ||||
| 
 | ||||
| 	      s = q - p; | ||||
| 	      lv->name = grub_malloc (vgname_len + 1 + s + 1); | ||||
| 	      grub_memcpy (lv->name, vgname, vgname_len); | ||||
| 	      lv->name[vgname_len] = '-'; | ||||
| 	      grub_memcpy (lv->name + vgname_len + 1, p, s); | ||||
| 	      lv->name[vgname_len + 1 + s] = '\0'; | ||||
| 
 | ||||
| 	      lv->size = 0; | ||||
| 
 | ||||
| 	      if (!grub_lvm_check_flag (p, "status", "VISIBLE")) | ||||
| 		{ | ||||
| 		  skip_lv = 1; | ||||
| 		  goto lv_parsed; | ||||
| 		} | ||||
| 
 | ||||
| 	      lv->segment_count = grub_lvm_getvalue (&p, "segment_count = "); | ||||
| 	      if (p == NULL) | ||||
| 		goto lvs_fail; | ||||
| 	      lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count); | ||||
| 	      seg = lv->segments; | ||||
| 
 | ||||
| 	      for (i = 0; i < lv->segment_count; i++) | ||||
| 		{ | ||||
| 		  struct grub_lvm_stripe *stripe; | ||||
| 
 | ||||
| 		  p = grub_strstr (p, "segment"); | ||||
| 		  if (p == NULL) | ||||
| 		    goto lvs_segment_fail; | ||||
| 
 | ||||
| 		  seg->start_extent = grub_lvm_getvalue (&p, "start_extent = "); | ||||
| 		  if (p == NULL) | ||||
| 		    goto lvs_segment_fail; | ||||
| 		  seg->extent_count = grub_lvm_getvalue (&p, "extent_count = "); | ||||
| 		  if (p == NULL) | ||||
| 		    goto lvs_segment_fail; | ||||
| 
 | ||||
| 		  if (grub_lvm_checkvalue (&p, "type = ", "snapshot")) | ||||
| 		    { | ||||
| 		      /* Found a snapshot, give up and move on. */ | ||||
| 		      skip_lv = 1; | ||||
| 		      break; | ||||
| 		    } | ||||
| 
 | ||||
| 		  seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = "); | ||||
| 		  if (p == NULL) | ||||
| 		    goto lvs_segment_fail; | ||||
| 
 | ||||
| 		  lv->size += seg->extent_count * vg->extent_size; | ||||
| 
 | ||||
| 		  if (seg->stripe_count != 1) | ||||
| 		    seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); | ||||
| 
 | ||||
| 		  seg->stripes = grub_malloc (sizeof (*stripe) | ||||
| 					      * seg->stripe_count); | ||||
| 		  stripe = seg->stripes; | ||||
| 
 | ||||
| 		  p = grub_strstr (p, "stripes = ["); | ||||
| 		  if (p == NULL) | ||||
| 		    goto lvs_segment_fail2; | ||||
| 		  p += sizeof("stripes = [") - 1; | ||||
| 
 | ||||
| 		  for (j = 0; j < seg->stripe_count; j++) | ||||
| 		    { | ||||
| 		      char *pvname; | ||||
| 
 | ||||
| 		      p = grub_strchr (p, '"'); | ||||
| 		      if (p == NULL) | ||||
| 			continue; | ||||
| 		      q = ++p; | ||||
| 		      while (*q != '"') | ||||
| 			q++; | ||||
| 
 | ||||
| 		      s = q - p; | ||||
| 
 | ||||
| 		      pvname = grub_malloc (s + 1); | ||||
|                       if (pvname == NULL) | ||||
|                         goto lvs_segment_fail2; | ||||
| 
 | ||||
| 		      grub_memcpy (pvname, p, s); | ||||
| 		      pvname[s] = '\0'; | ||||
| 
 | ||||
| 		      if (vg->pvs) | ||||
| 			for (pv = vg->pvs; pv; pv = pv->next) | ||||
| 			  { | ||||
| 			    if (! grub_strcmp (pvname, pv->name)) | ||||
| 			      { | ||||
| 				stripe->pv = pv; | ||||
| 				break; | ||||
| 			      } | ||||
| 			  } | ||||
| 
 | ||||
| 		      grub_free(pvname); | ||||
| 
 | ||||
| 		      stripe->start = grub_lvm_getvalue (&p, ","); | ||||
| 		      if (p == NULL) | ||||
| 			continue; | ||||
| 
 | ||||
| 		      stripe++; | ||||
| 		    } | ||||
| 
 | ||||
| 		  seg++; | ||||
| 
 | ||||
| 		  continue; | ||||
| 		lvs_segment_fail2: | ||||
| 		  grub_free (seg->stripes); | ||||
| 		lvs_segment_fail: | ||||
| 		  goto fail4; | ||||
| 		} | ||||
| 
 | ||||
| 	    lv_parsed: | ||||
| 	      if (p != NULL) | ||||
| 		p = grub_strchr (p, '}'); | ||||
| 	      if (p == NULL) | ||||
| 		goto lvs_fail; | ||||
| 	      p += 3; | ||||
| 
 | ||||
| 	      if (skip_lv) | ||||
| 		{ | ||||
| 		  grub_free (lv->name); | ||||
| 		  grub_free (lv); | ||||
| 		  continue; | ||||
| 		} | ||||
| 
 | ||||
| 	      lv->number = lv_count++; | ||||
| 	      lv->vg = vg; | ||||
| 	      lv->next = vg->lvs; | ||||
| 	      vg->lvs = lv; | ||||
| 
 | ||||
| 	      continue; | ||||
| 	    lvs_fail: | ||||
| 	      grub_free (lv->name); | ||||
| 	      grub_free (lv); | ||||
| 	      goto fail4; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
| 	vg->next = vg_list; | ||||
| 	vg_list = vg; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       grub_free (vgname); | ||||
|     } | ||||
| 
 | ||||
|   /* Match the device we are currently reading from with the right
 | ||||
|      PV. */ | ||||
|   if (vg->pvs) | ||||
|     for (pv = vg->pvs; pv; pv = pv->next) | ||||
|       { | ||||
| 	if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN)) | ||||
| 	  { | ||||
| 	    /* This could happen to LVM on RAID, pv->disk points to the
 | ||||
| 	       raid device, we shouldn't change it.  */ | ||||
| 	    if (! pv->disk) | ||||
| 	      pv->disk = grub_disk_open (name); | ||||
| 	    break; | ||||
| 	  } | ||||
|       } | ||||
| 
 | ||||
|   goto fail2; | ||||
| 
 | ||||
|   /* Failure path.  */ | ||||
|  fail4: | ||||
|   grub_free (vg); | ||||
|  fail3: | ||||
|   grub_free (vgname); | ||||
| 
 | ||||
|   /* Normal exit path.  */ | ||||
|  fail2: | ||||
|   grub_free (metadatabuf); | ||||
|  fail: | ||||
|   grub_disk_close (disk); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_lvm_dev = | ||||
|   { | ||||
|     .name = "lvm", | ||||
|     .id = GRUB_DISK_DEVICE_LVM_ID, | ||||
|     .iterate = grub_lvm_iterate, | ||||
|     .open = grub_lvm_open, | ||||
|     .close = grub_lvm_close, | ||||
|     .read = grub_lvm_read, | ||||
|     .write = grub_lvm_write, | ||||
| #ifdef GRUB_UTIL | ||||
|     .memberlist = grub_lvm_memberlist, | ||||
| #endif | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
|  | ||||
| GRUB_MOD_INIT(lvm) | ||||
| { | ||||
|   grub_device_iterate (&grub_lvm_scan_device); | ||||
|   if (grub_errno) | ||||
|     { | ||||
|       grub_print_error (); | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|     } | ||||
| 
 | ||||
|   grub_disk_dev_register (&grub_lvm_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(lvm) | ||||
| { | ||||
|   grub_disk_dev_unregister (&grub_lvm_dev); | ||||
|   /* FIXME: free the lvm list. */ | ||||
| } | ||||
							
								
								
									
										424
									
								
								grub-core/disk/mdraid_linux.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								grub-core/disk/mdraid_linux.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,424 @@ | |||
| /* mdraid_linux.c - module to handle Linux Software RAID.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/raid.h> | ||||
| 
 | ||||
| /* Linux RAID on disk structures and constants,
 | ||||
|    copied from include/linux/raid/md_p.h.  */ | ||||
| 
 | ||||
| #define RESERVED_BYTES			(64 * 1024) | ||||
| #define RESERVED_SECTORS		(RESERVED_BYTES / 512) | ||||
| 
 | ||||
| #define NEW_SIZE_SECTORS(x)		((x & ~(RESERVED_SECTORS - 1)) \ | ||||
| 					- RESERVED_SECTORS) | ||||
| 
 | ||||
| #define SB_BYTES			4096 | ||||
| #define SB_WORDS			(SB_BYTES / 4) | ||||
| #define SB_SECTORS			(SB_BYTES / 512) | ||||
| 
 | ||||
| /*
 | ||||
|  * The following are counted in 32-bit words | ||||
|  */ | ||||
| #define	SB_GENERIC_OFFSET		0 | ||||
| 
 | ||||
| #define SB_PERSONALITY_OFFSET		64 | ||||
| #define SB_DISKS_OFFSET			128 | ||||
| #define SB_DESCRIPTOR_OFFSET		992 | ||||
| 
 | ||||
| #define SB_GENERIC_CONSTANT_WORDS	32 | ||||
| #define SB_GENERIC_STATE_WORDS		32 | ||||
| #define SB_GENERIC_WORDS		(SB_GENERIC_CONSTANT_WORDS + \ | ||||
|                                          SB_GENERIC_STATE_WORDS) | ||||
| 
 | ||||
| #define SB_PERSONALITY_WORDS		64 | ||||
| #define SB_DESCRIPTOR_WORDS		32 | ||||
| #define SB_DISKS			27 | ||||
| #define SB_DISKS_WORDS			(SB_DISKS * SB_DESCRIPTOR_WORDS) | ||||
| 
 | ||||
| #define SB_RESERVED_WORDS		(1024 \ | ||||
|                                          - SB_GENERIC_WORDS \ | ||||
|                                          - SB_PERSONALITY_WORDS \ | ||||
|                                          - SB_DISKS_WORDS \ | ||||
|                                          - SB_DESCRIPTOR_WORDS) | ||||
| 
 | ||||
| #define SB_EQUAL_WORDS			(SB_GENERIC_WORDS \ | ||||
|                                          + SB_PERSONALITY_WORDS \ | ||||
|                                          + SB_DISKS_WORDS) | ||||
| 
 | ||||
| /*
 | ||||
|  * Device "operational" state bits | ||||
|  */ | ||||
| #define DISK_FAULTY			0 | ||||
| #define DISK_ACTIVE			1 | ||||
| #define DISK_SYNC			2 | ||||
| #define DISK_REMOVED			3 | ||||
| 
 | ||||
| #define	DISK_WRITEMOSTLY		9 | ||||
| 
 | ||||
| #define SB_MAGIC			0xa92b4efc | ||||
| 
 | ||||
| /*
 | ||||
|  * Superblock state bits | ||||
|  */ | ||||
| #define SB_CLEAN			0 | ||||
| #define SB_ERRORS			1 | ||||
| 
 | ||||
| #define	SB_BITMAP_PRESENT		8 | ||||
| 
 | ||||
| struct grub_raid_disk_09 | ||||
| { | ||||
|   grub_uint32_t number;		/* Device number in the entire set.  */ | ||||
|   grub_uint32_t major;		/* Device major number.  */ | ||||
|   grub_uint32_t minor;		/* Device minor number.  */ | ||||
|   grub_uint32_t raid_disk;	/* The role of the device in the raid set.  */ | ||||
|   grub_uint32_t state;		/* Operational state.  */ | ||||
|   grub_uint32_t reserved[SB_DESCRIPTOR_WORDS - 5]; | ||||
| }; | ||||
| 
 | ||||
| struct grub_raid_super_09 | ||||
| { | ||||
|   /*
 | ||||
|    * Constant generic information | ||||
|    */ | ||||
|   grub_uint32_t md_magic;	/* MD identifier.  */ | ||||
|   grub_uint32_t major_version;	/* Major version.  */ | ||||
|   grub_uint32_t minor_version;	/* Minor version.  */ | ||||
|   grub_uint32_t patch_version;	/* Patchlevel version.  */ | ||||
|   grub_uint32_t gvalid_words;	/* Number of used words in this section.  */ | ||||
|   grub_uint32_t set_uuid0;	/* Raid set identifier.  */ | ||||
|   grub_uint32_t ctime;		/* Creation time.  */ | ||||
|   grub_uint32_t level;		/* Raid personality.  */ | ||||
|   grub_uint32_t size;		/* Apparent size of each individual disk.  */ | ||||
|   grub_uint32_t nr_disks;	/* Total disks in the raid set.  */ | ||||
|   grub_uint32_t raid_disks;	/* Disks in a fully functional raid set.  */ | ||||
|   grub_uint32_t md_minor;	/* Preferred MD minor device number.  */ | ||||
|   grub_uint32_t not_persistent;	/* Does it have a persistent superblock.  */ | ||||
|   grub_uint32_t set_uuid1;	/* Raid set identifier #2.  */ | ||||
|   grub_uint32_t set_uuid2;	/* Raid set identifier #3.  */ | ||||
|   grub_uint32_t set_uuid3;	/* Raid set identifier #4.  */ | ||||
|   grub_uint32_t gstate_creserved[SB_GENERIC_CONSTANT_WORDS - 16]; | ||||
| 
 | ||||
|   /*
 | ||||
|    * Generic state information | ||||
|    */ | ||||
|   grub_uint32_t utime;		/* Superblock update time.  */ | ||||
|   grub_uint32_t state;		/* State bits (clean, ...).  */ | ||||
|   grub_uint32_t active_disks;	/* Number of currently active disks.  */ | ||||
|   grub_uint32_t working_disks;	/* Number of working disks.  */ | ||||
|   grub_uint32_t failed_disks;	/* Number of failed disks.  */ | ||||
|   grub_uint32_t spare_disks;	/* Number of spare disks.  */ | ||||
|   grub_uint32_t sb_csum;	/* Checksum of the whole superblock.  */ | ||||
|   grub_uint64_t events;		/* Superblock update count.  */ | ||||
|   grub_uint64_t cp_events;	/* Checkpoint update count.  */ | ||||
|   grub_uint32_t recovery_cp;	/* Recovery checkpoint sector count.  */ | ||||
|   grub_uint32_t gstate_sreserved[SB_GENERIC_STATE_WORDS - 12]; | ||||
| 
 | ||||
|   /*
 | ||||
|    * Personality information | ||||
|    */ | ||||
|   grub_uint32_t layout;		/* The array's physical layout.  */ | ||||
|   grub_uint32_t chunk_size;	/* Chunk size in bytes.  */ | ||||
|   grub_uint32_t root_pv;	/* LV root PV.  */ | ||||
|   grub_uint32_t root_block;	/* LV root block.  */ | ||||
|   grub_uint32_t pstate_reserved[SB_PERSONALITY_WORDS - 4]; | ||||
| 
 | ||||
|   /*
 | ||||
|    * Disks information | ||||
|    */ | ||||
|   struct grub_raid_disk_09 disks[SB_DISKS]; | ||||
| 
 | ||||
|   /*
 | ||||
|    * Reserved | ||||
|    */ | ||||
|   grub_uint32_t reserved[SB_RESERVED_WORDS]; | ||||
| 
 | ||||
|   /*
 | ||||
|    * Active descriptor | ||||
|    */ | ||||
|   struct grub_raid_disk_09 this_disk; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| /*
 | ||||
|  * The version-1 superblock : | ||||
|  * All numeric fields are little-endian. | ||||
|  * | ||||
|  * Total size: 256 bytes plus 2 per device. | ||||
|  * 1K allows 384 devices. | ||||
|  */ | ||||
| 
 | ||||
| struct grub_raid_super_1x | ||||
| { | ||||
|   /* Constant array information - 128 bytes.  */ | ||||
|   grub_uint32_t magic;		/* MD_SB_MAGIC: 0xa92b4efc - little endian.  */ | ||||
|   grub_uint32_t major_version;	/* 1.  */ | ||||
|   grub_uint32_t feature_map;	/* Bit 0 set if 'bitmap_offset' is meaningful.   */ | ||||
|   grub_uint32_t pad0;		/* Always set to 0 when writing.  */ | ||||
| 
 | ||||
|   grub_uint8_t set_uuid[16];	/* User-space generated.  */ | ||||
|   char set_name[32];		/* Set and interpreted by user-space.  */ | ||||
| 
 | ||||
|   grub_uint64_t ctime;		/* Lo 40 bits are seconds, top 24 are microseconds or 0.  */ | ||||
|   grub_uint32_t level;		/* -4 (multipath), -1 (linear), 0,1,4,5.  */ | ||||
|   grub_uint32_t layout;		/* only for raid5 and raid10 currently.  */ | ||||
|   grub_uint64_t size;		/* Used size of component devices, in 512byte sectors.  */ | ||||
| 
 | ||||
|   grub_uint32_t chunksize;	/* In 512byte sectors.  */ | ||||
|   grub_uint32_t raid_disks; | ||||
|   grub_uint32_t bitmap_offset;	/* Sectors after start of superblock that bitmap starts
 | ||||
| 				 * NOTE: signed, so bitmap can be before superblock | ||||
| 				 * only meaningful of feature_map[0] is set. | ||||
| 				 */ | ||||
| 
 | ||||
|   /* These are only valid with feature bit '4'.  */ | ||||
|   grub_uint32_t new_level;	/* New level we are reshaping to.  */ | ||||
|   grub_uint64_t reshape_position;	/* Next address in array-space for reshape.  */ | ||||
|   grub_uint32_t delta_disks;	/* Change in number of raid_disks.  */ | ||||
|   grub_uint32_t new_layout;	/* New layout.  */ | ||||
|   grub_uint32_t new_chunk;	/* New chunk size (512byte sectors).  */ | ||||
|   grub_uint8_t pad1[128 - 124];	/* Set to 0 when written.  */ | ||||
| 
 | ||||
|   /* Constant this-device information - 64 bytes.  */ | ||||
|   grub_uint64_t data_offset;	/* Sector start of data, often 0.  */ | ||||
|   grub_uint64_t data_size;	/* Sectors in this device that can be used for data.  */ | ||||
|   grub_uint64_t super_offset;	/* Sector start of this superblock.  */ | ||||
|   grub_uint64_t recovery_offset;	/* Sectors before this offset (from data_offset) have been recovered.  */ | ||||
|   grub_uint32_t dev_number;	/* Permanent identifier of this  device - not role in raid.  */ | ||||
|   grub_uint32_t cnt_corrected_read;	/* Number of read errors that were corrected by re-writing.  */ | ||||
|   grub_uint8_t device_uuid[16];	/* User-space setable, ignored by kernel.  */ | ||||
|   grub_uint8_t devflags;	/* Per-device flags.  Only one defined...  */ | ||||
|   grub_uint8_t pad2[64 - 57];	/* Set to 0 when writing.  */ | ||||
| 
 | ||||
|   /* Array state information - 64 bytes.  */ | ||||
|   grub_uint64_t utime;		/* 40 bits second, 24 btes microseconds.  */ | ||||
|   grub_uint64_t events;		/* Incremented when superblock updated.  */ | ||||
|   grub_uint64_t resync_offset;	/* Data before this offset (from data_offset) known to be in sync.  */ | ||||
|   grub_uint32_t sb_csum;	/* Checksum upto devs[max_dev].  */ | ||||
|   grub_uint32_t max_dev;	/* Size of devs[] array to consider.  */ | ||||
|   grub_uint8_t pad3[64 - 32];	/* Set to 0 when writing.  */ | ||||
| 
 | ||||
|   /* Device state information. Indexed by dev_number.
 | ||||
|    * 2 bytes per device. | ||||
|    * Note there are no per-device state flags. State information is rolled | ||||
|    * into the 'roles' value.  If a device is spare or faulty, then it doesn't | ||||
|    * have a meaningful role. | ||||
|    */ | ||||
|   grub_uint16_t dev_roles[0];	/* Role in array, or 0xffff for a spare, or 0xfffe for faulty.  */ | ||||
| }; | ||||
| /* Could be __attribute__ ((packed)), but since all members in this struct
 | ||||
|    are already appropriately aligned, we can omit this and avoid suboptimal | ||||
|    assembly in some cases.  */ | ||||
| 
 | ||||
| #define WriteMostly1    1	/* Mask for writemostly flag in above devflags.  */ | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_mdraid_detect_09 (grub_disk_addr_t sector, | ||||
| 		       struct grub_raid_super_09 *sb, | ||||
| 		       struct grub_raid_array *array, | ||||
| 		       grub_disk_addr_t *start_sector) | ||||
| { | ||||
|   grub_uint32_t *uuid; | ||||
| 
 | ||||
|   if (sb->major_version != 0 || sb->minor_version != 90) | ||||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		       "unsupported RAID version: %d.%d", | ||||
| 		       sb->major_version, sb->minor_version); | ||||
| 
 | ||||
|   /* FIXME: Check the checksum.  */ | ||||
| 
 | ||||
|   /* Multipath.  */ | ||||
|   if ((int) sb->level == -4) | ||||
|     sb->level = 1; | ||||
| 
 | ||||
|   if (sb->level != 0 && sb->level != 1 && sb->level != 4 && | ||||
|       sb->level != 5 && sb->level != 6 && sb->level != 10) | ||||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		       "unsupported RAID level: %d", sb->level); | ||||
| 
 | ||||
|   array->name = NULL; | ||||
|   array->number = sb->md_minor; | ||||
|   array->level = sb->level; | ||||
|   array->layout = sb->layout; | ||||
|   array->total_devs = sb->raid_disks; | ||||
|   array->disk_size = (sb->size) ? sb->size * 2 : sector; | ||||
|   array->chunk_size = sb->chunk_size >> 9; | ||||
|   array->index = sb->this_disk.number; | ||||
|   array->uuid_len = 16; | ||||
|   array->uuid = grub_malloc (16); | ||||
|   if (!array->uuid) | ||||
|       return grub_errno; | ||||
| 
 | ||||
|   uuid = (grub_uint32_t *) array->uuid; | ||||
|   uuid[0] = sb->set_uuid0; | ||||
|   uuid[1] = sb->set_uuid1; | ||||
|   uuid[2] = sb->set_uuid2; | ||||
|   uuid[3] = sb->set_uuid3; | ||||
| 
 | ||||
|   *start_sector = 0; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_mdraid_detect_1x (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		       struct grub_raid_super_1x *sb, | ||||
| 		       struct grub_raid_array *array, | ||||
| 		       grub_disk_addr_t *start_sector) | ||||
| { | ||||
|   grub_uint64_t sb_size; | ||||
|   struct grub_raid_super_1x *real_sb; | ||||
| 
 | ||||
|   if (sb->major_version != 1) | ||||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		       "Unsupported RAID version: %d", | ||||
| 		       sb->major_version); | ||||
| 
 | ||||
|   /* Multipath.  */ | ||||
|   if ((int) sb->level == -4) | ||||
|     sb->level = 1; | ||||
| 
 | ||||
|   if (sb->level != 0 && sb->level != 1 && sb->level != 4 && | ||||
|       sb->level != 5 && sb->level != 6 && sb->level != 10) | ||||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		       "Unsupported RAID level: %d", sb->level); | ||||
| 
 | ||||
|   /* 1.x superblocks don't have a fixed size on disk.  So we have to
 | ||||
|      read it again now that we now the max device count.  */ | ||||
|   sb_size = sizeof (struct grub_raid_super_1x) + 2 * grub_le_to_cpu32 (sb->max_dev); | ||||
|   real_sb = grub_malloc (sb_size); | ||||
|   if (! real_sb) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   if (grub_disk_read (disk, sector, 0, sb_size, real_sb)) | ||||
|     { | ||||
|       grub_free (real_sb); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   array->name = grub_strdup (real_sb->set_name); | ||||
|   if (! array->name) | ||||
|     { | ||||
|       grub_free (real_sb); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   array->number = 0; | ||||
|   array->level = grub_le_to_cpu32 (real_sb->level); | ||||
|   array->layout = grub_le_to_cpu32 (real_sb->layout); | ||||
|   array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks); | ||||
|   array->disk_size = grub_le_to_cpu64 (real_sb->size); | ||||
|   array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize); | ||||
|   if (grub_le_to_cpu32 (real_sb->dev_number) < | ||||
|       grub_le_to_cpu32 (real_sb->max_dev)) | ||||
|     array->index = grub_le_to_cpu16 | ||||
|       (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); | ||||
|   else | ||||
|     array->index = 0xffff;  /* disk will be later not used! */ | ||||
|   array->uuid_len = 16; | ||||
|   array->uuid = grub_malloc (16); | ||||
|   if (!array->uuid) | ||||
|     { | ||||
|       grub_free (real_sb); | ||||
|       return grub_errno; | ||||
|     } | ||||
| 
 | ||||
|   grub_memcpy (array->uuid, real_sb->set_uuid, 16); | ||||
| 
 | ||||
|   *start_sector = real_sb->data_offset; | ||||
| 
 | ||||
|   grub_free (real_sb); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, | ||||
| 		    grub_disk_addr_t *start_sector) | ||||
| { | ||||
|   grub_disk_addr_t sector; | ||||
|   grub_uint64_t size; | ||||
|   struct grub_raid_super_09 sb_09; | ||||
|   struct grub_raid_super_1x sb_1x; | ||||
|   grub_uint8_t minor_version; | ||||
| 
 | ||||
|   /* The sector where the mdraid 0.90 superblock is stored, if available.  */ | ||||
|   size = grub_disk_get_size (disk); | ||||
|   sector = NEW_SIZE_SECTORS (size); | ||||
| 
 | ||||
|   if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb_09)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* Look whether there is a mdraid 0.90 superblock.  */ | ||||
|   if (sb_09.md_magic == SB_MAGIC) | ||||
|     return grub_mdraid_detect_09 (sector, &sb_09, array, start_sector); | ||||
| 
 | ||||
|   /* Check for an 1.x superblock.
 | ||||
|    * It's always aligned to a 4K boundary | ||||
|    * and depending on the minor version it can be: | ||||
|    * 0: At least 8K, but less than 12K, from end of device | ||||
|    * 1: At start of device | ||||
|    * 2: 4K from start of device. | ||||
|    */ | ||||
| 
 | ||||
|   for (minor_version = 0; minor_version < 3; ++minor_version) | ||||
|     { | ||||
|       switch (minor_version) | ||||
| 	{ | ||||
| 	case 0: | ||||
| 	  sector = (size - 8 * 2) & ~(4 * 2 - 1); | ||||
| 	  break; | ||||
| 	case 1: | ||||
| 	  sector = 0; | ||||
| 	  break; | ||||
| 	case 2: | ||||
| 	  sector = 4 * 2; | ||||
| 	  break; | ||||
| 	} | ||||
| 
 | ||||
|       if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), | ||||
| 			  &sb_1x)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       if (sb_1x.magic == SB_MAGIC) | ||||
| 	return grub_mdraid_detect_1x (disk, sector, &sb_1x, array, | ||||
| 				      start_sector); | ||||
|     } | ||||
| 
 | ||||
|   /* Neither 0.90 nor 1.x.  */ | ||||
|   return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); | ||||
| } | ||||
| 
 | ||||
| static struct grub_raid grub_mdraid_dev = { | ||||
|   .name = "mdraid", | ||||
|   .detect = grub_mdraid_detect, | ||||
|   .next = 0 | ||||
| }; | ||||
| 
 | ||||
| GRUB_MOD_INIT (mdraid) | ||||
| { | ||||
|   grub_raid_register (&grub_mdraid_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI (mdraid) | ||||
| { | ||||
|   grub_raid_unregister (&grub_mdraid_dev); | ||||
| } | ||||
							
								
								
									
										116
									
								
								grub-core/disk/memdisk.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								grub-core/disk/memdisk.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,116 @@ | |||
| /* memdisk.c - Access embedded memory disk.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/disk.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/kernel.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/types.h> | ||||
| 
 | ||||
| static char *memdisk_addr; | ||||
| static grub_off_t memdisk_size = 0; | ||||
| 
 | ||||
| static int | ||||
| grub_memdisk_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   return hook ("memdisk"); | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_memdisk_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   if (grub_strcmp (name, "memdisk")) | ||||
|       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a memdisk"); | ||||
| 
 | ||||
|   disk->total_sectors = memdisk_size / GRUB_DISK_SECTOR_SIZE; | ||||
|   disk->id = (unsigned long) "mdsk"; | ||||
|   disk->has_partitions = 0; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_memdisk_close (grub_disk_t disk __attribute((unused))) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_memdisk_read (grub_disk_t disk __attribute((unused)), grub_disk_addr_t sector, | ||||
| 		    grub_size_t size, char *buf) | ||||
| { | ||||
|   grub_memcpy (buf, memdisk_addr + (sector << GRUB_DISK_SECTOR_BITS), size << GRUB_DISK_SECTOR_BITS); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_memdisk_write (grub_disk_t disk __attribute((unused)), grub_disk_addr_t sector, | ||||
| 		     grub_size_t size, const char *buf) | ||||
| { | ||||
|   grub_memcpy (memdisk_addr + (sector << GRUB_DISK_SECTOR_BITS), buf, size << GRUB_DISK_SECTOR_BITS); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_memdisk_dev = | ||||
|   { | ||||
|     .name = "memdisk", | ||||
|     .id = GRUB_DISK_DEVICE_MEMDISK_ID, | ||||
|     .iterate = grub_memdisk_iterate, | ||||
|     .open = grub_memdisk_open, | ||||
|     .close = grub_memdisk_close, | ||||
|     .read = grub_memdisk_read, | ||||
|     .write = grub_memdisk_write, | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| 	  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); | ||||
| 
 | ||||
| 	  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_MOD_FINI(memdisk) | ||||
| { | ||||
|   if (! memdisk_size) | ||||
|     return; | ||||
|   grub_free (memdisk_addr); | ||||
|   grub_disk_dev_unregister (&grub_memdisk_dev); | ||||
| } | ||||
							
								
								
									
										724
									
								
								grub-core/disk/raid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										724
									
								
								grub-core/disk/raid.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,724 @@ | |||
| /* raid.c - module to read RAID arrays.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/raid.h> | ||||
| 
 | ||||
| /* Linked list of RAID arrays. */ | ||||
| static struct grub_raid_array *array_list; | ||||
| grub_raid5_recover_func_t grub_raid5_recover_func; | ||||
| grub_raid6_recover_func_t grub_raid6_recover_func; | ||||
| 
 | ||||
|  | ||||
| static char | ||||
| grub_is_array_readable (struct grub_raid_array *array) | ||||
| { | ||||
|   switch (array->level) | ||||
|     { | ||||
|     case 0: | ||||
|       if (array->nr_devs == array->total_devs) | ||||
| 	return 1; | ||||
|       break; | ||||
| 
 | ||||
|     case 1: | ||||
|       if (array->nr_devs >= 1) | ||||
| 	return 1; | ||||
|       break; | ||||
| 
 | ||||
|     case 4: | ||||
|     case 5: | ||||
|     case 6: | ||||
|     case 10: | ||||
|       { | ||||
|         unsigned int n; | ||||
| 
 | ||||
|         if (array->level == 10) | ||||
|           { | ||||
|             n = array->layout & 0xFF; | ||||
|             if (n == 1) | ||||
|               n = (array->layout >> 8) & 0xFF; | ||||
| 
 | ||||
|             n--; | ||||
|           } | ||||
|         else | ||||
|           n = array->level / 3; | ||||
| 
 | ||||
|         if (array->nr_devs >= array->total_devs - n) | ||||
|           return 1; | ||||
| 
 | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_raid_iterate (int (*hook) (const char *name)) | ||||
| { | ||||
|   struct grub_raid_array *array; | ||||
| 
 | ||||
|   for (array = array_list; array != NULL; array = array->next) | ||||
|     { | ||||
|       if (grub_is_array_readable (array)) | ||||
| 	if (hook (array->name)) | ||||
| 	  return 1; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef GRUB_UTIL | ||||
| static grub_disk_memberlist_t | ||||
| grub_raid_memberlist (grub_disk_t disk) | ||||
| { | ||||
|   struct grub_raid_array *array = disk->data; | ||||
|   grub_disk_memberlist_t list = NULL, tmp; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   for (i = 0; i < array->total_devs; i++) | ||||
|     if (array->device[i]) | ||||
|       { | ||||
|         tmp = grub_malloc (sizeof (*tmp)); | ||||
|         tmp->disk = array->device[i]; | ||||
|         tmp->next = list; | ||||
|         list = tmp; | ||||
|       } | ||||
| 
 | ||||
|   return list; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_raid_open (const char *name, grub_disk_t disk) | ||||
| { | ||||
|   struct grub_raid_array *array; | ||||
|   unsigned n; | ||||
| 
 | ||||
|   for (array = array_list; array != NULL; array = array->next) | ||||
|     { | ||||
|       if (!grub_strcmp (array->name, name)) | ||||
| 	if (grub_is_array_readable (array)) | ||||
| 	  break; | ||||
|     } | ||||
| 
 | ||||
|   if (!array) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", | ||||
|                        name); | ||||
| 
 | ||||
|   disk->has_partitions = 1; | ||||
|   disk->id = array->number; | ||||
|   disk->data = array; | ||||
| 
 | ||||
|   grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name, | ||||
| 		array->total_devs, (unsigned long long) array->disk_size); | ||||
| 
 | ||||
|   switch (array->level) | ||||
|     { | ||||
|     case 1: | ||||
|       disk->total_sectors = array->disk_size; | ||||
|       break; | ||||
| 
 | ||||
|     case 10: | ||||
|       n = array->layout & 0xFF; | ||||
|       if (n == 1) | ||||
|         n = (array->layout >> 8) & 0xFF; | ||||
| 
 | ||||
|       disk->total_sectors = grub_divmod64 (array->total_devs * | ||||
|                                            array->disk_size, | ||||
|                                            n, 0); | ||||
|       break; | ||||
| 
 | ||||
|     case 0: | ||||
|     case 4: | ||||
|     case 5: | ||||
|     case 6: | ||||
|       n = array->level / 3; | ||||
| 
 | ||||
|       disk->total_sectors = (array->total_devs - n) * array->disk_size; | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name, | ||||
| 		array->level, (unsigned long long) disk->total_sectors); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_raid_close (grub_disk_t disk __attribute ((unused))) | ||||
| { | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_raid_block_xor (char *buf1, const char *buf2, int size) | ||||
| { | ||||
|   grub_size_t *p1; | ||||
|   const grub_size_t *p2; | ||||
| 
 | ||||
|   p1 = (grub_size_t *) buf1; | ||||
|   p2 = (const grub_size_t *) buf2; | ||||
|   size /= GRUB_CPU_SIZEOF_VOID_P; | ||||
| 
 | ||||
|   while (size) | ||||
|     { | ||||
|       *(p1++) ^= *(p2++); | ||||
|       size--; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, | ||||
| 		grub_size_t size, char *buf) | ||||
| { | ||||
|   struct grub_raid_array *array = disk->data; | ||||
|   grub_err_t err = 0; | ||||
| 
 | ||||
|   switch (array->level) | ||||
|     { | ||||
|     case 0: | ||||
|     case 1: | ||||
|     case 10: | ||||
|       { | ||||
|         grub_disk_addr_t read_sector, far_ofs; | ||||
| 	grub_uint32_t disknr, b, near, far, ofs; | ||||
| 
 | ||||
|         read_sector = grub_divmod64 (sector, array->chunk_size, &b); | ||||
|         far = ofs = near = 1; | ||||
|         far_ofs = 0; | ||||
| 
 | ||||
|         if (array->level == 1) | ||||
|           near = array->total_devs; | ||||
|         else if (array->level == 10) | ||||
|           { | ||||
|             near = array->layout & 0xFF; | ||||
|             far = (array->layout >> 8) & 0xFF; | ||||
|             if (array->layout >> 16) | ||||
|               { | ||||
|                 ofs = far; | ||||
|                 far_ofs = 1; | ||||
|               } | ||||
|             else | ||||
|               far_ofs = grub_divmod64 (array->disk_size, | ||||
|                                        far * array->chunk_size, 0); | ||||
| 
 | ||||
|             far_ofs *= array->chunk_size; | ||||
|           } | ||||
| 
 | ||||
|         read_sector = grub_divmod64 (read_sector * near, array->total_devs, | ||||
|                                      &disknr); | ||||
| 
 | ||||
|         ofs *= array->chunk_size; | ||||
|         read_sector *= ofs; | ||||
| 
 | ||||
|         while (1) | ||||
|           { | ||||
|             grub_size_t read_size; | ||||
|             unsigned int i, j; | ||||
| 
 | ||||
|             read_size = array->chunk_size - b; | ||||
|             if (read_size > size) | ||||
|               read_size = size; | ||||
| 
 | ||||
|             for (i = 0; i < near; i++) | ||||
|               { | ||||
|                 unsigned int k; | ||||
| 
 | ||||
|                 k = disknr; | ||||
|                 for (j = 0; j < far; j++) | ||||
|                   { | ||||
|                     if (array->device[k]) | ||||
|                       { | ||||
|                         if (grub_errno == GRUB_ERR_READ_ERROR) | ||||
|                           grub_errno = GRUB_ERR_NONE; | ||||
| 
 | ||||
|                         err = grub_disk_read (array->device[k], | ||||
|                                               array->start_sector[k] + | ||||
|                                                 read_sector + j * far_ofs + b, | ||||
|                                               0, | ||||
|                                               read_size << GRUB_DISK_SECTOR_BITS, | ||||
|                                               buf); | ||||
|                         if (! err) | ||||
|                           break; | ||||
|                         else if (err != GRUB_ERR_READ_ERROR) | ||||
|                           return err; | ||||
|                       } | ||||
|                     else | ||||
|                       err = grub_error (GRUB_ERR_READ_ERROR, | ||||
|                                         "disk missing"); | ||||
| 
 | ||||
|                     k++; | ||||
|                     if (k == array->total_devs) | ||||
|                       k = 0; | ||||
|                   } | ||||
| 
 | ||||
|                 if (! err) | ||||
|                   break; | ||||
| 
 | ||||
|                 disknr++; | ||||
|                 if (disknr == array->total_devs) | ||||
|                   { | ||||
|                     disknr = 0; | ||||
|                     read_sector += ofs; | ||||
|                   } | ||||
|               } | ||||
| 
 | ||||
|             if (err) | ||||
|               return err; | ||||
| 
 | ||||
|             buf += read_size << GRUB_DISK_SECTOR_BITS; | ||||
| 	    size -= read_size; | ||||
| 	    if (! size) | ||||
| 	      break; | ||||
| 
 | ||||
|             b = 0; | ||||
|             disknr += (near - i); | ||||
|             while (disknr >= array->total_devs) | ||||
|               { | ||||
|                 disknr -= array->total_devs; | ||||
|                 read_sector += ofs; | ||||
|               } | ||||
|           } | ||||
|         break; | ||||
|       } | ||||
| 
 | ||||
|     case 4: | ||||
|     case 5: | ||||
|     case 6: | ||||
|       { | ||||
| 	grub_disk_addr_t read_sector; | ||||
| 	grub_uint32_t b, p, n, disknr, e; | ||||
| 
 | ||||
|         /* n = 1 for level 4 and 5, 2 for level 6.  */ | ||||
|         n = array->level / 3; | ||||
| 
 | ||||
| 	/* Find the first sector to read. */ | ||||
| 	read_sector = grub_divmod64 (sector, array->chunk_size, &b); | ||||
| 	read_sector = grub_divmod64 (read_sector, array->total_devs - n, | ||||
|                                      &disknr); | ||||
|         if (array->level >= 5) | ||||
|           { | ||||
|             grub_divmod64 (read_sector, array->total_devs, &p); | ||||
| 
 | ||||
|             if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)) | ||||
|               p = array->total_devs - 1 - p; | ||||
| 
 | ||||
|             if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) | ||||
|               { | ||||
|                 disknr += p + n; | ||||
|               } | ||||
|             else | ||||
|               { | ||||
|                 grub_uint32_t q; | ||||
| 
 | ||||
|                 q = p + (n - 1); | ||||
|                 if (q >= array->total_devs) | ||||
|                   q -= array->total_devs; | ||||
| 
 | ||||
|                 if (disknr >= p) | ||||
|                   disknr += n; | ||||
|                 else if (disknr >= q) | ||||
|                   disknr += q + 1; | ||||
|               } | ||||
| 
 | ||||
|             if (disknr >= array->total_devs) | ||||
|               disknr -= array->total_devs; | ||||
|           } | ||||
|         else | ||||
|           p = array->total_devs - n; | ||||
| 
 | ||||
| 	read_sector *= array->chunk_size; | ||||
| 
 | ||||
| 	while (1) | ||||
| 	  { | ||||
|             grub_size_t read_size; | ||||
|             int next_level; | ||||
| 
 | ||||
|             read_size = array->chunk_size - b; | ||||
|             if (read_size > size) | ||||
|               read_size = size; | ||||
| 
 | ||||
|             e = 0; | ||||
|             if (array->device[disknr]) | ||||
|               { | ||||
|                 /* Reset read error.  */ | ||||
|                 if (grub_errno == GRUB_ERR_READ_ERROR) | ||||
|                   grub_errno = GRUB_ERR_NONE; | ||||
| 
 | ||||
|                 err = grub_disk_read (array->device[disknr], | ||||
|                                       array->start_sector[disknr] + | ||||
|                                         read_sector + b, 0, | ||||
|                                       read_size << GRUB_DISK_SECTOR_BITS, | ||||
|                                       buf); | ||||
| 
 | ||||
|                 if ((err) && (err != GRUB_ERR_READ_ERROR)) | ||||
|                   break; | ||||
|                 e++; | ||||
|               } | ||||
|             else | ||||
|               err = GRUB_ERR_READ_ERROR; | ||||
| 
 | ||||
| 	    if (err) | ||||
|               { | ||||
|                 if (array->nr_devs < array->total_devs - n + e) | ||||
|                   break; | ||||
| 
 | ||||
|                 grub_errno = GRUB_ERR_NONE; | ||||
|                 if (array->level == 6) | ||||
|                   { | ||||
|                     err = ((grub_raid6_recover_func) ? | ||||
|                            (*grub_raid6_recover_func) (array, disknr, p, | ||||
|                                                        buf, read_sector + b, | ||||
|                                                        read_size) : | ||||
|                            grub_error (GRUB_ERR_BAD_DEVICE, | ||||
|                                        "raid6rec is not loaded")); | ||||
|                   } | ||||
|                 else | ||||
|                   { | ||||
|                     err = ((grub_raid5_recover_func) ? | ||||
|                            (*grub_raid5_recover_func) (array, disknr, | ||||
|                                                        buf, read_sector + b, | ||||
|                                                        read_size) : | ||||
|                            grub_error (GRUB_ERR_BAD_DEVICE, | ||||
|                                        "raid5rec is not loaded")); | ||||
|                   } | ||||
| 
 | ||||
|                 if (err) | ||||
|                   break; | ||||
|               } | ||||
| 
 | ||||
| 	    buf += read_size << GRUB_DISK_SECTOR_BITS; | ||||
| 	    size -= read_size; | ||||
| 	    if (! size) | ||||
| 	      break; | ||||
| 
 | ||||
|             b = 0; | ||||
| 	    disknr++; | ||||
| 
 | ||||
|             if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) | ||||
|               { | ||||
|                 if (disknr == array->total_devs) | ||||
|                   disknr = 0; | ||||
| 
 | ||||
|                 next_level = (disknr == p); | ||||
|               } | ||||
|             else | ||||
|               { | ||||
|                 if (disknr == p) | ||||
|                   disknr += n; | ||||
| 
 | ||||
|                 next_level = (disknr >= array->total_devs); | ||||
|               } | ||||
| 
 | ||||
|             if (next_level) | ||||
|               { | ||||
|                 read_sector += array->chunk_size; | ||||
| 
 | ||||
|                 if (array->level >= 5) | ||||
|                   { | ||||
|                     if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK) | ||||
|                       p = (p == array->total_devs - 1) ? 0 : p + 1; | ||||
|                     else | ||||
|                       p = (p == 0) ? array->total_devs - 1 : p - 1; | ||||
| 
 | ||||
|                     if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK) | ||||
|                       { | ||||
|                         disknr = p + n; | ||||
|                         if (disknr >= array->total_devs) | ||||
|                           disknr -= array->total_devs; | ||||
|                       } | ||||
|                     else | ||||
|                       { | ||||
|                         disknr -= array->total_devs; | ||||
|                         if (disknr == p) | ||||
|                           disknr += n; | ||||
|                       } | ||||
|                   } | ||||
|                 else | ||||
|                   disknr = 0; | ||||
|               } | ||||
| 	  } | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
| 
 | ||||
|   return err; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_raid_write (grub_disk_t disk __attribute ((unused)), | ||||
| 		 grub_disk_addr_t sector __attribute ((unused)), | ||||
| 		 grub_size_t size __attribute ((unused)), | ||||
| 		 const char *buf __attribute ((unused))) | ||||
| { | ||||
|   return GRUB_ERR_NOT_IMPLEMENTED_YET; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| insert_array (grub_disk_t disk, struct grub_raid_array *new_array, | ||||
|               grub_disk_addr_t start_sector, const char *scanner_name) | ||||
| { | ||||
|   struct grub_raid_array *array = 0, *p; | ||||
| 
 | ||||
|   /* See whether the device is part of an array we have already seen a
 | ||||
|      device from.  */ | ||||
|   for (p = array_list; p != NULL; p = p->next) | ||||
|     if ((p->uuid_len == new_array->uuid_len) && | ||||
|         (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len))) | ||||
|       { | ||||
|         grub_free (new_array->uuid); | ||||
|         array = p; | ||||
| 
 | ||||
|         /* Do some checks before adding the device to the array.  */ | ||||
| 
 | ||||
|         /* FIXME: Check whether the update time of the superblocks are
 | ||||
|            the same.  */ | ||||
| 
 | ||||
|         if (array->total_devs == array->nr_devs) | ||||
|           /* We found more members of the array than the array
 | ||||
|              actually has according to its superblock.  This shouldn't | ||||
|              happen normally.  */ | ||||
|           grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?", | ||||
| 			array->total_devs); | ||||
| 
 | ||||
|         if (array->device[new_array->index] != NULL) | ||||
|           /* We found multiple devices with the same number. Again,
 | ||||
|              this shouldn't happen.  */ | ||||
|           grub_dprintf ("raid", "Found two disks with the number %d?!?", | ||||
| 			new_array->number); | ||||
| 
 | ||||
|         if (new_array->disk_size < array->disk_size) | ||||
|           array->disk_size = new_array->disk_size; | ||||
|         break; | ||||
|       } | ||||
| 
 | ||||
|   /* Add an array to the list if we didn't find any.  */ | ||||
|   if (!array) | ||||
|     { | ||||
|       array = grub_malloc (sizeof (*array)); | ||||
|       if (!array) | ||||
|         { | ||||
|           grub_free (new_array->uuid); | ||||
|           return grub_errno; | ||||
|         } | ||||
| 
 | ||||
|       *array = *new_array; | ||||
|       array->nr_devs = 0; | ||||
|       grub_memset (&array->device, 0, sizeof (array->device)); | ||||
|       grub_memset (&array->start_sector, 0, sizeof (array->start_sector)); | ||||
| 
 | ||||
|       if (! array->name) | ||||
| 	{ | ||||
| 	  for (p = array_list; p != NULL; p = p->next) | ||||
| 	    { | ||||
| 	      if (! p->name && p->number == array->number)  | ||||
| 		break; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       if (array->name || p) | ||||
|         { | ||||
| 	  /* The number is already in use, so we need to find a new one.
 | ||||
| 	     (Or, in the case of named arrays, the array doesn't have its | ||||
| 	     own number, but we need one that doesn't clash for use as a key | ||||
| 	     in the disk cache.  */ | ||||
|           int i = array->name ? 0x40000000 : 0; | ||||
| 
 | ||||
| 	  while (1) | ||||
| 	    { | ||||
| 	      for (p = array_list; p != NULL; p = p->next) | ||||
| 		{ | ||||
| 		  if (p->number == i) | ||||
| 		    break; | ||||
| 		} | ||||
| 
 | ||||
| 	      if (! p) | ||||
| 		{ | ||||
| 		  /* We found an unused number.  */ | ||||
| 		  array->number = i; | ||||
| 		  break; | ||||
| 		} | ||||
| 
 | ||||
| 	      i++; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       /* mdraid 1.x superblocks have only a name stored not a number.
 | ||||
| 	 Use it directly as GRUB device.  */ | ||||
|       if (! array->name) | ||||
| 	{ | ||||
| 	  array->name = grub_xasprintf ("md%d", array->number); | ||||
| 	  if (! array->name) | ||||
| 	    { | ||||
| 	      grub_free (array->uuid); | ||||
| 	      grub_free (array); | ||||
| 
 | ||||
| 	      return grub_errno; | ||||
| 	    } | ||||
| 	} | ||||
|       else | ||||
| 	{ | ||||
| 	  /* Strip off the homehost if present.  */ | ||||
| 	  char *colon = grub_strchr (array->name, ':'); | ||||
| 	  char *new_name = grub_xasprintf ("md/%s", | ||||
| 					   colon ? colon + 1 : array->name); | ||||
| 
 | ||||
| 	  if (! new_name) | ||||
| 	    { | ||||
| 	      grub_free (array->uuid); | ||||
| 	      grub_free (array); | ||||
| 
 | ||||
| 	      return grub_errno; | ||||
| 	    } | ||||
| 
 | ||||
| 	  grub_free (array->name); | ||||
| 	  array->name = new_name; | ||||
| 	} | ||||
| 
 | ||||
|       grub_dprintf ("raid", "Found array %s (%s)\n", array->name, | ||||
|                     scanner_name); | ||||
| 
 | ||||
|       /* Add our new array to the list.  */ | ||||
|       array->next = array_list; | ||||
|       array_list = array; | ||||
| 
 | ||||
|       /* RAID 1 doesn't use a chunksize but code assumes one so set
 | ||||
| 	 one. */ | ||||
|       if (array->level == 1) | ||||
| 	array->chunk_size = 64; | ||||
|     } | ||||
| 
 | ||||
|   /* Add the device to the array. */ | ||||
|   array->device[new_array->index] = disk; | ||||
|   array->start_sector[new_array->index] = start_sector; | ||||
|   array->nr_devs++; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_raid_t grub_raid_list; | ||||
| 
 | ||||
| static void | ||||
| free_array (void) | ||||
| { | ||||
|   struct grub_raid_array *array; | ||||
| 
 | ||||
|   array = array_list; | ||||
|   while (array) | ||||
|     { | ||||
|       struct grub_raid_array *p; | ||||
|       int i; | ||||
| 
 | ||||
|       p = array; | ||||
|       array = array->next; | ||||
| 
 | ||||
|       for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++) | ||||
|         if (p->device[i]) | ||||
|           grub_disk_close (p->device[i]); | ||||
| 
 | ||||
|       grub_free (p->uuid); | ||||
|       grub_free (p->name); | ||||
|       grub_free (p); | ||||
|     } | ||||
| 
 | ||||
|   array_list = 0; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_raid_register (grub_raid_t raid) | ||||
| { | ||||
|   auto int hook (const char *name); | ||||
|   int hook (const char *name) | ||||
|     { | ||||
|       grub_disk_t disk; | ||||
|       struct grub_raid_array array; | ||||
|       grub_disk_addr_t start_sector; | ||||
| 
 | ||||
|       grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); | ||||
| 
 | ||||
|       disk = grub_disk_open (name); | ||||
|       if (!disk) | ||||
|         return 0; | ||||
| 
 | ||||
|       if ((disk->total_sectors != GRUB_ULONG_MAX) && | ||||
| 	  (! grub_raid_list->detect (disk, &array, &start_sector)) && | ||||
| 	  (! insert_array (disk, &array, start_sector, grub_raid_list->name))) | ||||
| 	return 0; | ||||
| 
 | ||||
|       /* This error usually means it's not raid, no need to display
 | ||||
| 	 it.  */ | ||||
|       if (grub_errno != GRUB_ERR_OUT_OF_RANGE) | ||||
| 	grub_print_error (); | ||||
| 
 | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
| 
 | ||||
|       grub_disk_close (disk); | ||||
| 
 | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   raid->next = grub_raid_list; | ||||
|   grub_raid_list = raid; | ||||
|   grub_device_iterate (&hook); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_raid_unregister (grub_raid_t raid) | ||||
| { | ||||
|   grub_raid_t *p, q; | ||||
| 
 | ||||
|   for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next) | ||||
|     if (q == raid) | ||||
|       { | ||||
| 	*p = q->next; | ||||
| 	break; | ||||
|       } | ||||
| } | ||||
| 
 | ||||
| static struct grub_disk_dev grub_raid_dev = | ||||
|   { | ||||
|     .name = "raid", | ||||
|     .id = GRUB_DISK_DEVICE_RAID_ID, | ||||
|     .iterate = grub_raid_iterate, | ||||
|     .open = grub_raid_open, | ||||
|     .close = grub_raid_close, | ||||
|     .read = grub_raid_read, | ||||
|     .write = grub_raid_write, | ||||
| #ifdef GRUB_UTIL | ||||
|     .memberlist = grub_raid_memberlist, | ||||
| #endif | ||||
|     .next = 0 | ||||
|   }; | ||||
| 
 | ||||
|  | ||||
| GRUB_MOD_INIT(raid) | ||||
| { | ||||
|   grub_disk_dev_register (&grub_raid_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(raid) | ||||
| { | ||||
|   grub_disk_dev_unregister (&grub_raid_dev); | ||||
|   free_array (); | ||||
| } | ||||
							
								
								
									
										72
									
								
								grub-core/disk/raid5_recover.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								grub-core/disk/raid5_recover.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| /* raid5_recover.c - module to recover from faulty RAID4/5 arrays.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/dl.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/err.h> | ||||
| #include <grub/misc.h> | ||||
| #include <grub/raid.h> | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_raid5_recover (struct grub_raid_array *array, int disknr, | ||||
|                     char *buf, grub_disk_addr_t sector, int size) | ||||
| { | ||||
|   char *buf2; | ||||
|   int i; | ||||
| 
 | ||||
|   size <<= GRUB_DISK_SECTOR_BITS; | ||||
|   buf2 = grub_malloc (size); | ||||
|   if (!buf2) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   grub_memset (buf, 0, size); | ||||
| 
 | ||||
|   for (i = 0; i < (int) array->total_devs; i++) | ||||
|     { | ||||
|       grub_err_t err; | ||||
| 
 | ||||
|       if (i == disknr) | ||||
|         continue; | ||||
| 
 | ||||
|       err = grub_disk_read (array->device[i], sector, 0, size, buf2); | ||||
| 
 | ||||
|       if (err) | ||||
|         { | ||||
|           grub_free (buf2); | ||||
|           return err; | ||||
|         } | ||||
| 
 | ||||
|       grub_raid_block_xor (buf, buf2, size); | ||||
|     } | ||||
| 
 | ||||
|   grub_free (buf2); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_INIT(raid5rec) | ||||
| { | ||||
|   grub_raid5_recover_func = grub_raid5_recover; | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(raid5rec) | ||||
| { | ||||
|   grub_raid5_recover_func = 0; | ||||
| } | ||||
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