Merge mainline into mbivid

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-09-16 00:22:49 +02:00
commit 9ba27423f5
931 changed files with 122070 additions and 40781 deletions

302
grub-core/Makefile.am Normal file
View file

@ -0,0 +1,302 @@
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
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.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/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
endif
if COND_sparc64_ieee1275
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

1433
grub-core/Makefile.core.def Normal file

File diff suppressed because it is too large Load diff

View 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

View 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

View 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!!! */

View 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_I386_PC_MULTIBOOT_SIGNATURE)
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

View 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

View 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

View 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:

View 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

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

View 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++];
}

View 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);
}

View 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
View 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
View 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
View 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;
}

View 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);
}

773
grub-core/commands/acpi.c Normal file
View file

@ -0,0 +1,773 @@
/* 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/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, GRUB_ACPI_FADT_SIGNATURE,
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_context *ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
struct grub_acpi_rsdp_v10 *rsdp;
struct efiemu_acpi_table *cur, *t;
grub_err_t err;
int i, mmapregion;
int numoftables;
/* 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 FADT 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_file_open (args[i]);
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, 0,
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);
}

View file

@ -0,0 +1,266 @@
/*
* 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/acpi.h>
#include <grub/misc.h>
#include <grub/cpu/io.h>
static inline grub_uint32_t
decode_length (const grub_uint8_t *ptr, int *numlen)
{
int num_bytes, i;
grub_uint32_t ret;
if (*ptr < 64)
{
if (numlen)
*numlen = 1;
return *ptr;
}
num_bytes = *ptr >> 6;
if (numlen)
*numlen = num_bytes + 1;
ret = *ptr & 0xf;
ptr++;
for (i = 0; i < num_bytes; i++)
{
ret |= *ptr << (8 * i + 4);
ptr++;
}
return ret;
}
static inline grub_uint32_t
skip_name_string (const grub_uint8_t *ptr, const grub_uint8_t *end)
{
const grub_uint8_t *ptr0 = ptr;
while (ptr < end && (*ptr == '^' || *ptr == '\\'))
ptr++;
switch (*ptr)
{
case '.':
ptr++;
ptr += 8;
break;
case '/':
ptr++;
ptr += 1 + (*ptr) * 4;
break;
case 0:
ptr++;
break;
default:
ptr += 4;
break;
}
return ptr - ptr0;
}
static inline grub_uint32_t
skip_data_ref_object (const grub_uint8_t *ptr, const grub_uint8_t *end)
{
grub_dprintf ("acpi", "data type = 0x%x\n", *ptr);
switch (*ptr)
{
case GRUB_ACPI_OPCODE_PACKAGE:
return 1 + decode_length (ptr + 1, 0);
case GRUB_ACPI_OPCODE_ZERO:
case GRUB_ACPI_OPCODE_ONES:
case GRUB_ACPI_OPCODE_ONE:
return 1;
case GRUB_ACPI_OPCODE_BYTE_CONST:
return 2;
case GRUB_ACPI_OPCODE_WORD_CONST:
return 3;
case GRUB_ACPI_OPCODE_DWORD_CONST:
return 5;
default:
if (*ptr == '^' || *ptr == '\\' || *ptr == '_'
|| (*ptr >= 'A' && *ptr <= 'Z'))
return skip_name_string (ptr, end);
grub_printf ("Unknown opcode 0x%x\n", *ptr);
return 0;
}
}
static inline grub_uint32_t
skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end)
{
const grub_uint8_t *ptr0 = ptr;
int add;
grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr);
switch (*ptr)
{
case GRUB_ACPI_EXTOPCODE_MUTEX:
ptr++;
ptr += skip_name_string (ptr, end);
ptr++;
break;
case GRUB_ACPI_EXTOPCODE_OPERATION_REGION:
ptr++;
ptr += skip_name_string (ptr, end);
ptr++;
ptr += add = skip_data_ref_object (ptr, end);
if (!add)
return 0;
ptr += add = skip_data_ref_object (ptr, end);
if (!add)
return 0;
break;
case GRUB_ACPI_EXTOPCODE_FIELD_OP:
ptr++;
ptr += decode_length (ptr, 0);
break;
default:
grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr);
return 0;
}
return ptr - ptr0;
}
static int
get_sleep_type (grub_uint8_t *table, grub_uint8_t *end)
{
grub_uint8_t *ptr, *prev;
int sleep_type = -1;
ptr = table + sizeof (struct grub_acpi_table_header);
while (ptr < end && prev < ptr)
{
int add;
prev = ptr;
grub_dprintf ("acpi", "Opcode 0x%x\n", *ptr);
grub_dprintf ("acpi", "Tell %x\n", (unsigned) (ptr - table));
switch (*ptr)
{
case GRUB_ACPI_OPCODE_EXTOP:
ptr++;
ptr += add = skip_ext_op (ptr, end);
if (!add)
return -1;
break;
case GRUB_ACPI_OPCODE_NAME:
ptr++;
if (memcmp (ptr, "_S5_", 4) == 0)
{
int ll;
grub_uint8_t *ptr2 = ptr;
ptr2 += 4;
if (*ptr2 != 0x12)
{
grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2);
return -1;
}
ptr2++;
decode_length (ptr2, &ll);
ptr2 += ll;
ptr2++;
switch (*ptr2)
{
case GRUB_ACPI_OPCODE_ZERO:
sleep_type = 0;
break;
case GRUB_ACPI_OPCODE_ONE:
sleep_type = 1;
break;
case GRUB_ACPI_OPCODE_BYTE_CONST:
sleep_type = ptr2[1];
break;
default:
grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2);
return -1;
}
}
ptr += add = skip_name_string (ptr, end);
if (!add)
return -1;
ptr += add = skip_data_ref_object (ptr, end);
if (!add)
return -1;
break;
case GRUB_ACPI_OPCODE_SCOPE:
case GRUB_ACPI_OPCODE_IF:
case GRUB_ACPI_OPCODE_METHOD:
{
ptr++;
ptr += decode_length (ptr, 0);
break;
}
}
}
grub_dprintf ("acpi", "TYP = %d\n", sleep_type);
return sleep_type;
}
void
grub_acpi_halt (void)
{
struct grub_acpi_rsdp_v20 *rsdp2;
struct grub_acpi_rsdp_v10 *rsdp1;
struct grub_acpi_table_header *rsdt;
grub_uint32_t *entry_ptr;
rsdp2 = grub_acpi_get_rsdpv2 ();
if (rsdp2)
rsdp1 = &(rsdp2->rsdpv1);
else
rsdp1 = grub_acpi_get_rsdpv1 ();
grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1);
if (!rsdp1)
return;
rsdt = (struct grub_acpi_table_header *) (grub_addr_t) rsdp1->rsdt_addr;
for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
+ rsdt->length);
entry_ptr++)
{
if (grub_memcmp ((void *) (grub_addr_t) *entry_ptr, "FACP", 4) == 0)
{
grub_uint32_t port;
struct grub_acpi_fadt *fadt
= ((struct grub_acpi_fadt *) (grub_addr_t) *entry_ptr);
struct grub_acpi_table_header *dsdt
= (struct grub_acpi_table_header *) (grub_addr_t) fadt->dsdt_addr;
int sleep_type = -1;
port = fadt->pm1a;
grub_dprintf ("acpi", "PM1a port=%x\n", port);
if (grub_memcmp (dsdt->signature, "DSDT",
sizeof (dsdt->signature)) != 0)
break;
sleep_type = get_sleep_type ((grub_uint8_t *) dsdt,
(grub_uint8_t *) dsdt + dsdt->length);
if (sleep_type < 0 || sleep_type >= 8)
break;
grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n",
sleep_type, port);
grub_outw (GRUB_ACPI_SLP_EN
| (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET), port & 0xffff);
}
}
grub_printf ("ACPI shutdown failed\n");
}

View file

@ -0,0 +1,120 @@
/* 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");
grub_file_filter_disable_compression ();
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
View 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);
}

102
grub-core/commands/cat.c Normal file
View file

@ -0,0 +1,102 @@
/* 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/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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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_file_open (args[0]);
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, 0,
N_("FILE"), N_("Show the contents of a file."),
options);
}
GRUB_MOD_FINI(cat)
{
grub_unregister_extcmd (cmd);
}

118
grub-core/commands/cmp.c Normal file
View file

@ -0,0 +1,118 @@
/* 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/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_file_open (args[0]);
file2 = grub_file_open (args[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);
}

View 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);
}

72
grub-core/commands/crc.c Normal file
View file

@ -0,0 +1,72 @@
/* 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");
grub_file_filter_disable_compression ();
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
View 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);
}

126
grub-core/commands/echo.c Normal file
View file

@ -0,0 +1,126 @@
/* 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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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_ACCEPT_DASH
| GRUB_COMMAND_OPTIONS_AT_START,
N_("[-e|-n] STRING"), N_("Display a line of text."),
options);
}
GRUB_MOD_FINI(echo)
{
grub_unregister_extcmd (cmd);
}

View 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;
}

View 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);
}

View 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);
}

View file

@ -0,0 +1,107 @@
/* systab.c - Display EFI systab. */
/*
* 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/mm.h>
#include <grub/misc.h>
#include <grub/normal.h>
#include <grub/charset.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
struct guid_mapping
{
grub_efi_guid_t guid;
const char *name;
};
static const struct guid_mapping guid_mappings[] =
{
{ GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI-2.0"},
{ GRUB_EFI_ACPI_TABLE_GUID, "ACPI-1.0"},
{ GRUB_EFI_SAL_TABLE_GUID, "SAL"},
{ GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
{ GRUB_EFI_MPS_TABLE_GUID, "MPS"},
{ GRUB_EFI_HCDP_TABLE_GUID, "HCDP"}
};
static grub_err_t
grub_cmd_lsefisystab (struct grub_command *cmd __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
const grub_efi_system_table_t *st = grub_efi_system_table;
grub_efi_configuration_table_t *t;
unsigned int i;
grub_printf ("Signature: %016" PRIxGRUB_UINT64_T " revision: %08x\n",
st->hdr.signature, st->hdr.revision);
{
char *vendor;
grub_uint16_t *vendor_utf16;
grub_printf ("Vendor: ");
for (vendor_utf16 = st->firmware_vendor; *vendor_utf16; vendor_utf16++);
vendor = grub_malloc (4 * (vendor_utf16 - st->firmware_vendor) + 1);
if (!vendor)
return grub_errno;
*grub_utf16_to_utf8 ((grub_uint8_t *) vendor, st->firmware_vendor,
vendor_utf16 - st->firmware_vendor) = 0;
grub_printf ("%s", vendor);
grub_free (vendor);
}
grub_printf (", Version=%x\n", st->firmware_revision);
grub_printf ("%ld tables:\n", st->num_table_entries);
t = st->configuration_table;
for (i = 0; i < st->num_table_entries; i++)
{
unsigned int j;
grub_printf ("%p ", t->vendor_table);
grub_printf ("%08x-%04x-%04x-",
t->vendor_guid.data1, t->vendor_guid.data2,
t->vendor_guid.data3);
for (j = 0; j < 8; j++)
grub_printf ("%02x", t->vendor_guid.data4[j]);
for (j = 0; j < ARRAY_SIZE (guid_mappings); j++)
if (grub_memcmp (&guid_mappings[j].guid, &t->vendor_guid,
sizeof (grub_efi_guid_t)) == 0)
grub_printf (" %s", guid_mappings[j].name);
grub_printf ("\n");
t++;
}
return GRUB_ERR_NONE;
}
static grub_command_t cmd;
GRUB_MOD_INIT(lsefisystab)
{
cmd = grub_register_command ("lsefisystab", grub_cmd_lsefisystab,
"", "Display EFI system tables.");
}
GRUB_MOD_FINI(lsefisystab)
{
grub_unregister_command (cmd);
}

View file

@ -0,0 +1,162 @@
/* systab.c - Display EFI systab. */
/*
* 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/mm.h>
#include <grub/misc.h>
#include <grub/normal.h>
#include <grub/charset.h>
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
static void
disp_sal (void *table)
{
struct grub_efi_sal_system_table *t = table;
void *desc;
grub_uint32_t len, l;
grub_printf ("SAL rev: %02x, signature: %x, len:%x\n",
t->sal_rev, t->signature, t->total_table_len);
grub_printf ("nbr entry: %d, chksum: %02x, SAL version A: %02x B: %02x\n",
t->entry_count, t->checksum,
t->sal_a_version, t->sal_b_version);
grub_printf ("OEM-ID: %-32s\n", t->oem_id);
grub_printf ("Product-ID: %-32s\n", t->product_id);
desc = t->entries;
len = t->total_table_len - sizeof (struct grub_efi_sal_system_table);
while (len > 0)
{
switch (*(grub_uint8_t *) desc)
{
case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_ENTRYPOINT_DESCRIPTOR:
{
struct grub_efi_sal_system_table_entrypoint_descriptor *c = desc;
l = sizeof (*c);
grub_printf (" Entry point: PAL=%016" PRIxGRUB_UINT64_T
" SAL=%016" PRIxGRUB_UINT64_T " GP=%016"
PRIxGRUB_UINT64_T "\n",
c->pal_proc_addr, c->sal_proc_addr,
c->global_data_ptr);
}
break;
case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_MEMORY_DESCRIPTOR:
{
struct grub_efi_sal_system_table_memory_descriptor *c = desc;
l = sizeof (*c);
grub_printf (" Memory descriptor entry addr=%016" PRIxGRUB_UINT64_T
" len=%" PRIuGRUB_UINT64_T "KB\n",
c->addr, c->len * 4);
grub_printf (" sal_used=%d attr=%x AR=%x attr_mask=%x "
"type=%x usage=%x\n",
c->sal_used, c->attr, c->ar, c->attr_mask, c->mem_type,
c->usage);
}
break;
case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_PLATFORM_FEATURES:
{
struct grub_efi_sal_system_table_platform_features *c = desc;
l = sizeof (*c);
grub_printf (" Platform features: %02x", c->flags);
if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_BUSLOCK)
grub_printf (" BusLock");
if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_IRQREDIRECT)
grub_printf (" IrqRedirect");
if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_IPIREDIRECT)
grub_printf (" IPIRedirect");
if (c->flags & GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_ITCDRIFT)
grub_printf (" ITCDrift");
grub_printf ("\n");
}
break;
case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_TRANSLATION_REGISTER_DESCRIPTOR:
{
struct grub_efi_sal_system_table_translation_register_descriptor *c
= desc;
l = sizeof (*c);
grub_printf (" TR type=%d num=%d va=%016" PRIxGRUB_UINT64_T
" pte=%016" PRIxGRUB_UINT64_T "\n",
c->register_type, c->register_number,
c->addr, c->page_size);
}
break;
case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_PURGE_TRANSLATION_COHERENCE:
{
struct grub_efi_sal_system_table_purge_translation_coherence *c
= desc;
l = sizeof (*c);
grub_printf (" PTC coherence nbr=%d addr=%016" PRIxGRUB_UINT64_T "\n",
c->ndomains, c->coherence);
}
break;
case GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_AP_WAKEUP:
{
struct grub_efi_sal_system_table_ap_wakeup *c = desc;
l = sizeof (*c);
grub_printf (" AP wake-up: mec=%d vect=%" PRIxGRUB_UINT64_T "\n",
c->mechanism, c->vector);
}
break;
default:
grub_printf (" unknown entry 0x%x\n", *(grub_uint8_t *)desc);
return;
}
desc = (grub_uint8_t *)desc + l;
len -= l;
}
}
static grub_err_t
grub_cmd_lssal (struct grub_command *cmd __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
const grub_efi_system_table_t *st = grub_efi_system_table;
grub_efi_configuration_table_t *t = st->configuration_table;
unsigned int i;
grub_efi_guid_t guid = GRUB_EFI_SAL_TABLE_GUID;
for (i = 0; i < st->num_table_entries; i++)
{
if (grub_memcmp (&guid, &t->vendor_guid,
sizeof (grub_efi_guid_t)) == 0)
{
disp_sal (t->vendor_table);
return GRUB_ERR_NONE;
}
t++;
}
grub_printf ("SAL not found\n");
return GRUB_ERR_NONE;
}
static grub_command_t cmd;
GRUB_MOD_INIT(lssal)
{
cmd = grub_register_command ("lssal", grub_cmd_lssal, "",
"Display SAL system table.");
}
GRUB_MOD_FINI(lssal)
{
grub_unregister_command (cmd);
}

115
grub-core/commands/extcmd.c Normal file
View file

@ -0,0 +1,115 @@
/* 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>
#include <grub/script_sh.h>
grub_err_t
grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
struct grub_script *script)
{
int new_argc;
char **new_args;
struct grub_arg_list *state;
struct grub_extcmd_context context;
grub_err_t ret;
grub_extcmd_t ext = cmd->data;
context.state = 0;
context.extcmd = ext;
context.script = script;
if (! ext->options)
{
ret = (ext->func) (&context, argc, args);
return ret;
}
state = grub_arg_list_alloc (ext, argc, args);
if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
{
context.state = state;
ret = (ext->func) (&context, new_argc, new_args);
grub_free (new_args);
grub_free (state);
return ret;
}
grub_free (state);
return grub_errno;
}
static grub_err_t
grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args)
{
return grub_extcmd_dispatcher (cmd, argc, args, 0);
}
grub_extcmd_t
grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func,
grub_command_flags_t flags, const char *summary,
const char *description,
const struct grub_arg_option *parser,
int prio)
{
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_dispatch,
summary, description, prio);
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;
}
grub_extcmd_t
grub_register_extcmd (const char *name, grub_extcmd_func_t func,
grub_command_flags_t flags, const char *summary,
const char *description,
const struct grub_arg_option *parser)
{
return grub_register_extcmd_prio (name, func, flags,
summary, description, parser, 1);
}
void
grub_unregister_extcmd (grub_extcmd_t ext)
{
grub_unregister_command (ext->cmd);
grub_free (ext);
}

View 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
View 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);
}

View 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);
}

View file

@ -0,0 +1,283 @@
/*
* 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},
{"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 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, int uncompress)
{
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;
if (!uncompress)
grub_file_filter_disable_compression ();
file = grub_file_open (filename);
grub_free (filename);
}
else
{
if (!uncompress)
grub_file_filter_disable_compression ();
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_context *ctxt,
int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
const char *hashname = NULL;
const char *prefix = NULL;
const gcry_md_spec_t *hash;
unsigned i;
int keep = state[3].set;
int uncompress = state[4].set;
unsigned unread = 0;
for (i = 0; i < ARRAY_SIZE (aliases); i++)
if (grub_strcmp (ctxt->extcmd->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, uncompress);
}
for (i = 0; i < (unsigned) argc; i++)
{
grub_uint8_t result[hash->mdlen];
grub_file_t file;
grub_err_t err;
unsigned j;
if (!uncompress)
grub_file_filter_disable_compression ();
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, 0,
"hashsum -h HASH [-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]",
"Compute or check hash checksum.",
options);
cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0,
N_("[-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]"),
N_("Compute or check hash checksum."),
options);
cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, 0,
N_("[-c FILE [-p PREFIX]] "
"[FILE1 [FILE2 ...]]"),
"Compute or check hash checksum.",
options);
cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, 0,
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);
}

420
grub-core/commands/hdparm.c Normal file
View file

@ -0,0 +1,420 @@
/* 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_context_t ctxt, int argc, char **args) // state????
{
struct grub_arg_list *state = ctxt->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, 0,
N_("[OPTIONS] DISK"),
N_("Get/set ATA disk parameters."), options);
}
GRUB_MOD_FINI(hdparm)
{
grub_unregister_extcmd (cmd);
}

141
grub-core/commands/help.c Normal file
View file

@ -0,0 +1,141 @@
/* 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_context_t ctxt __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))
{
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) &&
! (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD))
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, 0,
N_("[PATTERN ...]"),
N_("Show a help message."), 0);
}
GRUB_MOD_FINI(help)
{
grub_unregister_extcmd (cmd);
}

View file

@ -0,0 +1,131 @@
/* 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/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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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_file_open (args[0]);
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, 0,
N_("[OPTIONS] FILE_OR_DEVICE"),
N_("Dump the contents of a file or memory."),
options);
}
GRUB_MOD_FINI (hexdump)
{
grub_unregister_extcmd (cmd);
}

View 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);
}

View 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_context_t ctxt __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, 0,
"[-l]", N_("Check for CPU features."), options);
}
GRUB_MOD_FINI(cpuid)
{
grub_unregister_extcmd (cmd);
}

View 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;
}

View file

@ -0,0 +1,420 @@
/* 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_context *ctxt, int argc, char **args)
{
if (ctxt->state[OPTIDX_LIST].set)
{
return list_mappings ();
}
else if (ctxt->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 (!ctxt->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",
ctxt->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 (ctxt->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, 0,
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);
}

View 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

View file

@ -0,0 +1,125 @@
/* 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>
#include <grub/acpi.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;
grub_acpi_halt ();
if (no_apm)
stop ();
/* detect APM */
regs.eax = 0x5300;
regs.ebx = 0;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
grub_bios_interrupt (0x15, &regs);
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, &regs);
/* connect APM */
regs.eax = 0x5301;
regs.ebx = 0;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
grub_bios_interrupt (0x15, &regs);
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, &regs);
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, &regs);
/* shouldn't reach here */
stop ();
}
static grub_err_t
grub_cmd_halt (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = ctxt->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, 0, "[-n]",
N_("Halt the system, if possible using APM."),
options);
}
GRUB_MOD_FINI(halt)
{
grub_unregister_extcmd (cmd);
}

View 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, &note))
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);
}

View 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);
}

View file

@ -0,0 +1,383 @@
/* 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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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, 0,
"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);
}

View 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);
}

View file

@ -0,0 +1,178 @@
/* 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/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);
}

View 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
View 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_context_t ctxt, int argc, char **argv)
{
grub_target_addr_t addr;
grub_uint32_t value = 0;
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments");
addr = grub_strtoul (argv[0], 0, 0);
switch (ctxt->extcmd->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 (ctxt->state[0].set)
{
char buf[sizeof ("XXXXXXXX")];
grub_snprintf (buf, sizeof (buf), "%x", value);
grub_env_set (ctxt->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, 0,
N_("PORT"), N_("Read byte from PORT."), options);
cmd_read_word =
grub_register_extcmd ("inw", grub_cmd_read, 0,
N_("PORT"), N_("Read word from PORT."), options);
cmd_read_dword =
grub_register_extcmd ("inl", grub_cmd_read, 0,
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);
}

View file

@ -0,0 +1,92 @@
/* 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_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = ctxt->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, 0,
N_("[--shift] [--ctrl] [--alt]"),
N_("Check key modifier status."),
options);
}
GRUB_MOD_FINI(keystatus)
{
grub_unregister_extcmd (cmd);
}

View file

@ -0,0 +1,397 @@
/* 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);
grub_file_filter_disable_compression ();
file = grub_file_open (filename);
grub_free (filename);
return file;
}
else
{
grub_error (GRUB_ERR_FILE_NOT_FOUND, "prefix is not found");
return 0;
}
}
grub_file_filter_disable_compression ();
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_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = ctxt->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_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = ctxt->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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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, 0, N_("[-f FILE]"),
N_("Load variables from environment block file."),
options);
cmd_list =
grub_register_extcmd ("list_env", grub_cmd_list_env, 0, N_("[-f FILE]"),
N_("List variables from environment block file."),
options);
cmd_save =
grub_register_extcmd ("save_env", grub_cmd_save_env, 0,
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);
}

280
grub-core/commands/ls.c Normal file
View file

@ -0,0 +1,280 @@
/* 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. */
grub_file_filter_disable_compression ();
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;
grub_file_filter_disable_compression ();
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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
int i;
if (argc == 0)
grub_ls_list_devices (state[0].set);
else
for (i = 0; i < argc; i++)
grub_ls_list_files (args[i], 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, 0,
N_("[-l|-h|-a] [FILE]"),
N_("List devices and files."), options);
}
GRUB_MOD_FINI(ls)
{
grub_unregister_extcmd (cmd);
}

250
grub-core/commands/lsacpi.c Normal file
View file

@ -0,0 +1,250 @@
/* acpi.c - Display acpi tables. */
/*
* 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/mm.h>
#include <grub/misc.h>
#include <grub/normal.h>
#include <grub/acpi.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/dl.h>
static void
print_strn (grub_uint8_t *str, grub_size_t len)
{
for (; *str && len; str++, len--)
grub_printf ("%c", *str);
for (len++; len; len--)
grub_printf (" ");
}
#define print_field(x) print_strn(x, sizeof (x))
static void
disp_acpi_table (struct grub_acpi_table_header *t)
{
print_field (t->signature);
grub_printf ("%4" PRIuGRUB_UINT32_T "B rev=%u OEM=", t->length, t->revision);
print_field (t->oemid);
print_field (t->oemtable);
grub_printf ("OEMrev=%08" PRIxGRUB_UINT32_T " ", t->oemrev);
print_field (t->creator_id);
grub_printf (" %08" PRIxGRUB_UINT32_T "\n", t->creator_rev);
}
static void
disp_madt_table (struct grub_acpi_madt *t)
{
struct grub_acpi_madt_entry_header *d;
grub_uint32_t len;
disp_acpi_table (&t->hdr);
grub_printf ("Local APIC=%08" PRIxGRUB_UINT32_T " Flags=%08"
PRIxGRUB_UINT32_T "\n",
t->lapic_addr, t->flags);
len = t->hdr.length - sizeof (struct grub_acpi_madt);
d = t->entries;
for (;len > 0; len -= d->len, d = (void *) ((grub_uint8_t *) d + d->len))
{
grub_printf (" type=%x l=%u ", d->type, d->len);
switch (d->type)
{
case GRUB_ACPI_MADT_ENTRY_TYPE_INTERRUPT_OVERRIDE:
{
struct grub_acpi_madt_entry_interrupt_override *dt = (void *) d;
grub_printf ("Int Override bus=%x src=%x GSI=%08x Flags=%04x\n",
dt->bus, dt->source, dt->global_sys_interrupt,
dt->flags);
}
break;
case GRUB_ACPI_MADT_ENTRY_TYPE_SAPIC:
{
struct grub_acpi_madt_entry_sapic *dt = (void *) d;
grub_printf ("IOSAPIC Id=%02x GSI=%08x Addr=%016" PRIxGRUB_UINT64_T
"\n",
dt->id, dt->global_sys_interrupt_base,
dt->addr);
}
break;
case GRUB_ACPI_MADT_ENTRY_TYPE_LSAPIC:
{
struct grub_acpi_madt_entry_lsapic *dt = (void *) d;
grub_printf ("LSAPIC ProcId=%02x ID=%02x EID=%02x Flags=%x",
dt->cpu_id, dt->id, dt->eid, dt->flags);
if (dt->flags & GRUB_ACPI_MADT_ENTRY_SAPIC_FLAGS_ENABLED)
grub_printf (" Enabled\n");
else
grub_printf (" Disabled\n");
if (d->len > sizeof (struct grub_acpi_madt_entry_sapic))
grub_printf (" UID val=%08x, Str=%s\n", dt->cpu_uid,
dt->cpu_uid_str);
}
break;
case GRUB_ACPI_MADT_ENTRY_TYPE_PLATFORM_INT_SOURCE:
{
struct grub_acpi_madt_entry_platform_int_source *dt = (void *) d;
static const char * const platint_type[] =
{"Nul", "PMI", "INIT", "CPEI"};
grub_printf ("Platform INT flags=%04x type=%02x (%s)"
" ID=%02x EID=%02x\n",
dt->flags, dt->inttype,
(dt->inttype < ARRAY_SIZE (platint_type))
? platint_type[dt->inttype] : "??", dt->cpu_id,
dt->cpu_eid);
grub_printf (" IOSAPIC Vec=%02x GSI=%08x source flags=%08x\n",
dt->sapic_vector, dt->global_sys_int, dt->src_flags);
}
break;
default:
grub_printf (" ??\n");
}
}
}
static void
disp_acpi_xsdt_table (struct grub_acpi_table_header *t)
{
grub_uint32_t len;
grub_uint64_t *desc;
disp_acpi_table (t);
len = t->length - sizeof (*t);
desc = (grub_uint64_t *) (t + 1);
for (; len > 0; desc++, len -= sizeof (*desc))
{
if (sizeof (grub_addr_t) == 4 && *desc >= (1ULL << 32))
{
grub_printf ("Unreachable table\n");
continue;
}
t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;
if (t == NULL)
continue;
if (grub_memcmp (t->signature, GRUB_ACPI_MADT_SIGNATURE,
sizeof (t->signature)) == 0)
disp_madt_table ((struct grub_acpi_madt *) t);
else
disp_acpi_table (t);
}
}
static void
disp_acpi_rsdt_table (struct grub_acpi_table_header *t)
{
grub_uint32_t len;
grub_uint32_t *desc;
disp_acpi_table (t);
len = t->length - sizeof (*t);
desc = (grub_uint32_t *) (t + 1);
for (; len > 0; desc++, len -= sizeof (*desc))
{
t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;
if (t == NULL)
continue;
if (grub_memcmp (t->signature, GRUB_ACPI_MADT_SIGNATURE,
sizeof (t->signature)) == 0)
disp_madt_table ((struct grub_acpi_madt *) t);
else
disp_acpi_table (t);
}
}
static void
disp_acpi_rsdpv1 (struct grub_acpi_rsdp_v10 *rsdp)
{
print_field (rsdp->signature);
grub_printf ("chksum:%02x, OEM-ID: ", rsdp->checksum);
print_field (rsdp->oemid);
grub_printf ("rev=%d\n", rsdp->revision);
grub_printf ("RSDT=%08" PRIxGRUB_UINT32_T "\n", rsdp->rsdt_addr);
}
static void
disp_acpi_rsdpv2 (struct grub_acpi_rsdp_v20 *rsdp)
{
disp_acpi_rsdpv1 (&rsdp->rsdpv1);
grub_printf ("len=%d XSDT=%016" PRIxGRUB_UINT64_T "\n", rsdp->length,
rsdp->xsdt_addr);
}
static const struct grub_arg_option options[] = {
{"v1", '1', 0, N_("Show v1 tables only."), 0, ARG_TYPE_NONE},
{"v2", '2', 0, N_("Show v2 and v3 tablesv only."), 0, ARG_TYPE_NONE}
};
static grub_err_t
grub_cmd_lsacpi (struct grub_extcmd_context *ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
if (!ctxt->state[1].set)
{
struct grub_acpi_rsdp_v10 *rsdp1 = grub_acpi_get_rsdpv1 ();
if (!rsdp1)
grub_printf ("No RSDPv1\n");
else
{
grub_printf ("RSDPv1 signature:");
disp_acpi_rsdpv1 (rsdp1);
disp_acpi_rsdt_table ((void *) (grub_addr_t) rsdp1->rsdt_addr);
}
}
if (!ctxt->state[0].set)
{
struct grub_acpi_rsdp_v20 *rsdp2 = grub_acpi_get_rsdpv2 ();
if (!rsdp2)
grub_printf ("No RSDPv2\n");
else
{
if (sizeof (grub_addr_t) == 4 && rsdp2->xsdt_addr >= (1ULL << 32))
grub_printf ("Unreachable RSDPv2\n");
else
{
grub_printf ("RSDPv2 signature:");
disp_acpi_rsdpv2 (rsdp2);
disp_acpi_xsdt_table ((void *) (grub_addr_t) rsdp2->xsdt_addr);
grub_printf ("\n");
}
}
}
return GRUB_ERR_NONE;
}
static grub_extcmd_t cmd;
GRUB_MOD_INIT(lsapi)
{
cmd = grub_register_extcmd ("lsacpi", grub_cmd_lsacpi, 0, N_("[-1|-2]"),
N_("Show ACPI information."), options);
}
GRUB_MOD_FINI(lsacpi)
{
grub_unregister_extcmd (cmd);
}

View 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
View 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_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
iospace = ctxt->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, 0, "[-i]",
N_("List PCI devices."), options);
}
GRUB_MOD_FINI(lspci)
{
grub_unregister_extcmd (cmd);
}

149
grub-core/commands/memrw.c Normal file
View 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_context_t ctxt, 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 (ctxt->extcmd->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 (ctxt->state[0].set)
{
grub_snprintf (buf, sizeof (buf), "%x", value);
grub_env_set (ctxt->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, 0,
N_("ADDR"), N_("Read byte from ADDR."), options);
cmd_read_word =
grub_register_extcmd ("read_word", grub_cmd_read, 0,
N_("ADDR"), N_("Read word from ADDR."), options);
cmd_read_dword =
grub_register_extcmd ("read_dword", grub_cmd_read, 0,
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);
}

View file

@ -0,0 +1,285 @@
/* menuentry.c - menuentry command */
/*
* 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/err.h>
#include <grub/dl.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/normal.h>
static const struct grub_arg_option options[] =
{
{"class", 1, GRUB_ARG_OPTION_REPEATABLE,
N_("Menu entry type."), "STRING", ARG_TYPE_STRING},
{"users", 2, 0,
N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
{"hotkey", 3, 0,
N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
{"source", 4, 0,
N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
static struct
{
char *name;
int key;
} hotkey_aliases[] =
{
{"backspace", '\b'},
{"tab", '\t'},
{"delete", GRUB_TERM_DC}
};
/* Add a menu entry to the current menu context (as given by the environment
variable data slot `menu'). As the configuration file is read, the script
parser calls this when a menu entry is to be created. */
static grub_err_t
append_menu_entry (int argc, const char **args, char **classes,
const char *users, const char *hotkey,
const char *prefix, const char *sourcecode)
{
unsigned i;
int menu_hotkey = 0;
char **menu_args = NULL;
char *menu_users = NULL;
char *menu_title = NULL;
char *menu_sourcecode = NULL;
struct grub_menu_entry_class *menu_classes = NULL;
grub_menu_t menu;
grub_menu_entry_t *last;
menu = grub_env_get_menu ();
if (! menu)
return grub_error (GRUB_ERR_MENU, "no menu context");
last = &menu->entry_list;
menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
if (! menu_sourcecode)
return grub_errno;
if (classes)
{
for (i = 0; classes[i]; i++); /* count # of menuentry classes */
menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i);
if (! menu_classes)
goto fail;
for (i = 0; classes[i]; i++)
{
menu_classes[i].name = grub_strdup (classes[i]);
if (! menu_classes[i].name)
goto fail;
menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
}
}
if (users)
{
menu_users = grub_strdup (users);
if (! menu_users)
goto fail;
}
if (hotkey)
{
for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
{
menu_hotkey = hotkey_aliases[i].key;
break;
}
if (i == ARRAY_SIZE (hotkey_aliases))
menu_hotkey = hotkey[0];
}
if (! argc)
{
grub_error (GRUB_ERR_MENU, "menuentry is missing title");
goto fail;
}
menu_title = grub_strdup (args[0]);
if (! menu_title)
goto fail;
/* Save argc, args to pass as parameters to block arg later. */
menu_args = grub_malloc (sizeof (char*) * (argc + 1));
if (! menu_args)
goto fail;
for (i = 0; i < argc; i++)
{
menu_args[i] = grub_strdup (args[i]);
if (! menu_args[i])
goto fail;
}
menu_args[argc] = NULL;
/* Add the menu entry at the end of the list. */
while (*last)
last = &(*last)->next;
*last = grub_zalloc (sizeof (**last));
if (! *last)
goto fail;
(*last)->title = menu_title;
(*last)->hotkey = menu_hotkey;
(*last)->classes = menu_classes;
if (menu_users)
(*last)->restricted = 1;
(*last)->users = menu_users;
(*last)->argc = argc;
(*last)->args = menu_args;
(*last)->sourcecode = menu_sourcecode;
menu->size++;
return GRUB_ERR_NONE;
fail:
grub_free (menu_sourcecode);
for (i = 0; menu_classes && menu_classes[i].name; i++)
grub_free (menu_classes[i].name);
grub_free (menu_classes);
for (i = 0; menu_args && menu_args[i]; i++)
grub_free (menu_args[i]);
grub_free (menu_args);
grub_free (menu_users);
grub_free (menu_title);
return grub_errno;
}
static char *
setparams_prefix (int argc, char **args)
{
int i;
int j;
char *p;
char *result;
grub_size_t len = 10;
static const char *escape_characters = "\"\\";
auto char *strescpy (char *, const char *, const char *);
char * strescpy (char *d, const char *s, const char *escapes)
{
while (*s)
{
if (grub_strchr (escapes, *s))
*d++ = '\\';
*d++ = *s++;
}
*d = '\0';
return d;
}
/* Count resulting string length */
for (i = 0; i < argc; i++)
{
len += 3; /* 3 = 1 space + 2 quotes */
p = args[i];
while (*p)
len += grub_strchr (escape_characters, *p++) ? 2 : 1;
}
result = grub_malloc (len + 2);
if (! result)
return 0;
grub_strcpy (result, "setparams");
i = 9;
for (j = 0; j < argc; j++)
{
result[i++] = ' ';
result[i++] = '"';
i = strescpy (result + i, args[j], escape_characters) - result;
result[i++] = '"';
}
result[i++] = '\n';
result[i] = '\0';
return result;
}
static grub_err_t
grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
{
char ch;
char *src;
char *prefix;
unsigned len;
grub_err_t r;
if (! argc)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
if (ctxt->state[3].set && ctxt->script)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
if (! ctxt->state[3].set && ! ctxt->script)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
if (! ctxt->script)
return append_menu_entry (argc, (const char **) args,
ctxt->state[0].args, ctxt->state[1].arg,
ctxt->state[2].arg, 0, ctxt->state[3].arg);
src = args[argc - 1];
args[argc - 1] = NULL;
len = grub_strlen(src);
ch = src[len - 1];
src[len - 1] = '\0';
prefix = setparams_prefix (argc - 1, args);
if (! prefix)
return grub_errno;
r = append_menu_entry (argc - 1, (const char **) args,
ctxt->state[0].args, ctxt->state[1].arg,
ctxt->state[2].arg, prefix, src + 1);
src[len - 1] = ch;
args[argc - 1] = src;
grub_free (prefix);
return r;
}
static grub_extcmd_t cmd;
void
grub_menu_init (void)
{
cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
GRUB_COMMAND_FLAG_BLOCKS,
N_("BLOCK"), N_("Define a menuentry."), options);
}
void
grub_menu_fini (void)
{
grub_unregister_extcmd (cmd);
}

View file

@ -0,0 +1,228 @@
/* 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
/* 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;
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_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_dump);
grub_unregister_command (cmd_rmmod);
grub_unregister_command (cmd_lsmod);
grub_unregister_command (cmd_exit);
}

View 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);
}

View 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[j],
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);
}

View 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);
}

View 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);
}

160
grub-core/commands/probe.c Normal file
View file

@ -0,0 +1,160 @@
/*
* 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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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->dev->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, 0, N_("[DEVICE]"),
N_("Retrieve device info."), options);
}
GRUB_MOD_FINI (probe)
{
grub_unregister_extcmd (cmd);
}

90
grub-core/commands/read.c Normal file
View 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);
}

View 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);
}

150
grub-core/commands/regexp.c Normal file
View file

@ -0,0 +1,150 @@
/* 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/err.h>
#include <grub/env.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/script_sh.h>
#include <regex.h>
static const struct grub_arg_option options[] =
{
{ "set", 's', GRUB_ARG_OPTION_REPEATABLE,
N_("Variable names to update with matches."),
N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING },
{ 0, 0, 0, 0, 0, 0 }
};
static grub_err_t
set_matches (char **varnames, char *str, grub_size_t nmatches,
regmatch_t *matches)
{
int i;
char ch;
char *p;
char *q;
grub_err_t err;
unsigned long j;
auto void setvar (char *v, regmatch_t *m);
void setvar (char *v, regmatch_t *m)
{
ch = str[m->rm_eo];
str[m->rm_eo] = '\0';
err = grub_env_set (v, str + m->rm_so);
str[m->rm_eo] = ch;
}
for (i = 0; varnames && varnames[i]; i++)
{
if (! (p = grub_strchr (varnames[i], ':')))
{
/* varname w/o index defaults to 1 */
if (nmatches < 2 || matches[1].rm_so == -1)
grub_env_unset (varnames[i]);
else
setvar (varnames[i], &matches[1]);
}
else
{
j = grub_strtoul (varnames[i], &q, 10);
if (q != p)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"invalid variable name format %s", varnames[i]);
if (nmatches <= j || matches[j].rm_so == -1)
grub_env_unset (p + 1);
else
setvar (p + 1, &matches[j]);
}
if (err != GRUB_ERR_NONE)
return err;
}
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args)
{
int argn = 0;
regex_t regex;
int ret;
grub_size_t s;
char *comperr;
grub_err_t err;
regmatch_t *matches = 0;
if (argc != 2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected");
ret = regcomp (&regex, args[0], REG_EXTENDED);
if (ret)
goto fail;
matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1));
if (! matches)
goto fail;
ret = regexec (&regex, args[1], regex.re_nsub + 1, matches, 0);
if (!ret)
{
err = set_matches (ctxt->state[0].args, args[1],
regex.re_nsub + 1, matches);
regfree (&regex);
grub_free (matches);
return err;
}
fail:
grub_free (matches);
s = regerror (ret, &regex, 0, 0);
comperr = grub_malloc (s);
if (!comperr)
{
regfree (&regex);
return grub_errno;
}
regerror (ret, &regex, comperr, s);
err = grub_error (GRUB_ERR_TEST_FAILURE, "%s", comperr);
regfree (&regex);
grub_free (comperr);
return err;
}
static grub_extcmd_t cmd;
GRUB_MOD_INIT(regexp)
{
cmd = grub_register_extcmd ("regexp", grub_cmd_regexp, 0, N_("REGEXP STRING"),
N_("Test if REGEXP matches STRING."), options);
/* Setup GRUB script wildcard translator. */
grub_wildcard_translator = &grub_filename_translator;
}
GRUB_MOD_FINI(regexp)
{
grub_unregister_extcmd (cmd);
grub_wildcard_translator = 0;
}

243
grub-core/commands/search.c Normal file
View file

@ -0,0 +1,243 @@
/* 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>
#include <grub/disk.h>
#include <grub/partition.h>
void
FUNC_NAME (const char *key, const char *var, int no_floppy,
char **hints, unsigned nhints)
{
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;
grub_file_filter_disable_compression ();
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);
}
auto int part_hook (grub_disk_t disk, const grub_partition_t partition);
int part_hook (grub_disk_t disk, const grub_partition_t partition)
{
char *partition_name, *devname;
int ret;
partition_name = grub_partition_get_name (partition);
if (! partition_name)
return 1;
devname = grub_xasprintf ("%s,%s", disk->name, partition_name);
grub_free (partition_name);
if (!devname)
return 1;
ret = iterate_device (devname);
grub_free (devname);
return ret;
}
auto void try (void);
void try (void)
{
unsigned i;
for (i = 0; i < nhints; i++)
{
char *end;
if (!hints[i][0])
continue;
end = hints[i] + grub_strlen (hints[i]) - 1;
if (*end == ',')
*end = 0;
if (iterate_device (hints[i]))
{
if (!*end)
*end = ',';
return;
}
if (!*end)
{
grub_device_t dev;
int ret;
dev = grub_device_open (hints[i]);
if (!dev)
{
*end = ',';
continue;
}
if (!dev->disk)
{
grub_device_close (dev);
*end = ',';
continue;
}
ret = grub_partition_iterate (dev->disk, part_hook);
*end = ',';
grub_device_close (dev);
if (ret)
return;
}
}
grub_device_iterate (iterate_device);
}
/* First try without autoloading if we're setting variable. */
if (var)
{
saved_autoload = grub_fs_autoload_hook;
grub_fs_autoload_hook = 0;
try ();
/* Restore autoload hook. */
grub_fs_autoload_hook = saved_autoload;
/* Retry with autoload if nothing found. */
if (grub_errno == GRUB_ERR_NONE && count == 0)
try ();
}
else
try ();
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, (args + 2),
argc > 2 ? argc - 2 : 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] [HINTS]"),
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);
}

View 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"

View 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"

View 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"

View file

@ -0,0 +1,107 @@
/* 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},
{"hint", 'h', GRUB_ARG_OPTION_REPEATABLE,
N_("First try the device HINT. If HINT ends in comma, "
"also try subpartitions"), N_("HINT"), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
enum options
{
SEARCH_FILE,
SEARCH_LABEL,
SEARCH_FS_UUID,
SEARCH_SET,
SEARCH_NO_FLOPPY,
SEARCH_HINT
};
static grub_err_t
grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->state;
const char *var = 0;
int nhints = 0;
if (state[SEARCH_HINT].set)
while (state[SEARCH_HINT].args[nhints])
nhints++;
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,
state[SEARCH_HINT].args, nhints);
else if (state[SEARCH_FS_UUID].set)
grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set,
state[SEARCH_HINT].args, nhints);
else if (state[SEARCH_FILE].set)
grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set,
state[SEARCH_HINT].args, nhints);
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, 0,
N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]"
" 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
View 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_context_t ctxt, int argc, char **argv)
{
const char *ptr;
unsigned i;
pciid_check_value = 0;
pciid_check_mask = 0;
if (ctxt->state[0].set)
{
ptr = ctxt->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 = ctxt->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 (ctxt->state[1].set)
{
const char *optr;
ptr = ctxt->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 (ctxt->state[2].set)
varname = ctxt->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, 0,
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
View 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_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = ctxt->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, 0,
N_("NUMBER_OF_SECONDS"),
N_("Wait for a specified number of seconds."),
options);
}
GRUB_MOD_FINI(sleep)
{
grub_unregister_extcmd (cmd);
}

View 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);
}

434
grub-core/commands/test.c Normal file
View file

@ -0,0 +1,434 @@
/* 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;
grub_file_filter_disable_compression ();
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);
}

View file

@ -0,0 +1,155 @@
/* minicmd.c - commands for the rescue mode */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <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>
static grub_err_t
grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file;
char *buf;
grub_size_t size;
grub_off_t pos;
auto void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector, unsigned offset, unsigned len);
void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector __attribute__ ((unused)),
unsigned offset __attribute__ ((unused)),
unsigned len __attribute__ ((unused)))
{
grub_xputs (".");
grub_refresh ();
}
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
file = grub_file_open (argv[0]);
if (! file)
return grub_errno;
size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
if (size == 0)
{
grub_file_close (file);
return GRUB_ERR_NONE;
}
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) != (grub_ssize_t) size)
goto fail;
grub_printf (" Done.\n");
/* Read sequentially again. */
grub_printf ("Reading %s sequentially again", argv[0]);
grub_file_seek (file, 0);
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 %lld\n", (unsigned long long) 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;
grub_file_seek (file, pos);
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 %lld\n", (unsigned long long) pos);
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
{
grub_printf ("%02x ", buf[pos + i]);
if ((i & 15) == 15)
grub_printf ("\n");
}
if (i)
grub_refresh ();
goto fail;
}
}
grub_printf (" Done.\n");
return GRUB_ERR_NONE;
fail:
grub_file_close (file);
grub_free (buf);
if (!grub_errno)
grub_error (GRUB_ERR_IO, "bad read");
return grub_errno;
}
static grub_command_t cmd;
GRUB_MOD_INIT(testload)
{
cmd =
grub_register_command ("testload", grub_cmd_testload,
N_("FILE"),
N_("Load the same file in multiple ways."));
}
GRUB_MOD_FINI(testload)
{
grub_unregister_command (cmd);
}

57
grub-core/commands/true.c Normal file
View 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);
}

View 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);
}

View file

@ -0,0 +1,150 @@
/* videoinfo.c - command to list video modes. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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/video.h>
#include <grub/dl.h>
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/command.h>
#include <grub/i18n.h>
static int
hook (const struct grub_video_mode_info *info)
{
if (info->mode_number == GRUB_VIDEO_MODE_NUMBER_INVALID)
grub_printf (" ");
else
grub_printf (" 0x%03x ", info->mode_number);
grub_printf ("%4d x %4d x %2d ", info->width, info->height, info->bpp);
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
grub_printf ("Text-only ");
/* Show mask and position details for direct color modes. */
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_RGB)
grub_printf ("Direct, mask: %d/%d/%d/%d pos: %d/%d/%d/%d",
info->red_mask_size,
info->green_mask_size,
info->blue_mask_size,
info->reserved_mask_size,
info->red_field_pos,
info->green_field_pos,
info->blue_field_pos,
info->reserved_field_pos);
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)
grub_printf ("Packed ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_YUV)
grub_printf ("YUV ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PLANAR)
grub_printf ("Planar ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_HERCULES)
grub_printf ("Hercules ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_CGA)
grub_printf ("CGA ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_NONCHAIN4)
grub_printf ("Non-chain 4 ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP)
grub_printf ("Monochrome ");
if (info->mode_type & GRUB_VIDEO_MODE_TYPE_UNKNOWN)
grub_printf ("Unknown ");
grub_printf ("\n");
return 0;
}
static grub_err_t
grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
grub_video_adapter_t adapter;
grub_video_driver_id_t id;
#ifdef GRUB_MACHINE_PCBIOS
if (grub_strcmp (cmd->name, "vbeinfo") == 0)
grub_dl_load ("vbe");
#endif
id = grub_video_get_driver_id ();
grub_printf ("List of supported video modes:\n");
grub_printf ("Legend: P=Packed pixel, D=Direct color, "
"mask/pos=R/G/B/reserved\n");
FOR_VIDEO_ADAPTERS (adapter)
{
grub_printf ("Adapter '%s':\n", adapter->name);
if (!adapter->iterate)
{
grub_printf (" No info available\n");
continue;
}
if (adapter->id != id)
{
if (adapter->init ())
{
grub_printf (" Failed\n");
grub_errno = GRUB_ERR_NONE;
continue;
}
}
if (adapter->print_adapter_specific_info)
adapter->print_adapter_specific_info ();
adapter->iterate (hook);
if (adapter->id != id)
{
if (adapter->fini ())
{
grub_errno = GRUB_ERR_NONE;
continue;
}
}
}
return GRUB_ERR_NONE;
}
static grub_command_t cmd;
#ifdef GRUB_MACHINE_PCBIOS
static grub_command_t cmd_vbe;
#endif
GRUB_MOD_INIT(videoinfo)
{
cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo, 0,
N_("List available video modes."));
#ifdef GRUB_MACHINE_PCBIOS
cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo, 0,
N_("List available video modes."));
#endif
}
GRUB_MOD_FINI(videoinfo)
{
grub_unregister_command (cmd);
#ifdef GRUB_MACHINE_PCBIOS
grub_unregister_command (cmd_vbe);
#endif
}

View file

@ -0,0 +1,216 @@
/*
* 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>
#include <grub/env.h>
static grub_err_t
grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
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];
const char *mode = NULL;
#ifdef GRUB_MACHINE_PCBIOS
if (grub_strcmp (cmd->name, "vbetest") == 0)
grub_dl_load ("vbe");
#endif
mode = grub_env_get ("gfxmode");
if (argc)
mode = args[0];
if (!mode)
mode = "auto";
err = grub_video_set_mode (mode, 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;
#ifdef GRUB_MACHINE_PCBIOS
static grub_command_t cmd_vbe;
#endif
GRUB_MOD_INIT(videotest)
{
cmd = grub_register_command ("videotest", grub_cmd_videotest,
"[WxH]",
N_("Test video subsystem in mode WxH."));
#ifdef GRUB_MACHINE_PCBIOS
cmd_vbe = grub_register_command ("vbetest", grub_cmd_videotest,
0, N_("Test video subsystem."));
#endif
}
GRUB_MOD_FINI(videotest)
{
grub_unregister_command (cmd);
#ifdef GRUB_MACHINE_PCBIOS
grub_unregister_command (cmd_vbe);
#endif
}

View file

@ -0,0 +1,498 @@
/* wildcard.c - Wildcard character expansion for GRUB script. */
/*
* 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/mm.h>
#include <grub/fs.h>
#include <grub/env.h>
#include <grub/file.h>
#include <grub/device.h>
#include <grub/script_sh.h>
#include <regex.h>
static inline int isregexop (char ch);
static char ** merge (char **lhs, char **rhs);
static char *make_dir (const char *prefix, const char *start, const char *end);
static int make_regex (const char *regex_start, const char *regex_end,
regex_t *regexp);
static void split_path (const char *path, const char **suffix_end, const char **regex_end);
static char ** match_devices (const regex_t *regexp, int noparts);
static char ** match_files (const char *prefix, const char *suffix_start,
const char *suffix_end, const regex_t *regexp);
static char* wildcard_escape (const char *s);
static char* wildcard_unescape (const char *s);
static grub_err_t wildcard_expand (const char *s, char ***strs);
struct grub_script_wildcard_translator grub_filename_translator = {
.expand = wildcard_expand,
.escape = wildcard_escape,
.unescape = wildcard_unescape
};
static char **
merge (char **dest, char **ps)
{
int i;
int j;
char **p;
if (! dest)
return ps;
if (! ps)
return dest;
for (i = 0; dest[i]; i++)
;
for (j = 0; ps[j]; j++)
;
p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
if (! p)
{
grub_free (dest);
grub_free (ps);
return 0;
}
dest = p;
for (j = 0; ps[j]; j++)
dest[i++] = ps[j];
dest[i] = 0;
grub_free (ps);
return dest;
}
static inline int
isregexop (char ch)
{
return grub_strchr ("*.\\", ch) ? 1 : 0;
}
static char *
make_dir (const char *prefix, const char *start, const char *end)
{
char ch;
unsigned i;
unsigned n;
char *result;
i = grub_strlen (prefix);
n = i + end - start;
result = grub_malloc (n + 1);
if (! result)
return 0;
grub_strcpy (result, prefix);
while (start < end && (ch = *start++))
if (ch == '\\' && isregexop (*start))
result[i++] = *start++;
else
result[i++] = ch;
result[i] = '\0';
return result;
}
static int
make_regex (const char *start, const char *end, regex_t *regexp)
{
char ch;
int i = 0;
unsigned len = end - start;
char *buffer = grub_malloc (len * 2 + 2 + 1); /* worst case size. */
if (! buffer)
return 1;
buffer[i++] = '^';
while (start < end)
{
/* XXX Only * expansion for now. */
switch ((ch = *start++))
{
case '\\':
buffer[i++] = ch;
if (*start != '\0')
buffer[i++] = *start++;
break;
case '.':
case '(':
case ')':
buffer[i++] = '\\';
buffer[i++] = ch;
break;
case '*':
buffer[i++] = '.';
buffer[i++] = '*';
break;
default:
buffer[i++] = ch;
}
}
buffer[i++] = '$';
buffer[i] = '\0';
grub_dprintf ("expand", "Regexp is %s\n", buffer);
if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK))
{
grub_free (buffer);
return 1;
}
grub_free (buffer);
return 0;
}
/* Split `str' into two parts: (1) dirname that is regexop free (2)
dirname that has a regexop. */
static void
split_path (const char *str, const char **noregexop, const char **regexop)
{
char ch = 0;
int regex = 0;
const char *end;
const char *split; /* points till the end of dirnaname that doesn't
need expansion. */
split = end = str;
while ((ch = *end))
{
if (ch == '\\' && end[1])
end++;
else if (isregexop (ch))
regex = 1;
else if (ch == '/' && ! regex)
split = end + 1; /* forward to next regexop-free dirname */
else if (ch == '/' && regex)
break; /* stop at the first dirname with a regexop */
end++;
}
*regexop = end;
if (! regex)
*noregexop = end;
else
*noregexop = split;
}
static char **
match_devices (const regex_t *regexp, int noparts)
{
int i;
int ndev;
char **devs;
auto int match (const char *name);
int match (const char *name)
{
char **t;
char *buffer;
/* skip partitions if asked to. */
if (noparts && grub_strchr(name, ','))
return 0;
buffer = grub_xasprintf ("(%s)", name);
if (! buffer)
return 1;
grub_dprintf ("expand", "matching: %s\n", buffer);
if (regexec (regexp, buffer, 0, 0, 0))
{
grub_dprintf ("expand", "not matched\n");
grub_free (buffer);
return 0;
}
t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
if (! t)
return 1;
devs = t;
devs[ndev++] = buffer;
devs[ndev] = 0;
return 0;
}
ndev = 0;
devs = 0;
if (grub_device_iterate (match))
goto fail;
return devs;
fail:
for (i = 0; devs && devs[i]; i++)
grub_free (devs[i]);
if (devs)
grub_free (devs);
return 0;
}
static char **
match_files (const char *prefix, const char *suffix, const char *end,
const regex_t *regexp)
{
int i;
int error;
char **files;
unsigned nfile;
char *dir;
const char *path;
char *device_name;
grub_fs_t fs;
grub_device_t dev;
auto int match (const char *name, const struct grub_dirhook_info *info);
int match (const char *name, const struct grub_dirhook_info *info)
{
char **t;
char *buffer;
/* skip . and .. names */
if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
return 0;
grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
if (regexec (regexp, name, 0, 0, 0))
return 0;
buffer = grub_xasprintf ("%s%s", dir, name);
if (! buffer)
return 1;
t = grub_realloc (files, sizeof (char*) * (nfile + 2));
if (! t)
{
grub_free (buffer);
return 1;
}
files = t;
files[nfile++] = buffer;
files[nfile] = 0;
return 0;
}
nfile = 0;
files = 0;
dev = 0;
device_name = 0;
grub_error_push ();
dir = make_dir (prefix, suffix, end);
if (! dir)
goto fail;
device_name = grub_file_get_device_name (dir);
dev = grub_device_open (device_name);
if (! dev)
goto fail;
fs = grub_fs_probe (dev);
if (! fs)
goto fail;
path = grub_strchr (dir, ')');
if (! path)
goto fail;
path++;
if (fs->dir (dev, path, match))
goto fail;
grub_free (dir);
grub_device_close (dev);
grub_free (device_name);
grub_error_pop ();
return files;
fail:
if (dir)
grub_free (dir);
for (i = 0; files && files[i]; i++)
grub_free (files[i]);
if (files)
grub_free (files);
if (dev)
grub_device_close (dev);
if (device_name)
grub_free (device_name);
grub_error_pop ();
return 0;
}
static char*
wildcard_escape (const char *s)
{
int i;
int len;
char ch;
char *p;
len = grub_strlen (s);
p = grub_malloc (len * 2 + 1);
if (! p)
return NULL;
i = 0;
while ((ch = *s++))
{
if (isregexop (ch))
p[i++] = '\\';
p[i++] = ch;
}
p[i] = '\0';
return p;
}
static char*
wildcard_unescape (const char *s)
{
int i;
int len;
char ch;
char *p;
len = grub_strlen (s);
p = grub_malloc (len + 1);
if (! p)
return NULL;
i = 0;
while ((ch = *s++))
{
if (ch == '\\' && isregexop (*s))
p[i++] = *s++;
else
p[i++] = ch;
}
p[i] = '\0';
return p;
}
static grub_err_t
wildcard_expand (const char *s, char ***strs)
{
const char *start;
const char *regexop;
const char *noregexop;
char **paths = 0;
unsigned i;
regex_t regexp;
start = s;
while (*start)
{
split_path (start, &noregexop, &regexop);
if (noregexop >= regexop) /* no more wildcards */
break;
if (make_regex (noregexop, regexop, &regexp))
goto fail;
if (paths == 0)
{
if (start == noregexop) /* device part has regexop */
paths = match_devices (&regexp, *start != '(');
else if (*start == '(') /* device part explicit wo regexop */
paths = match_files ("", start, noregexop, &regexp);
else if (*start == '/') /* no device part */
{
char **r;
unsigned n;
char *root;
char *prefix;
root = grub_env_get ("root");
if (! root)
goto fail;
prefix = grub_xasprintf ("(%s)", root);
if (! prefix)
goto fail;
paths = match_files (prefix, start, noregexop, &regexp);
grub_free (prefix);
}
}
else
{
char **r = 0;
for (i = 0; paths[i]; i++)
{
char **p;
p = match_files (paths[i], start, noregexop, &regexp);
if (! p)
continue;
r = merge (r, p);
if (! r)
goto fail;
}
paths = r;
}
regfree (&regexp);
if (! paths)
goto done;
start = regexop;
}
done:
*strs = paths;
return 0;
fail:
for (i = 0; paths && paths[i]; i++)
grub_free (paths[i]);
grub_free (paths);
regfree (&regexp);
return grub_errno;
}

View 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);
}

916
grub-core/disk/ata.c Normal file
View file

@ -0,0 +1,916 @@
/* 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->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
View 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;
}

View 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);
}

View file

@ -0,0 +1,847 @@
/*
* 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':
d = get_device (fd_devices, num);
break;
case 'c':
d = get_device (cd_devices, num);
break;
case 'h':
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;
}

95
grub-core/disk/host.c Normal file
View file

@ -0,0 +1,95 @@
/* 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->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);
}

View file

@ -0,0 +1,634 @@
/*
* 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, &regs);
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, &regs);
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, &regs);
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, &regs);
/* 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, &regs);
}
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, &regs);
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, &regs);
/* 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, &regs);
/* 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] == 'c' && name[1] == 'd' && name[2] == 0 && cd_drive)
return cd_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];
if (cd_drive && drive == cd_drive)
return hook ("cd");
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->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 ();
}

View file

@ -0,0 +1,214 @@
/* 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->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);
}

Some files were not shown because too many files have changed in this diff Show more