mirror of
https://github.com/ventoy/Ventoy.git
synced 2025-08-28 00:11:15 +00:00
1. change some directory structure for the build script
2. add build script and document see DOC/BuildVentoyFromSource.txt for detail
This commit is contained in:
2517
GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def
Normal file
2517
GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def
Normal file
File diff suppressed because it is too large
Load Diff
545
GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S
Normal file
545
GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S
Normal file
@@ -0,0 +1,545 @@
|
||||
/* -*-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/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)
|
||||
|
||||
.macro floppy
|
||||
part_start:
|
||||
|
||||
LOCAL(probe_values):
|
||||
.byte 36, 18, 15, 9, 0
|
||||
|
||||
LOCAL(floppy_probe):
|
||||
pushw %dx
|
||||
/*
|
||||
* Perform floppy probe.
|
||||
*/
|
||||
#ifdef __APPLE__
|
||||
LOCAL(probe_values_minus_one) = LOCAL(probe_values) - 1
|
||||
movw MACRO_DOLLAR(LOCAL(probe_values_minus_one)), %si
|
||||
#else
|
||||
movw MACRO_DOLLAR(LOCAL(probe_values)) - 1, %si
|
||||
#endif
|
||||
|
||||
LOCAL(probe_loop):
|
||||
/* reset floppy controller INT 13h AH=0 */
|
||||
xorw %ax, %ax
|
||||
int MACRO_DOLLAR(0x13)
|
||||
|
||||
incw %si
|
||||
movb (%si), %cl
|
||||
|
||||
/* if number of sectors is 0, display error and die */
|
||||
testb %cl, %cl
|
||||
jnz 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 MACRO_DOLLAR(GRUB_BOOT_MACHINE_BUFFER_SEG), %bx
|
||||
movw %bx, %es
|
||||
xorw %bx, %bx
|
||||
movw MACRO_DOLLAR(0x201), %ax
|
||||
movb MACRO_DOLLAR(0), %ch
|
||||
movb MACRO_DOLLAR(0), %dh
|
||||
int MACRO_DOLLAR(0x13)
|
||||
|
||||
/* if error, jump to "LOCAL(probe_loop)" */
|
||||
jc LOCAL(probe_loop)
|
||||
|
||||
/* %cl is already the correct value! */
|
||||
movb MACRO_DOLLAR(1), %dh
|
||||
movb MACRO_DOLLAR(79), %ch
|
||||
|
||||
jmp LOCAL(final_init)
|
||||
.endm
|
||||
|
||||
.macro scratch
|
||||
|
||||
/* 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... */
|
||||
.endm
|
||||
|
||||
.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 ??? */
|
||||
|
||||
#ifdef HYBRID_BOOT
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
nop
|
||||
nop
|
||||
jmp LOCAL(after_BPB)
|
||||
#else
|
||||
/*
|
||||
* This space is for the BIOS parameter block!!!! Don't change
|
||||
* the first jump, nor start the code anywhere but right after
|
||||
* this area.
|
||||
*/
|
||||
|
||||
.org GRUB_BOOT_MACHINE_BPB_START
|
||||
.org 4
|
||||
#endif
|
||||
#ifdef HYBRID_BOOT
|
||||
floppy
|
||||
#else
|
||||
scratch
|
||||
#endif
|
||||
|
||||
.org GRUB_BOOT_MACHINE_BPB_END
|
||||
/*
|
||||
* End of BIOS parameter block.
|
||||
*/
|
||||
|
||||
LOCAL(kernel_address):
|
||||
.word GRUB_BOOT_MACHINE_KERNEL_ADDR
|
||||
|
||||
#ifndef HYBRID_BOOT
|
||||
.org GRUB_BOOT_MACHINE_KERNEL_SECTOR
|
||||
LOCAL(kernel_sector):
|
||||
.long 1
|
||||
LOCAL(kernel_sector_high):
|
||||
.long 0
|
||||
#endif
|
||||
|
||||
.org 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).
|
||||
*/
|
||||
.org GRUB_BOOT_MACHINE_DRIVE_CHECK
|
||||
boot_drive_check:
|
||||
jmp 3f /* grub-setup may overwrite this jump */
|
||||
testb $0x80, %dl
|
||||
jz 2f
|
||||
3:
|
||||
/* Ignore %dl different from 0-0x0f and 0x80-0x8f. */
|
||||
testb $0x70, %dl
|
||||
jz 1f
|
||||
2:
|
||||
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)
|
||||
|
||||
LOCAL(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 LOCAL(kernel_sector), %ebx
|
||||
movl %ebx, 8(%si)
|
||||
movl LOCAL(kernel_sector_high), %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)
|
||||
|
||||
popw %dx
|
||||
/*
|
||||
* The call failed, so maybe use the floppy probe instead.
|
||||
*/
|
||||
testb %dl, %dl
|
||||
jnb 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 LOCAL(kernel_sector_high), %eax
|
||||
|
||||
orl %eax, %eax
|
||||
jnz LOCAL(geometry_error)
|
||||
|
||||
/* load logical sector start (bottom half) */
|
||||
movl LOCAL(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 *(LOCAL(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)
|
||||
|
||||
ventoy_uuid: .ascii "XXXXXXXXXXXXXXXX"
|
||||
notification_string: .asciz "GR"
|
||||
geometry_error_string: .asciz "Ge"
|
||||
hd_probe_error_string: .asciz "HD"
|
||||
read_error_string: .asciz "Rd"
|
||||
general_error_string: .asciz " Er\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.
|
||||
*/
|
||||
|
||||
#ifdef HYBRID_BOOT
|
||||
.org 0x1b0
|
||||
LOCAL(kernel_sector):
|
||||
.long 1
|
||||
LOCAL(kernel_sector_high):
|
||||
.long 0
|
||||
#endif
|
||||
.org 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?
|
||||
*/
|
||||
|
||||
.org GRUB_BOOT_MACHINE_PART_START
|
||||
|
||||
#ifndef HYBRID_BOOT
|
||||
floppy
|
||||
#else
|
||||
scratch
|
||||
#endif
|
||||
|
||||
.org GRUB_BOOT_MACHINE_PART_END
|
||||
|
||||
/* the last 2 bytes in the sector 0 contain the signature */
|
||||
.word GRUB_BOOT_MACHINE_SIGNATURE
|
162
GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c
Normal file
162
GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* 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>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
/* Context for grub_cmd_blocklist. */
|
||||
struct blocklist_ctx
|
||||
{
|
||||
unsigned long start_sector;
|
||||
unsigned num_sectors;
|
||||
int num_entries;
|
||||
grub_disk_addr_t part_start;
|
||||
};
|
||||
|
||||
/* Helper for grub_cmd_blocklist. */
|
||||
static void
|
||||
print_blocklist (grub_disk_addr_t sector, unsigned num,
|
||||
unsigned offset, unsigned length, struct blocklist_ctx *ctx)
|
||||
{
|
||||
if (ctx->num_entries++)
|
||||
grub_printf (",");
|
||||
|
||||
grub_printf ("%llu", (unsigned long long) (sector - ctx->part_start));
|
||||
if (num > 0)
|
||||
grub_printf ("+%u", num);
|
||||
if (offset != 0 || length != 0)
|
||||
grub_printf ("[%u-%u]", offset, offset + length);
|
||||
}
|
||||
|
||||
/* Helper for grub_cmd_blocklist. */
|
||||
static void
|
||||
read_blocklist (grub_disk_addr_t sector, unsigned offset, unsigned length,
|
||||
void *data)
|
||||
{
|
||||
struct blocklist_ctx *ctx = data;
|
||||
|
||||
if (ctx->num_sectors > 0)
|
||||
{
|
||||
if (ctx->start_sector + ctx->num_sectors == sector
|
||||
&& offset == 0 && length >= GRUB_DISK_SECTOR_SIZE)
|
||||
{
|
||||
ctx->num_sectors += length >> GRUB_DISK_SECTOR_BITS;
|
||||
sector += length >> GRUB_DISK_SECTOR_BITS;
|
||||
length &= (GRUB_DISK_SECTOR_SIZE - 1);
|
||||
}
|
||||
|
||||
if (!length)
|
||||
return;
|
||||
print_blocklist (ctx->start_sector, ctx->num_sectors, 0, 0, ctx);
|
||||
ctx->num_sectors = 0;
|
||||
}
|
||||
|
||||
if (offset)
|
||||
{
|
||||
unsigned l = length + offset;
|
||||
l &= (GRUB_DISK_SECTOR_SIZE - 1);
|
||||
l -= offset;
|
||||
print_blocklist (sector, 0, offset, l, ctx);
|
||||
length -= l;
|
||||
sector++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (!length)
|
||||
return;
|
||||
|
||||
if (length & (GRUB_DISK_SECTOR_SIZE - 1))
|
||||
{
|
||||
if (length >> GRUB_DISK_SECTOR_BITS)
|
||||
{
|
||||
print_blocklist (sector, length >> GRUB_DISK_SECTOR_BITS, 0, 0, ctx);
|
||||
sector += length >> GRUB_DISK_SECTOR_BITS;
|
||||
}
|
||||
print_blocklist (sector, 0, 0, length & (GRUB_DISK_SECTOR_SIZE - 1), ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->start_sector = sector;
|
||||
ctx->num_sectors = length >> GRUB_DISK_SECTOR_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
struct blocklist_ctx ctx = {
|
||||
.start_sector = 0,
|
||||
.num_sectors = 0,
|
||||
.num_entries = 0,
|
||||
.part_start = 0
|
||||
};
|
||||
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
|
||||
file = grub_file_open (args[0], GRUB_FILE_TYPE_PRINT_BLOCKLIST
|
||||
| GRUB_FILE_TYPE_NO_DECOMPRESS);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
if (! file->device->disk)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"this command is available only for disk devices");
|
||||
|
||||
ctx.part_start = grub_partition_get_start (file->device->disk->partition);
|
||||
|
||||
file->read_hook = read_blocklist;
|
||||
file->read_hook_data = &ctx;
|
||||
|
||||
while (grub_file_read (file, buf, sizeof (buf)) > 0)
|
||||
;
|
||||
|
||||
if (ctx.num_sectors > 0)
|
||||
print_blocklist (ctx.start_sector, ctx.num_sectors, 0, 0, &ctx);
|
||||
|
||||
grub_printf("\nentry number:%d \n", ctx.num_entries);
|
||||
|
||||
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);
|
||||
}
|
764
GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
Normal file
764
GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
Normal file
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
* 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/kernel.h>
|
||||
#include <grub/machine/memory.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>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static int cd_drive = 0;
|
||||
static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap);
|
||||
|
||||
static int grub_biosdisk_get_num_floppies (void)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
int drive;
|
||||
|
||||
/* reset the disk system first */
|
||||
regs.eax = 0;
|
||||
regs.edx = 0;
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
|
||||
for (drive = 0; drive < 2; drive++)
|
||||
{
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT | GRUB_CPU_INT_FLAGS_CARRY;
|
||||
regs.edx = drive;
|
||||
|
||||
/* call GET DISK TYPE */
|
||||
regs.eax = 0x1500;
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
|
||||
break;
|
||||
|
||||
/* check if this drive exists */
|
||||
if (!(regs.eax & 0x300))
|
||||
break;
|
||||
}
|
||||
|
||||
return drive;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
|
||||
* is passed for disk address packet. If an error occurs, return
|
||||
* non-zero, otherwise zero.
|
||||
*/
|
||||
|
||||
static int
|
||||
grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
regs.eax = ah << 8;
|
||||
/* compute the address of disk_address_packet */
|
||||
regs.ds = (((grub_addr_t) dap) & 0xffff0000) >> 4;
|
||||
regs.esi = (((grub_addr_t) dap) & 0xffff);
|
||||
regs.edx = drive;
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
return (regs.eax >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
|
||||
* NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
|
||||
* return non-zero, otherwise zero.
|
||||
*/
|
||||
static int
|
||||
grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
|
||||
int soff, int nsec, int segment)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
/* Try 3 times. */
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
/* set up CHS information */
|
||||
/* set %ch to low eight bits of cylinder */
|
||||
regs.ecx = (coff << 8) & 0xff00;
|
||||
/* set bits 6-7 of %cl to high two bits of cylinder */
|
||||
regs.ecx |= (coff >> 2) & 0xc0;
|
||||
/* set bits 0-5 of %cl to sector */
|
||||
regs.ecx |= soff & 0x3f;
|
||||
|
||||
/* set %dh to head and %dl to drive */
|
||||
regs.edx = (drive & 0xff) | ((hoff << 8) & 0xff00);
|
||||
/* set %ah to AH */
|
||||
regs.eax = (ah << 8) & 0xff00;
|
||||
/* set %al to NSEC */
|
||||
regs.eax |= nsec & 0xff;
|
||||
|
||||
regs.ebx = 0;
|
||||
regs.es = segment;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
/* check if successful */
|
||||
if (!(regs.flags & GRUB_CPU_INT_FLAGS_CARRY))
|
||||
return 0;
|
||||
|
||||
/* save return value */
|
||||
ret = regs.eax >> 8;
|
||||
|
||||
/* if fail, reset the disk system */
|
||||
regs.eax = 0;
|
||||
regs.edx = (drive & 0xff);
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if LBA is supported for DRIVE. If it is supported, then return
|
||||
* the major version of extensions, otherwise zero.
|
||||
*/
|
||||
static int
|
||||
grub_biosdisk_check_int13_extensions (int drive)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
regs.edx = drive & 0xff;
|
||||
regs.eax = 0x4100;
|
||||
regs.ebx = 0x55aa;
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
|
||||
if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
|
||||
return 0;
|
||||
|
||||
if ((regs.ebx & 0xffff) != 0xaa55)
|
||||
return 0;
|
||||
|
||||
/* check if AH=0x42 is supported */
|
||||
if (!(regs.ecx & 1))
|
||||
return 0;
|
||||
|
||||
return (regs.eax >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
|
||||
* error occurs, then return non-zero, otherwise zero.
|
||||
*/
|
||||
static int
|
||||
grub_biosdisk_get_diskinfo_standard (int drive,
|
||||
unsigned long *cylinders,
|
||||
unsigned long *heads,
|
||||
unsigned long *sectors)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
regs.eax = 0x0800;
|
||||
regs.edx = drive & 0xff;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
|
||||
/* Check if unsuccessful. Ignore return value if carry isn't set to
|
||||
workaround some buggy BIOSes. */
|
||||
if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0))
|
||||
return (regs.eax & 0xff00) >> 8;
|
||||
|
||||
/* bogus BIOSes may not return an error number */
|
||||
/* 0 sectors means no disk */
|
||||
if (!(regs.ecx & 0x3f))
|
||||
/* XXX 0x60 is one of the unused error numbers */
|
||||
return 0x60;
|
||||
|
||||
/* the number of heads is counted from zero */
|
||||
*heads = ((regs.edx >> 8) & 0xff) + 1;
|
||||
*cylinders = (((regs.ecx >> 8) & 0xff) | ((regs.ecx << 2) & 0x0300)) + 1;
|
||||
*sectors = regs.ecx & 0x3f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_biosdisk_get_diskinfo_real (int drive, void *drp, grub_uint16_t ax)
|
||||
{
|
||||
struct grub_bios_int_registers regs;
|
||||
|
||||
regs.eax = ax;
|
||||
|
||||
/* compute the address of drive parameters */
|
||||
regs.esi = ((grub_addr_t) drp) & 0xf;
|
||||
regs.ds = ((grub_addr_t) drp) >> 4;
|
||||
regs.edx = drive & 0xff;
|
||||
|
||||
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
|
||||
grub_bios_interrupt (0x13, ®s);
|
||||
|
||||
/* Check if unsuccessful. Ignore return value if carry isn't set to
|
||||
workaround some buggy BIOSes. */
|
||||
if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0))
|
||||
return (regs.eax & 0xff00) >> 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the cdrom information of DRIVE in CDRP. If an error occurs,
|
||||
* then return non-zero, otherwise zero.
|
||||
*/
|
||||
static int
|
||||
grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
|
||||
{
|
||||
return grub_biosdisk_get_diskinfo_real (drive, cdrp, 0x4b01);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the geometry of DRIVE in a drive parameters, DRP. If an error
|
||||
* occurs, then return non-zero, otherwise zero.
|
||||
*/
|
||||
static int
|
||||
grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
|
||||
{
|
||||
return grub_biosdisk_get_diskinfo_real (drive, drp, 0x4800);
|
||||
}
|
||||
|
||||
static int
|
||||
grub_biosdisk_get_drive (const char *name)
|
||||
{
|
||||
unsigned long drive;
|
||||
|
||||
if (name[0] == '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 (grub_disk_dev_iterate_hook_t hook, void *hook_data,
|
||||
int drive)
|
||||
{
|
||||
char name[10];
|
||||
|
||||
if (cd_drive && drive == cd_drive)
|
||||
return hook ("cd", hook_data);
|
||||
|
||||
grub_snprintf (name, sizeof (name),
|
||||
(drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
|
||||
return hook (name, hook_data);
|
||||
}
|
||||
|
||||
static int
|
||||
grub_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
|
||||
grub_disk_pull_t pull)
|
||||
{
|
||||
int num_floppies;
|
||||
int drive;
|
||||
|
||||
/* For hard disks, attempt to read the MBR. */
|
||||
switch (pull)
|
||||
{
|
||||
case GRUB_DISK_PULL_NONE:
|
||||
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, hook_data, drive))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case GRUB_DISK_PULL_REMOVABLE:
|
||||
if (cd_drive)
|
||||
{
|
||||
if (grub_biosdisk_call_hook (hook, hook_data, 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, hook_data, drive))
|
||||
return 1;
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct ventoy_part_table
|
||||
{
|
||||
grub_uint8_t Active; // 0x00 0x80
|
||||
|
||||
grub_uint8_t StartHead;
|
||||
grub_uint16_t StartSector : 6;
|
||||
grub_uint16_t StartCylinder : 10;
|
||||
|
||||
grub_uint8_t FsFlag;
|
||||
|
||||
grub_uint8_t EndHead;
|
||||
grub_uint16_t EndSector : 6;
|
||||
grub_uint16_t EndCylinder : 10;
|
||||
|
||||
grub_uint32_t StartSectorId;
|
||||
grub_uint32_t SectorCount;
|
||||
}ventoy_part_table;
|
||||
|
||||
typedef struct ventoy_mbr_head
|
||||
{
|
||||
grub_uint8_t BootCode[446];
|
||||
ventoy_part_table PartTbl[4];
|
||||
grub_uint8_t Byte55;
|
||||
grub_uint8_t ByteAA;
|
||||
}ventoy_mbr_head;
|
||||
#pragma pack()
|
||||
|
||||
static grub_err_t
|
||||
grub_biosdisk_rw (int cmd, grub_disk_t disk,
|
||||
grub_disk_addr_t sector, grub_size_t size,
|
||||
unsigned segment);
|
||||
|
||||
static int ventoy_is_mbr_match(ventoy_mbr_head *head)
|
||||
{
|
||||
grub_uint32_t PartStartSector;
|
||||
|
||||
if (head->Byte55 != 0x55 || head->ByteAA != 0xAA) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (head->PartTbl[2].SectorCount > 0 || head->PartTbl[3].SectorCount > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (head->PartTbl[0].StartSectorId != 2048) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (head->PartTbl[1].Active != 0x80 || head->PartTbl[1].FsFlag != 0xEF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PartStartSector = head->PartTbl[0].StartSectorId + head->PartTbl[0].SectorCount;
|
||||
|
||||
if (head->PartTbl[1].StartSectorId != PartStartSector || head->PartTbl[1].SectorCount != 65536) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 = 8;
|
||||
disk->log_sector_size = 11;
|
||||
/* TODO: get the correct size. */
|
||||
total_sectors = GRUB_DISK_SIZE_UNKNOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* HDD */
|
||||
int version;
|
||||
|
||||
disk->log_sector_size = 9;
|
||||
|
||||
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 = ((grub_uint64_t) drp->cylinders)
|
||||
* drp->heads * drp->sectors;
|
||||
if (drp->bytes_per_sector
|
||||
&& !(drp->bytes_per_sector & (drp->bytes_per_sector - 1))
|
||||
&& drp->bytes_per_sector >= 512
|
||||
&& drp->bytes_per_sector <= 16384)
|
||||
{
|
||||
for (disk->log_sector_size = 0;
|
||||
(1 << disk->log_sector_size) < drp->bytes_per_sector;
|
||||
disk->log_sector_size++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (data->sectors == 0)
|
||||
data->sectors = 63;
|
||||
if (data->heads == 0)
|
||||
data->heads = 255;
|
||||
|
||||
if (! total_sectors)
|
||||
total_sectors = ((grub_uint64_t) data->cylinders)
|
||||
* data->heads * data->sectors;
|
||||
}
|
||||
|
||||
disk->total_sectors = total_sectors;
|
||||
/* Limit the max to 0x7f because of Phoenix EDD. */
|
||||
disk->max_agglomerate = 0x7f >> GRUB_DISK_CACHE_BITS;
|
||||
COMPILE_TIME_ASSERT ((0x7f >> GRUB_DISK_CACHE_BITS
|
||||
<< (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS))
|
||||
+ sizeof (struct grub_biosdisk_dap)
|
||||
< GRUB_MEMORY_MACHINE_SCRATCH_SIZE);
|
||||
|
||||
disk->data = data;
|
||||
|
||||
//fixup some buggy bios
|
||||
if (total_sectors > (16434495 - 2097152) && total_sectors < (16434495 + 2097152) &&
|
||||
(data->flags & GRUB_BIOSDISK_FLAG_LBA) > 0 && (data->flags & GRUB_BIOSDISK_FLAG_CDROM) == 0) {
|
||||
if (grub_biosdisk_rw(0, disk, 0, 1, GRUB_MEMORY_MACHINE_SCRATCH_SEG) == 0) {
|
||||
ventoy_mbr_head *mbr = (ventoy_mbr_head *)GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
|
||||
if (ventoy_is_mbr_match(mbr)) {
|
||||
total_sectors = mbr->PartTbl[1].StartSectorId + mbr->PartTbl[1].SectorCount + 1;
|
||||
if (disk->total_sectors < total_sectors) {
|
||||
disk->total_sectors = total_sectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* VirtualBox fails with sectors above 2T on CDs.
|
||||
Since even BD-ROMS are never that big anyway, return error. */
|
||||
if ((data->flags & GRUB_BIOSDISK_FLAG_CDROM)
|
||||
&& (sector >> 32))
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
N_("attempt to read or write outside of disk `%s'"),
|
||||
disk->name);
|
||||
|
||||
if (data->flags & GRUB_BIOSDISK_FLAG_LBA)
|
||||
{
|
||||
struct grub_biosdisk_dap *dap;
|
||||
|
||||
dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR
|
||||
+ (data->sectors
|
||||
<< disk->log_sector_size));
|
||||
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, N_("cannot write to CD-ROM"));
|
||||
|
||||
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, N_("failure reading sector 0x%llx "
|
||||
"from `%s'"),
|
||||
(unsigned long long) sector,
|
||||
disk->name);
|
||||
}
|
||||
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,
|
||||
N_("attempt to read or write outside of disk `%s'"),
|
||||
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,
|
||||
N_("attempt to read or write outside of disk `%s'"),
|
||||
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, N_("failure reading sector 0x%llx "
|
||||
"from `%s'"),
|
||||
(unsigned long long) sector,
|
||||
disk->name);
|
||||
case GRUB_BIOSDISK_WRITE:
|
||||
return grub_error (GRUB_ERR_WRITE_ERROR, N_("failure writing sector 0x%llx "
|
||||
"to `%s'"),
|
||||
(unsigned long long) sector,
|
||||
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_t disk, grub_disk_addr_t sector)
|
||||
{
|
||||
grub_size_t size;
|
||||
grub_uint64_t offset;
|
||||
struct grub_biosdisk_data *data = disk->data;
|
||||
grub_uint32_t sectors = data->sectors;
|
||||
|
||||
/* OFFSET = SECTOR % SECTORS */
|
||||
grub_divmod64 (sector, sectors, &offset);
|
||||
|
||||
size = sectors - offset;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
grub_size_t len;
|
||||
|
||||
len = get_safe_sectors (disk, sector);
|
||||
|
||||
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,
|
||||
len << disk->log_sector_size);
|
||||
|
||||
buf += len << disk->log_sector_size;
|
||||
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, N_("cannot write to CD-ROM"));
|
||||
|
||||
while (size)
|
||||
{
|
||||
grub_size_t len;
|
||||
|
||||
len = get_safe_sectors (disk, sector);
|
||||
if (len > size)
|
||||
len = size;
|
||||
|
||||
grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf,
|
||||
len << disk->log_sector_size);
|
||||
|
||||
if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len,
|
||||
GRUB_MEMORY_MACHINE_SCRATCH_SEG))
|
||||
return grub_errno;
|
||||
|
||||
buf += len << disk->log_sector_size;
|
||||
sector += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_biosdisk_dev =
|
||||
{
|
||||
.name = "biosdisk",
|
||||
.id = GRUB_DISK_DEVICE_BIOSDISK_ID,
|
||||
.disk_iterate = grub_biosdisk_iterate,
|
||||
.disk_open = grub_biosdisk_open,
|
||||
.disk_close = grub_biosdisk_close,
|
||||
.disk_read = grub_biosdisk_read,
|
||||
.disk_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;
|
||||
grub_uint8_t boot_drive;
|
||||
|
||||
if (grub_disk_firmware_is_tainted)
|
||||
{
|
||||
grub_puts_ (N_("Native disk drivers are in use. "
|
||||
"Refusing to use firmware disk interface."));
|
||||
return;
|
||||
}
|
||||
grub_disk_firmware_fini = grub_disk_biosdisk_fini;
|
||||
|
||||
grub_memset (cdrp, 0, sizeof (*cdrp));
|
||||
cdrp->size = sizeof (*cdrp);
|
||||
cdrp->media_type = 0xFF;
|
||||
boot_drive = (grub_boot_device >> 24);
|
||||
if ((! grub_biosdisk_get_cdinfo_int13_extensions (boot_drive, cdrp))
|
||||
&& ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK)
|
||||
== GRUB_BIOSDISK_CDTYPE_NO_EMUL))
|
||||
cd_drive = cdrp->drive_no;
|
||||
/* Since diskboot.S rejects devices over 0x90 it must be a CD booted with
|
||||
cdboot.S
|
||||
*/
|
||||
if (boot_drive >= 0x90)
|
||||
cd_drive = boot_drive;
|
||||
|
||||
grub_disk_dev_register (&grub_biosdisk_dev);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(biosdisk)
|
||||
{
|
||||
grub_disk_biosdisk_fini ();
|
||||
}
|
1100
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c
Normal file
1100
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c
Normal file
File diff suppressed because it is too large
Load Diff
1403
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c
Normal file
1403
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c
Normal file
File diff suppressed because it is too large
Load Diff
1149
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c
Normal file
1149
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c
Normal file
File diff suppressed because it is too large
Load Diff
1239
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c
Normal file
1239
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c
Normal file
File diff suppressed because it is too large
Load Diff
1439
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c
Normal file
1439
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c
Normal file
File diff suppressed because it is too large
Load Diff
1164
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c
Normal file
1164
GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c
Normal file
File diff suppressed because it is too large
Load Diff
161
GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c
Normal file
161
GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/* gfxmenu.c - Graphical menu interface controller. */
|
||||
/*
|
||||
* 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/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/gfxterm.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/menu.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/gfxmenu_model.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
extern int g_ventoy_menu_refresh;
|
||||
|
||||
static grub_gfxmenu_view_t cached_view;
|
||||
|
||||
static void
|
||||
grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
/* FIXME: Previously 't' changed to text menu is it necessary? */
|
||||
static grub_err_t
|
||||
grub_gfxmenu_try (int entry, grub_menu_t menu, int nested)
|
||||
{
|
||||
int force_refresh = 0;
|
||||
grub_gfxmenu_view_t view = NULL;
|
||||
const char *theme_path;
|
||||
char *full_theme_path = 0;
|
||||
struct grub_menu_viewer *instance;
|
||||
grub_err_t err;
|
||||
struct grub_video_mode_info mode_info;
|
||||
|
||||
theme_path = grub_env_get ("theme");
|
||||
if (! theme_path)
|
||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
|
||||
"theme");
|
||||
|
||||
err = grub_video_get_info (&mode_info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
instance = grub_zalloc (sizeof (*instance));
|
||||
if (!instance)
|
||||
return grub_errno;
|
||||
|
||||
if (theme_path[0] != '/' && theme_path[0] != '(')
|
||||
{
|
||||
const char *prefix;
|
||||
prefix = grub_env_get ("prefix");
|
||||
full_theme_path = grub_xasprintf ("%s/themes/%s",
|
||||
prefix,
|
||||
theme_path);
|
||||
}
|
||||
|
||||
if (g_ventoy_menu_refresh)
|
||||
{
|
||||
g_ventoy_menu_refresh = 0;
|
||||
force_refresh = 1;
|
||||
}
|
||||
|
||||
if (force_refresh ||
|
||||
!cached_view || grub_strcmp (cached_view->theme_path,
|
||||
full_theme_path ? : theme_path) != 0
|
||||
|| cached_view->screen.width != mode_info.width
|
||||
|| cached_view->screen.height != mode_info.height)
|
||||
{
|
||||
grub_gfxmenu_view_destroy (cached_view);
|
||||
/* Create the view. */
|
||||
cached_view = grub_gfxmenu_view_new (full_theme_path ? : theme_path,
|
||||
mode_info.width,
|
||||
mode_info.height);
|
||||
}
|
||||
grub_free (full_theme_path);
|
||||
|
||||
if (! cached_view)
|
||||
{
|
||||
grub_free (instance);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
view = cached_view;
|
||||
|
||||
view->double_repaint = (mode_info.mode_type
|
||||
& GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED)
|
||||
&& !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
|
||||
view->selected = entry;
|
||||
view->menu = menu;
|
||||
view->nested = nested;
|
||||
view->first_timeout = -1;
|
||||
|
||||
grub_video_set_viewport (0, 0, mode_info.width, mode_info.height);
|
||||
if (view->double_repaint)
|
||||
{
|
||||
grub_video_swap_buffers ();
|
||||
grub_video_set_viewport (0, 0, mode_info.width, mode_info.height);
|
||||
}
|
||||
|
||||
grub_gfxmenu_view_draw (view);
|
||||
|
||||
instance->data = view;
|
||||
instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry;
|
||||
instance->fini = grub_gfxmenu_viewer_fini;
|
||||
instance->print_timeout = grub_gfxmenu_print_timeout;
|
||||
instance->clear_timeout = grub_gfxmenu_clear_timeout;
|
||||
|
||||
grub_menu_register_viewer (instance);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT (gfxmenu)
|
||||
{
|
||||
struct grub_term_output *term;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
if (grub_gfxmenu_try_hook && term->fullscreen)
|
||||
{
|
||||
term->fullscreen ();
|
||||
break;
|
||||
}
|
||||
|
||||
grub_gfxmenu_try_hook = grub_gfxmenu_try;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (gfxmenu)
|
||||
{
|
||||
grub_gfxmenu_view_destroy (cached_view);
|
||||
grub_gfxmenu_try_hook = NULL;
|
||||
}
|
295
GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c
Normal file
295
GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/* gui_label.c - GUI component to display a line of text. */
|
||||
/*
|
||||
* 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/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/font.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/color.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
extern int g_ventoy_memdisk_mode;
|
||||
extern int g_ventoy_iso_raw;
|
||||
extern int g_ventoy_iso_uefi_drv;
|
||||
|
||||
static const char *align_options[] =
|
||||
{
|
||||
"left",
|
||||
"center",
|
||||
"right",
|
||||
0
|
||||
};
|
||||
|
||||
enum align_mode {
|
||||
align_left,
|
||||
align_center,
|
||||
align_right
|
||||
};
|
||||
|
||||
struct grub_gui_label
|
||||
{
|
||||
struct grub_gui_component comp;
|
||||
|
||||
grub_gui_container_t parent;
|
||||
grub_video_rect_t bounds;
|
||||
char *id;
|
||||
int visible;
|
||||
char *text;
|
||||
char *template;
|
||||
grub_font_t font;
|
||||
grub_video_rgba_color_t color;
|
||||
int value;
|
||||
enum align_mode align;
|
||||
};
|
||||
|
||||
typedef struct grub_gui_label *grub_gui_label_t;
|
||||
|
||||
static void
|
||||
label_destroy (void *vself)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
|
||||
grub_free (self->text);
|
||||
grub_free (self->template);
|
||||
grub_free (self);
|
||||
}
|
||||
|
||||
static const char *
|
||||
label_get_id (void *vself)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
return self->id;
|
||||
}
|
||||
|
||||
static int
|
||||
label_is_instance (void *vself __attribute__((unused)), const char *type)
|
||||
{
|
||||
return grub_strcmp (type, "component") == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
label_paint (void *vself, const grub_video_rect_t *region)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
|
||||
if (! self->visible)
|
||||
return;
|
||||
|
||||
if (!grub_video_have_common_points (region, &self->bounds))
|
||||
return;
|
||||
|
||||
/* Calculate the starting x coordinate. */
|
||||
int left_x;
|
||||
if (self->align == align_left)
|
||||
left_x = 0;
|
||||
else if (self->align == align_center)
|
||||
left_x = (self->bounds.width
|
||||
- grub_font_get_string_width (self->font, self->text)) / 2;
|
||||
else if (self->align == align_right)
|
||||
left_x = (self->bounds.width
|
||||
- grub_font_get_string_width (self->font, self->text));
|
||||
else
|
||||
return; /* Invalid alignment. */
|
||||
|
||||
if (left_x < 0 || left_x > (int) self->bounds.width)
|
||||
left_x = 0;
|
||||
|
||||
grub_video_rect_t vpsave;
|
||||
grub_gui_set_viewport (&self->bounds, &vpsave);
|
||||
grub_font_draw_string (self->text,
|
||||
self->font,
|
||||
grub_video_map_rgba_color (self->color),
|
||||
left_x,
|
||||
grub_font_get_ascent (self->font));
|
||||
grub_gui_restore_viewport (&vpsave);
|
||||
}
|
||||
|
||||
static void
|
||||
label_set_parent (void *vself, grub_gui_container_t parent)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
self->parent = parent;
|
||||
}
|
||||
|
||||
static grub_gui_container_t
|
||||
label_get_parent (void *vself)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
return self->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
label_set_bounds (void *vself, const grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
self->bounds = *bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
label_get_bounds (void *vself, grub_video_rect_t *bounds)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
*bounds = self->bounds;
|
||||
}
|
||||
|
||||
static void
|
||||
label_get_minimal_size (void *vself, unsigned *width, unsigned *height)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
*width = grub_font_get_string_width (self->font, self->text);
|
||||
*height = (grub_font_get_ascent (self->font)
|
||||
+ grub_font_get_descent (self->font));
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
|
||||
static void
|
||||
label_set_state (void *vself, int visible, int start __attribute__ ((unused)),
|
||||
int current, int end __attribute__ ((unused)))
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
self->value = -current;
|
||||
self->visible = visible;
|
||||
grub_free (self->text);
|
||||
self->text = grub_xasprintf (self->template ? : "%d", self->value);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
label_set_property (void *vself, const char *name, const char *value)
|
||||
{
|
||||
grub_gui_label_t self = vself;
|
||||
if (grub_strcmp (name, "text") == 0)
|
||||
{
|
||||
grub_free (self->text);
|
||||
grub_free (self->template);
|
||||
if (! value)
|
||||
{
|
||||
self->template = NULL;
|
||||
self->text = grub_strdup ("");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (grub_strcmp (value, "@KEYMAP_LONG@") == 0)
|
||||
value = _("Press enter to boot the selected OS, "
|
||||
"`e' to edit the commands before booting "
|
||||
"or `c' for a command-line. ESC to return previous menu.");
|
||||
else if (grub_strcmp (value, "@KEYMAP_MIDDLE@") == 0)
|
||||
value = _("Press enter to boot the selected OS, "
|
||||
"`e' to edit the commands before booting "
|
||||
"or `c' for a command-line.");
|
||||
else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0)
|
||||
value = _("enter: boot, `e': options, `c': cmd-line");
|
||||
/* FIXME: Add more templates here if needed. */
|
||||
|
||||
else if (grub_strcmp (value, "@VTOY_MEM_DISK@") == 0) {
|
||||
value = g_ventoy_memdisk_mode ? grub_env_get("VTOY_MEM_DISK_STR") : " ";
|
||||
}
|
||||
else if (grub_strcmp (value, "@VTOY_ISO_RAW@") == 0) {
|
||||
value = g_ventoy_iso_raw ? grub_env_get("VTOY_ISO_RAW_STR") : " ";
|
||||
}
|
||||
else if (grub_strcmp (value, "@VTOY_ISO_UEFI_DRV@") == 0) {
|
||||
value = g_ventoy_iso_uefi_drv ? grub_env_get("VTOY_ISO_UEFI_DRV_STR") : " ";
|
||||
}
|
||||
else if (grub_strcmp (value, "@VTOY_HOTKEY_TIP@") == 0) {
|
||||
value = grub_env_get("VTOY_HOTKEY_TIP");
|
||||
if (value == NULL) {
|
||||
value = _(" ");
|
||||
}
|
||||
}
|
||||
|
||||
self->template = grub_strdup (value);
|
||||
self->text = grub_xasprintf (value, self->value);
|
||||
}
|
||||
}
|
||||
else if (grub_strcmp (name, "font") == 0)
|
||||
{
|
||||
self->font = grub_font_get (value);
|
||||
}
|
||||
else if (grub_strcmp (name, "color") == 0)
|
||||
{
|
||||
grub_video_parse_color (value, &self->color);
|
||||
}
|
||||
else if (grub_strcmp (name, "align") == 0)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; align_options[i]; i++)
|
||||
{
|
||||
if (grub_strcmp (align_options[i], value) == 0)
|
||||
{
|
||||
self->align = i; /* Set the alignment mode. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grub_strcmp (name, "visible") == 0)
|
||||
{
|
||||
self->visible = grub_strcmp (value, "false") != 0;
|
||||
}
|
||||
else if (grub_strcmp (name, "id") == 0)
|
||||
{
|
||||
grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self);
|
||||
grub_free (self->id);
|
||||
if (value)
|
||||
self->id = grub_strdup (value);
|
||||
else
|
||||
self->id = 0;
|
||||
if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID)
|
||||
== 0)
|
||||
grub_gfxmenu_timeout_register ((grub_gui_component_t) self,
|
||||
label_set_state);
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic error "-Wformat-nonliteral"
|
||||
|
||||
static struct grub_gui_component_ops label_ops =
|
||||
{
|
||||
.destroy = label_destroy,
|
||||
.get_id = label_get_id,
|
||||
.is_instance = label_is_instance,
|
||||
.paint = label_paint,
|
||||
.set_parent = label_set_parent,
|
||||
.get_parent = label_get_parent,
|
||||
.set_bounds = label_set_bounds,
|
||||
.get_bounds = label_get_bounds,
|
||||
.get_minimal_size = label_get_minimal_size,
|
||||
.set_property = label_set_property
|
||||
};
|
||||
|
||||
grub_gui_component_t
|
||||
grub_gui_label_new (void)
|
||||
{
|
||||
grub_gui_label_t label;
|
||||
label = grub_zalloc (sizeof (*label));
|
||||
if (! label)
|
||||
return 0;
|
||||
label->comp.ops = &label_ops;
|
||||
label->visible = 1;
|
||||
label->text = grub_strdup ("");
|
||||
label->font = grub_font_get ("Unknown Regular 16");
|
||||
label->color.red = 0;
|
||||
label->color.green = 0;
|
||||
label->color.blue = 0;
|
||||
label->color.alpha = 255;
|
||||
label->align = align_left;
|
||||
return (grub_gui_component_t) label;
|
||||
}
|
600
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c
Normal file
600
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c
Normal file
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/disk.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/ventoy.h>
|
||||
|
||||
#define GRUB_CACHE_TIMEOUT 2
|
||||
|
||||
/* The last time the disk was used. */
|
||||
static grub_uint64_t grub_last_time = 0;
|
||||
|
||||
struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM];
|
||||
|
||||
void (*grub_disk_firmware_fini) (void);
|
||||
int grub_disk_firmware_is_tainted;
|
||||
|
||||
#if DISK_CACHE_STATS
|
||||
static unsigned long grub_disk_cache_hits;
|
||||
static unsigned long grub_disk_cache_misses;
|
||||
|
||||
void
|
||||
grub_disk_cache_get_performance (unsigned long *hits, unsigned long *misses)
|
||||
{
|
||||
*hits = grub_disk_cache_hits;
|
||||
*misses = grub_disk_cache_misses;
|
||||
}
|
||||
#endif
|
||||
|
||||
grub_err_t (*grub_disk_write_weak) (grub_disk_t disk,
|
||||
grub_disk_addr_t sector,
|
||||
grub_off_t offset,
|
||||
grub_size_t size,
|
||||
const void *buf);
|
||||
#include "disk_common.c"
|
||||
|
||||
void
|
||||
grub_disk_cache_invalidate_all (void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < GRUB_DISK_CACHE_NUM; i++)
|
||||
{
|
||||
struct grub_disk_cache *cache = grub_disk_cache_table + i;
|
||||
|
||||
if (cache->data && ! cache->lock)
|
||||
{
|
||||
grub_free (cache->data);
|
||||
cache->data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id,
|
||||
grub_disk_addr_t sector)
|
||||
{
|
||||
struct grub_disk_cache *cache;
|
||||
unsigned cache_index;
|
||||
|
||||
cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
|
||||
cache = grub_disk_cache_table + cache_index;
|
||||
|
||||
if (cache->dev_id == dev_id && cache->disk_id == disk_id
|
||||
&& cache->sector == sector)
|
||||
{
|
||||
cache->lock = 1;
|
||||
#if DISK_CACHE_STATS
|
||||
grub_disk_cache_hits++;
|
||||
#endif
|
||||
return cache->data;
|
||||
}
|
||||
|
||||
#if DISK_CACHE_STATS
|
||||
grub_disk_cache_misses++;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_disk_cache_unlock (unsigned long dev_id, unsigned long disk_id,
|
||||
grub_disk_addr_t sector)
|
||||
{
|
||||
struct grub_disk_cache *cache;
|
||||
unsigned cache_index;
|
||||
|
||||
cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
|
||||
cache = grub_disk_cache_table + cache_index;
|
||||
|
||||
if (cache->dev_id == dev_id && cache->disk_id == disk_id
|
||||
&& cache->sector == sector)
|
||||
cache->lock = 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
|
||||
grub_disk_addr_t sector, const char *data)
|
||||
{
|
||||
unsigned cache_index;
|
||||
struct grub_disk_cache *cache;
|
||||
|
||||
cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector);
|
||||
cache = grub_disk_cache_table + cache_index;
|
||||
|
||||
cache->lock = 1;
|
||||
grub_free (cache->data);
|
||||
cache->data = 0;
|
||||
cache->lock = 0;
|
||||
|
||||
cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
|
||||
if (! cache->data)
|
||||
return grub_errno;
|
||||
|
||||
grub_memcpy (cache->data, data,
|
||||
GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
|
||||
cache->dev_id = dev_id;
|
||||
cache->disk_id = disk_id;
|
||||
cache->sector = sector;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
grub_disk_dev_t grub_disk_dev_list;
|
||||
|
||||
void
|
||||
grub_disk_dev_register (grub_disk_dev_t dev)
|
||||
{
|
||||
dev->next = grub_disk_dev_list;
|
||||
grub_disk_dev_list = dev;
|
||||
}
|
||||
|
||||
void
|
||||
grub_disk_dev_unregister (grub_disk_dev_t dev)
|
||||
{
|
||||
grub_disk_dev_t *p, q;
|
||||
|
||||
for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
|
||||
if (q == dev)
|
||||
{
|
||||
*p = q->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the location of the first ',', if any, which is not
|
||||
escaped by a '\'. */
|
||||
static const char *
|
||||
find_part_sep (const char *name)
|
||||
{
|
||||
const char *p = name;
|
||||
char c;
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
{
|
||||
if (c == '\\' && *p == ',')
|
||||
p++;
|
||||
else if (c == ',')
|
||||
return p - 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_disk_t
|
||||
grub_disk_open (const char *name)
|
||||
{
|
||||
const char *p;
|
||||
grub_disk_t disk;
|
||||
grub_disk_dev_t dev;
|
||||
char *raw = (char *) name;
|
||||
grub_uint64_t current_time;
|
||||
|
||||
grub_dprintf ("disk", "Opening `%s'...\n", name);
|
||||
|
||||
disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
|
||||
if (! disk)
|
||||
return 0;
|
||||
disk->log_sector_size = GRUB_DISK_SECTOR_BITS;
|
||||
/* Default 1MiB of maximum agglomerate. */
|
||||
disk->max_agglomerate = 1048576 >> (GRUB_DISK_SECTOR_BITS
|
||||
+ GRUB_DISK_CACHE_BITS);
|
||||
|
||||
p = find_part_sep (name);
|
||||
if (p)
|
||||
{
|
||||
grub_size_t len = p - name;
|
||||
|
||||
raw = grub_malloc (len + 1);
|
||||
if (! raw)
|
||||
goto fail;
|
||||
|
||||
grub_memcpy (raw, name, len);
|
||||
raw[len] = '\0';
|
||||
disk->name = grub_strdup (raw);
|
||||
}
|
||||
else
|
||||
disk->name = grub_strdup (name);
|
||||
if (! disk->name)
|
||||
goto fail;
|
||||
|
||||
for (dev = grub_disk_dev_list; dev; dev = dev->next)
|
||||
{
|
||||
if ((dev->disk_open) (raw, disk) == GRUB_ERR_NONE)
|
||||
break;
|
||||
else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
else
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (! dev)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
|
||||
name);
|
||||
goto fail;
|
||||
}
|
||||
if (disk->log_sector_size > GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS
|
||||
|| disk->log_sector_size < GRUB_DISK_SECTOR_BITS)
|
||||
{
|
||||
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"sector sizes of %d bytes aren't supported yet",
|
||||
(1 << disk->log_sector_size));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
disk->dev = dev;
|
||||
|
||||
if (p)
|
||||
{
|
||||
disk->partition = grub_partition_probe (disk, p + 1);
|
||||
if (! disk->partition)
|
||||
{
|
||||
/* TRANSLATORS: It means that the specified partition e.g.
|
||||
hd0,msdos1=/dev/sda1 doesn't exist. */
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition"));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* The cache will be invalidated about 2 seconds after a device was
|
||||
closed. */
|
||||
current_time = grub_get_time_ms ();
|
||||
|
||||
if (current_time > (grub_last_time
|
||||
+ GRUB_CACHE_TIMEOUT * 1000))
|
||||
grub_disk_cache_invalidate_all ();
|
||||
|
||||
grub_last_time = current_time;
|
||||
|
||||
fail:
|
||||
|
||||
if (raw && raw != name)
|
||||
grub_free (raw);
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_dprintf ("disk", "Opening `%s' failed.\n", name);
|
||||
grub_error_pop ();
|
||||
|
||||
grub_disk_close (disk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return disk;
|
||||
}
|
||||
|
||||
void
|
||||
grub_disk_close (grub_disk_t disk)
|
||||
{
|
||||
grub_partition_t part;
|
||||
grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
|
||||
|
||||
if (disk->dev && disk->dev->disk_close)
|
||||
(disk->dev->disk_close) (disk);
|
||||
|
||||
/* Reset the timer. */
|
||||
grub_last_time = grub_get_time_ms ();
|
||||
|
||||
while (disk->partition)
|
||||
{
|
||||
part = disk->partition->parent;
|
||||
grub_free (disk->partition);
|
||||
disk->partition = part;
|
||||
}
|
||||
grub_free ((void *) disk->name);
|
||||
grub_free (disk);
|
||||
}
|
||||
|
||||
/* Small read (less than cache size and not pass across cache unit boundaries).
|
||||
sector is already adjusted and is divisible by cache unit size.
|
||||
*/
|
||||
static grub_err_t
|
||||
grub_disk_read_small_real (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_off_t offset, grub_size_t size, void *buf)
|
||||
{
|
||||
char *data;
|
||||
char *tmp_buf;
|
||||
|
||||
/* Fetch the cache. */
|
||||
data = grub_disk_cache_fetch (disk->dev->id, disk->id, sector);
|
||||
if (data)
|
||||
{
|
||||
/* Just copy it! */
|
||||
grub_memcpy (buf, data + offset, size);
|
||||
grub_disk_cache_unlock (disk->dev->id, disk->id, sector);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Allocate a temporary buffer. */
|
||||
tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
|
||||
if (! tmp_buf)
|
||||
return grub_errno;
|
||||
|
||||
/* Otherwise read data from the disk actually. */
|
||||
if (disk->total_sectors == GRUB_DISK_SIZE_UNKNOWN
|
||||
|| sector + GRUB_DISK_CACHE_SIZE
|
||||
< (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
|
||||
{
|
||||
grub_err_t err;
|
||||
err = (disk->dev->disk_read) (disk, transform_sector (disk, sector),
|
||||
1U << (GRUB_DISK_CACHE_BITS
|
||||
+ GRUB_DISK_SECTOR_BITS
|
||||
- disk->log_sector_size), tmp_buf);
|
||||
if (!err)
|
||||
{
|
||||
/* Copy it and store it in the disk cache. */
|
||||
grub_memcpy (buf, tmp_buf + offset, size);
|
||||
grub_disk_cache_store (disk->dev->id, disk->id,
|
||||
sector, tmp_buf);
|
||||
grub_free (tmp_buf);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
grub_free (tmp_buf);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
{
|
||||
/* Uggh... Failed. Instead, just read necessary data. */
|
||||
unsigned num;
|
||||
grub_disk_addr_t aligned_sector;
|
||||
|
||||
sector += (offset >> GRUB_DISK_SECTOR_BITS);
|
||||
offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
|
||||
aligned_sector = (sector & ~((1ULL << (disk->log_sector_size
|
||||
- GRUB_DISK_SECTOR_BITS))
|
||||
- 1));
|
||||
offset += ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
|
||||
num = ((size + offset + (1ULL << (disk->log_sector_size))
|
||||
- 1) >> (disk->log_sector_size));
|
||||
|
||||
tmp_buf = grub_malloc (num << disk->log_sector_size);
|
||||
if (!tmp_buf)
|
||||
return grub_errno;
|
||||
|
||||
if ((disk->dev->disk_read) (disk, transform_sector (disk, aligned_sector),
|
||||
num, tmp_buf))
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_dprintf ("disk", "%s read failed\n", disk->name);
|
||||
grub_error_pop ();
|
||||
grub_free (tmp_buf);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_memcpy (buf, tmp_buf + offset, size);
|
||||
grub_free (tmp_buf);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_off_t offset, grub_size_t size, void *buf)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
||||
err = grub_disk_read_small_real (disk, sector, offset, size, buf);
|
||||
if (err)
|
||||
return err;
|
||||
if (disk->read_hook)
|
||||
(disk->read_hook) (sector + (offset >> GRUB_DISK_SECTOR_BITS),
|
||||
offset & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
size, disk->read_hook_data);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t grub_disk_blocklist_read(void *chunklist, grub_uint64_t sector,
|
||||
grub_uint64_t size, grub_uint32_t log_sector_size)
|
||||
{
|
||||
ventoy_img_chunk *last_chunk = NULL;
|
||||
ventoy_img_chunk *new_chunk = NULL;
|
||||
ventoy_img_chunk_list *chunk_list = (ventoy_img_chunk_list *)chunklist;
|
||||
|
||||
if (chunk_list->cur_chunk == 0)
|
||||
{
|
||||
chunk_list->chunk[0].img_start_sector = 0;
|
||||
chunk_list->chunk[0].img_end_sector = (size >> 11) - 1;
|
||||
chunk_list->chunk[0].disk_start_sector = sector;
|
||||
chunk_list->chunk[0].disk_end_sector = sector + (size >> log_sector_size) - 1;
|
||||
chunk_list->cur_chunk = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1;
|
||||
if (last_chunk->disk_end_sector + 1 == sector)
|
||||
{
|
||||
last_chunk->img_end_sector += (size >> 11);
|
||||
last_chunk->disk_end_sector += (size >> log_sector_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (chunk_list->cur_chunk == chunk_list->max_chunk)
|
||||
{
|
||||
new_chunk = grub_realloc(chunk_list->chunk, chunk_list->max_chunk * 2 * sizeof(ventoy_img_chunk));
|
||||
if (NULL == new_chunk)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
chunk_list->chunk = new_chunk;
|
||||
chunk_list->max_chunk *= 2;
|
||||
|
||||
/* issue: update last_chunk */
|
||||
last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1;
|
||||
}
|
||||
|
||||
new_chunk = chunk_list->chunk + chunk_list->cur_chunk;
|
||||
new_chunk->img_start_sector = last_chunk->img_end_sector + 1;
|
||||
new_chunk->img_end_sector = new_chunk->img_start_sector + (size >> 11) - 1;
|
||||
new_chunk->disk_start_sector = sector;
|
||||
new_chunk->disk_end_sector = sector + (size >> log_sector_size) - 1;
|
||||
|
||||
chunk_list->cur_chunk++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read data from the disk. */
|
||||
grub_err_t
|
||||
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_off_t offset, grub_size_t size, void *buf)
|
||||
{
|
||||
if (disk->read_hook == (grub_disk_read_hook_t)grub_disk_blocklist_read)
|
||||
{
|
||||
return grub_disk_blocklist_read((ventoy_img_chunk_list *)disk->read_hook_data, sector, size, disk->log_sector_size);
|
||||
}
|
||||
|
||||
/* First of all, check if the region is within the disk. */
|
||||
if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_error_push ();
|
||||
grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
|
||||
(unsigned long long) sector, grub_errmsg);
|
||||
grub_error_pop ();
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* First read until first cache boundary. */
|
||||
if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
|
||||
{
|
||||
grub_disk_addr_t start_sector;
|
||||
grub_size_t pos;
|
||||
grub_err_t err;
|
||||
grub_size_t len;
|
||||
|
||||
start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1);
|
||||
pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS;
|
||||
len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS)
|
||||
- pos - offset);
|
||||
if (len > size)
|
||||
len = size;
|
||||
err = grub_disk_read_small (disk, start_sector,
|
||||
offset + pos, len, buf);
|
||||
if (err)
|
||||
return err;
|
||||
buf = (char *) buf + len;
|
||||
size -= len;
|
||||
offset += len;
|
||||
sector += (offset >> GRUB_DISK_SECTOR_BITS);
|
||||
offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
|
||||
}
|
||||
|
||||
/* Until SIZE is zero... */
|
||||
while (size >= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS))
|
||||
{
|
||||
char *data = NULL;
|
||||
grub_disk_addr_t agglomerate;
|
||||
grub_err_t err;
|
||||
|
||||
/* agglomerate read until we find a first cached entry. */
|
||||
for (agglomerate = 0; agglomerate
|
||||
< (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS))
|
||||
&& agglomerate < disk->max_agglomerate;
|
||||
agglomerate++)
|
||||
{
|
||||
data = grub_disk_cache_fetch (disk->dev->id, disk->id,
|
||||
sector + (agglomerate
|
||||
<< GRUB_DISK_CACHE_BITS));
|
||||
if (data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
grub_memcpy ((char *) buf
|
||||
+ (agglomerate << (GRUB_DISK_CACHE_BITS
|
||||
+ GRUB_DISK_SECTOR_BITS)),
|
||||
data, GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
|
||||
grub_disk_cache_unlock (disk->dev->id, disk->id,
|
||||
sector + (agglomerate
|
||||
<< GRUB_DISK_CACHE_BITS));
|
||||
}
|
||||
|
||||
if (agglomerate)
|
||||
{
|
||||
grub_disk_addr_t i;
|
||||
|
||||
err = (disk->dev->disk_read) (disk, transform_sector (disk, sector),
|
||||
agglomerate << (GRUB_DISK_CACHE_BITS
|
||||
+ GRUB_DISK_SECTOR_BITS
|
||||
- disk->log_sector_size),
|
||||
buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < agglomerate; i ++)
|
||||
grub_disk_cache_store (disk->dev->id, disk->id,
|
||||
sector + (i << GRUB_DISK_CACHE_BITS),
|
||||
(char *) buf
|
||||
+ (i << (GRUB_DISK_CACHE_BITS
|
||||
+ GRUB_DISK_SECTOR_BITS)));
|
||||
|
||||
|
||||
if (disk->read_hook)
|
||||
(disk->read_hook) (sector, 0, agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS),
|
||||
disk->read_hook_data);
|
||||
|
||||
sector += agglomerate << GRUB_DISK_CACHE_BITS;
|
||||
size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
|
||||
buf = (char *) buf
|
||||
+ (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
if (disk->read_hook)
|
||||
(disk->read_hook) (sector, 0, (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS),
|
||||
disk->read_hook_data);
|
||||
sector += GRUB_DISK_CACHE_SIZE;
|
||||
buf = (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
|
||||
size -= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
/* And now read the last part. */
|
||||
if (size)
|
||||
{
|
||||
grub_err_t err;
|
||||
err = grub_disk_read_small (disk, sector, 0, size, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_uint64_t
|
||||
grub_disk_get_size (grub_disk_t disk)
|
||||
{
|
||||
if (disk->partition)
|
||||
return grub_partition_get_len (disk->partition);
|
||||
else if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN)
|
||||
return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
|
||||
else
|
||||
return GRUB_DISK_SIZE_UNKNOWN;
|
||||
}
|
966
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c
Normal file
966
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c
Normal file
@@ -0,0 +1,966 @@
|
||||
/* efi.c - generic EFI support */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/misc.h>
|
||||
#include <grub/charset.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/console_control.h>
|
||||
#include <grub/efi/pe32.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/loader.h>
|
||||
|
||||
/* The handle of GRUB itself. Filled in by the startup code. */
|
||||
grub_efi_handle_t grub_efi_image_handle;
|
||||
|
||||
/* The pointer to a system table. Filled in by the startup code. */
|
||||
grub_efi_system_table_t *grub_efi_system_table;
|
||||
|
||||
static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
|
||||
static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
|
||||
static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
|
||||
|
||||
void *
|
||||
grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
|
||||
{
|
||||
void *interface;
|
||||
grub_efi_status_t status;
|
||||
|
||||
status = efi_call_3 (grub_efi_system_table->boot_services->locate_protocol,
|
||||
protocol, registration, &interface);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return 0;
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
/* Return the array of handles which meet the requirement. If successful,
|
||||
the number of handles is stored in NUM_HANDLES. The array is allocated
|
||||
from the heap. */
|
||||
grub_efi_handle_t *
|
||||
grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
|
||||
grub_efi_guid_t *protocol,
|
||||
void *search_key,
|
||||
grub_efi_uintn_t *num_handles)
|
||||
{
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_handle_t *buffer;
|
||||
grub_efi_uintn_t buffer_size = 8 * sizeof (grub_efi_handle_t);
|
||||
|
||||
buffer = grub_malloc (buffer_size);
|
||||
if (! buffer)
|
||||
return 0;
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
status = efi_call_5 (b->locate_handle, search_type, protocol, search_key,
|
||||
&buffer_size, buffer);
|
||||
if (status == GRUB_EFI_BUFFER_TOO_SMALL)
|
||||
{
|
||||
grub_free (buffer);
|
||||
buffer = grub_malloc (buffer_size);
|
||||
if (! buffer)
|
||||
return 0;
|
||||
|
||||
status = efi_call_5 (b->locate_handle, search_type, protocol, search_key,
|
||||
&buffer_size, buffer);
|
||||
}
|
||||
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
grub_free (buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*num_handles = buffer_size / sizeof (grub_efi_handle_t);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void *
|
||||
grub_efi_open_protocol (grub_efi_handle_t handle,
|
||||
grub_efi_guid_t *protocol,
|
||||
grub_efi_uint32_t attributes)
|
||||
{
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_efi_status_t status;
|
||||
void *interface;
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
status = efi_call_6 (b->open_protocol, handle,
|
||||
protocol,
|
||||
&interface,
|
||||
grub_efi_image_handle,
|
||||
0,
|
||||
attributes);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return 0;
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
int
|
||||
grub_efi_set_text_mode (int on)
|
||||
{
|
||||
grub_efi_console_control_protocol_t *c;
|
||||
grub_efi_screen_mode_t mode, new_mode;
|
||||
|
||||
c = grub_efi_locate_protocol (&console_control_guid, 0);
|
||||
if (! c)
|
||||
/* No console control protocol instance available, assume it is
|
||||
already in text mode. */
|
||||
return 1;
|
||||
|
||||
if (efi_call_4 (c->get_mode, c, &mode, 0, 0) != GRUB_EFI_SUCCESS)
|
||||
return 0;
|
||||
|
||||
new_mode = on ? GRUB_EFI_SCREEN_TEXT : GRUB_EFI_SCREEN_GRAPHICS;
|
||||
if (mode != new_mode)
|
||||
if (efi_call_2 (c->set_mode, c, new_mode) != GRUB_EFI_SUCCESS)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
grub_efi_stall (grub_efi_uintn_t microseconds)
|
||||
{
|
||||
efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds);
|
||||
}
|
||||
|
||||
grub_efi_loaded_image_t *
|
||||
grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
|
||||
{
|
||||
return grub_efi_open_protocol (image_handle,
|
||||
&loaded_image_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
}
|
||||
|
||||
void
|
||||
grub_reboot (void)
|
||||
{
|
||||
grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
|
||||
efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
|
||||
GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
|
||||
for (;;) ;
|
||||
}
|
||||
|
||||
void
|
||||
grub_exit (void)
|
||||
{
|
||||
grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
|
||||
efi_call_4 (grub_efi_system_table->boot_services->exit,
|
||||
grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0);
|
||||
for (;;) ;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
|
||||
grub_efi_uintn_t descriptor_size,
|
||||
grub_efi_uint32_t descriptor_version,
|
||||
grub_efi_memory_descriptor_t *virtual_map)
|
||||
{
|
||||
grub_efi_runtime_services_t *r;
|
||||
grub_efi_status_t status;
|
||||
|
||||
r = grub_efi_system_table->runtime_services;
|
||||
status = efi_call_4 (r->set_virtual_address_map, memory_map_size,
|
||||
descriptor_size, descriptor_version, virtual_map);
|
||||
|
||||
if (status == GRUB_EFI_SUCCESS)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed");
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
|
||||
void *data, grub_size_t datasize)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
grub_efi_runtime_services_t *r;
|
||||
grub_efi_char16_t *var16;
|
||||
grub_size_t len, len16;
|
||||
|
||||
len = grub_strlen (var);
|
||||
len16 = len * GRUB_MAX_UTF16_PER_UTF8;
|
||||
var16 = grub_malloc ((len16 + 1) * sizeof (var16[0]));
|
||||
if (!var16)
|
||||
return grub_errno;
|
||||
len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL);
|
||||
var16[len16] = 0;
|
||||
|
||||
r = grub_efi_system_table->runtime_services;
|
||||
|
||||
status = efi_call_5 (r->set_variable, var16, guid,
|
||||
(GRUB_EFI_VARIABLE_NON_VOLATILE
|
||||
| GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| GRUB_EFI_VARIABLE_RUNTIME_ACCESS),
|
||||
datasize, data);
|
||||
grub_free (var16);
|
||||
if (status == GRUB_EFI_SUCCESS)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var);
|
||||
}
|
||||
|
||||
void *
|
||||
grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
|
||||
grub_size_t *datasize_out)
|
||||
{
|
||||
grub_efi_status_t status;
|
||||
grub_efi_uintn_t datasize = 0;
|
||||
grub_efi_runtime_services_t *r;
|
||||
grub_efi_char16_t *var16;
|
||||
void *data;
|
||||
grub_size_t len, len16;
|
||||
|
||||
*datasize_out = 0;
|
||||
|
||||
len = grub_strlen (var);
|
||||
len16 = len * GRUB_MAX_UTF16_PER_UTF8;
|
||||
var16 = grub_malloc ((len16 + 1) * sizeof (var16[0]));
|
||||
if (!var16)
|
||||
return NULL;
|
||||
len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL);
|
||||
var16[len16] = 0;
|
||||
|
||||
r = grub_efi_system_table->runtime_services;
|
||||
|
||||
status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, NULL);
|
||||
|
||||
if (status != GRUB_EFI_BUFFER_TOO_SMALL || !datasize)
|
||||
{
|
||||
grub_free (var16);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = grub_malloc (datasize);
|
||||
if (!data)
|
||||
{
|
||||
grub_free (var16);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data);
|
||||
grub_free (var16);
|
||||
|
||||
if (status == GRUB_EFI_SUCCESS)
|
||||
{
|
||||
*datasize_out = datasize;
|
||||
return data;
|
||||
}
|
||||
|
||||
grub_free (data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
/* Search the mods section from the PE32/PE32+ image. This code uses
|
||||
a PE32 header, but should work with PE32+ as well. */
|
||||
grub_addr_t
|
||||
grub_efi_modules_addr (void)
|
||||
{
|
||||
grub_efi_loaded_image_t *image;
|
||||
struct grub_pe32_header *header;
|
||||
struct grub_pe32_coff_header *coff_header;
|
||||
struct grub_pe32_section_table *sections;
|
||||
struct grub_pe32_section_table *section;
|
||||
struct grub_module_info *info;
|
||||
grub_uint16_t i;
|
||||
|
||||
image = grub_efi_get_loaded_image (grub_efi_image_handle);
|
||||
if (! image)
|
||||
return 0;
|
||||
|
||||
header = image->image_base;
|
||||
coff_header = &(header->coff_header);
|
||||
sections
|
||||
= (struct grub_pe32_section_table *) ((char *) coff_header
|
||||
+ sizeof (*coff_header)
|
||||
+ coff_header->optional_header_size);
|
||||
|
||||
for (i = 0, section = sections;
|
||||
i < coff_header->num_sections;
|
||||
i++, section++)
|
||||
{
|
||||
if (grub_strcmp (section->name, "mods") == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == coff_header->num_sections)
|
||||
return 0;
|
||||
|
||||
info = (struct grub_module_info *) ((char *) image->image_base
|
||||
+ section->virtual_address);
|
||||
if (info->magic != GRUB_MODULE_MAGIC)
|
||||
return 0;
|
||||
|
||||
return (grub_addr_t) info;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic error "-Wcast-align"
|
||||
|
||||
char *
|
||||
grub_efi_get_filename (grub_efi_device_path_t *dp0)
|
||||
{
|
||||
char *name = 0, *p, *pi;
|
||||
grub_size_t filesize = 0;
|
||||
grub_efi_device_path_t *dp;
|
||||
|
||||
if (!dp0)
|
||||
return NULL;
|
||||
|
||||
dp = dp0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
|
||||
grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
|
||||
|
||||
if (type == GRUB_EFI_END_DEVICE_PATH_TYPE)
|
||||
break;
|
||||
if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
|
||||
&& subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
|
||||
{
|
||||
grub_efi_uint16_t len;
|
||||
len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4)
|
||||
/ sizeof (grub_efi_char16_t));
|
||||
filesize += GRUB_MAX_UTF8_PER_UTF16 * len + 2;
|
||||
}
|
||||
|
||||
dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
|
||||
}
|
||||
|
||||
if (!filesize)
|
||||
return NULL;
|
||||
|
||||
dp = dp0;
|
||||
|
||||
p = name = grub_malloc (filesize);
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
|
||||
grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
|
||||
|
||||
if (type == GRUB_EFI_END_DEVICE_PATH_TYPE)
|
||||
break;
|
||||
else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
|
||||
&& subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
|
||||
{
|
||||
grub_efi_file_path_device_path_t *fp;
|
||||
grub_efi_uint16_t len;
|
||||
grub_efi_char16_t *dup_name;
|
||||
|
||||
*p++ = '/';
|
||||
|
||||
len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4)
|
||||
/ sizeof (grub_efi_char16_t));
|
||||
fp = (grub_efi_file_path_device_path_t *) dp;
|
||||
/* According to EFI spec Path Name is NULL terminated */
|
||||
while (len > 0 && fp->path_name[len - 1] == 0)
|
||||
len--;
|
||||
|
||||
dup_name = grub_malloc (len * sizeof (*dup_name));
|
||||
if (!dup_name)
|
||||
{
|
||||
grub_free (name);
|
||||
return NULL;
|
||||
}
|
||||
p = (char *) grub_utf16_to_utf8 ((unsigned char *) p,
|
||||
grub_memcpy (dup_name, fp->path_name, len * sizeof (*dup_name)),
|
||||
len);
|
||||
grub_free (dup_name);
|
||||
}
|
||||
|
||||
dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
|
||||
for (pi = name, p = name; *pi;)
|
||||
{
|
||||
/* EFI breaks paths with backslashes. */
|
||||
if (*pi == '\\' || *pi == '/')
|
||||
{
|
||||
*p++ = '/';
|
||||
while (*pi == '\\' || *pi == '/')
|
||||
pi++;
|
||||
continue;
|
||||
}
|
||||
*p++ = *pi++;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
grub_efi_device_path_t *
|
||||
grub_efi_get_device_path (grub_efi_handle_t handle)
|
||||
{
|
||||
return grub_efi_open_protocol (handle, &device_path_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
}
|
||||
|
||||
/* Return the device path node right before the end node. */
|
||||
grub_efi_device_path_t *
|
||||
grub_efi_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;
|
||||
}
|
||||
|
||||
/* Duplicate a device path. */
|
||||
grub_efi_device_path_t *
|
||||
grub_efi_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;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_vendor_path (const char *type, grub_efi_vendor_device_path_t *vendor)
|
||||
{
|
||||
grub_uint32_t vendor_data_len = vendor->header.length - sizeof (*vendor);
|
||||
grub_printf ("/%sVendor(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)[%x: ",
|
||||
type,
|
||||
(unsigned) vendor->vendor_guid.data1,
|
||||
(unsigned) vendor->vendor_guid.data2,
|
||||
(unsigned) vendor->vendor_guid.data3,
|
||||
(unsigned) vendor->vendor_guid.data4[0],
|
||||
(unsigned) vendor->vendor_guid.data4[1],
|
||||
(unsigned) vendor->vendor_guid.data4[2],
|
||||
(unsigned) vendor->vendor_guid.data4[3],
|
||||
(unsigned) vendor->vendor_guid.data4[4],
|
||||
(unsigned) vendor->vendor_guid.data4[5],
|
||||
(unsigned) vendor->vendor_guid.data4[6],
|
||||
(unsigned) vendor->vendor_guid.data4[7],
|
||||
vendor_data_len);
|
||||
if (vendor->header.length > sizeof (*vendor))
|
||||
{
|
||||
grub_uint32_t i;
|
||||
for (i = 0; i < vendor_data_len; i++)
|
||||
grub_printf ("%02x ", vendor->vendor_defined_data[i]);
|
||||
}
|
||||
grub_printf ("]");
|
||||
}
|
||||
|
||||
|
||||
/* Print the chain of Device Path nodes. This is mainly for debugging. */
|
||||
void
|
||||
grub_efi_print_device_path (grub_efi_device_path_t *dp)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
|
||||
grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
|
||||
grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GRUB_EFI_END_DEVICE_PATH_TYPE:
|
||||
switch (subtype)
|
||||
{
|
||||
case GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE:
|
||||
grub_printf ("/EndEntire\n");
|
||||
//grub_putchar ('\n');
|
||||
break;
|
||||
case GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE:
|
||||
grub_printf ("/EndThis\n");
|
||||
//grub_putchar ('\n');
|
||||
break;
|
||||
default:
|
||||
grub_printf ("/EndUnknown(%x)\n", (unsigned) subtype);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE:
|
||||
switch (subtype)
|
||||
{
|
||||
case GRUB_EFI_PCI_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_pci_device_path_t *pci
|
||||
= (grub_efi_pci_device_path_t *) dp;
|
||||
grub_printf ("/PCI(%x,%x)",
|
||||
(unsigned) pci->function, (unsigned) pci->device);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_PCCARD_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_pccard_device_path_t *pccard
|
||||
= (grub_efi_pccard_device_path_t *) dp;
|
||||
grub_printf ("/PCCARD(%x)",
|
||||
(unsigned) pccard->function);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_memory_mapped_device_path_t *mmapped
|
||||
= (grub_efi_memory_mapped_device_path_t *) dp;
|
||||
grub_printf ("/MMap(%x,%llx,%llx)",
|
||||
(unsigned) mmapped->memory_type,
|
||||
(unsigned long long) mmapped->start_address,
|
||||
(unsigned long long) mmapped->end_address);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE:
|
||||
dump_vendor_path ("Hardware",
|
||||
(grub_efi_vendor_device_path_t *) dp);
|
||||
break;
|
||||
case GRUB_EFI_CONTROLLER_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_controller_device_path_t *controller
|
||||
= (grub_efi_controller_device_path_t *) dp;
|
||||
grub_printf ("/Ctrl(%x)",
|
||||
(unsigned) controller->controller_number);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
grub_printf ("/UnknownHW(%x)", (unsigned) subtype);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_ACPI_DEVICE_PATH_TYPE:
|
||||
switch (subtype)
|
||||
{
|
||||
case GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_acpi_device_path_t *acpi
|
||||
= (grub_efi_acpi_device_path_t *) dp;
|
||||
grub_printf ("/ACPI(%x,%x)",
|
||||
(unsigned) acpi->hid,
|
||||
(unsigned) acpi->uid);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_expanded_acpi_device_path_t *eacpi
|
||||
= (grub_efi_expanded_acpi_device_path_t *) dp;
|
||||
grub_printf ("/ACPI(");
|
||||
|
||||
if (GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)[0] == '\0')
|
||||
grub_printf ("%x,", (unsigned) eacpi->hid);
|
||||
else
|
||||
grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp));
|
||||
|
||||
if (GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)[0] == '\0')
|
||||
grub_printf ("%x,", (unsigned) eacpi->uid);
|
||||
else
|
||||
grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp));
|
||||
|
||||
if (GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)[0] == '\0')
|
||||
grub_printf ("%x)", (unsigned) eacpi->cid);
|
||||
else
|
||||
grub_printf ("%s)", GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
grub_printf ("/UnknownACPI(%x)", (unsigned) subtype);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE:
|
||||
switch (subtype)
|
||||
{
|
||||
case GRUB_EFI_ATAPI_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_atapi_device_path_t *atapi
|
||||
= (grub_efi_atapi_device_path_t *) dp;
|
||||
grub_printf ("/ATAPI(%x,%x,%x)",
|
||||
(unsigned) atapi->primary_secondary,
|
||||
(unsigned) atapi->slave_master,
|
||||
(unsigned) atapi->lun);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_SCSI_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_scsi_device_path_t *scsi
|
||||
= (grub_efi_scsi_device_path_t *) dp;
|
||||
grub_printf ("/SCSI(%x,%x)",
|
||||
(unsigned) scsi->pun,
|
||||
(unsigned) scsi->lun);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_fibre_channel_device_path_t *fc
|
||||
= (grub_efi_fibre_channel_device_path_t *) dp;
|
||||
grub_printf ("/FibreChannel(%llx,%llx)",
|
||||
(unsigned long long) fc->wwn,
|
||||
(unsigned long long) fc->lun);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_1394_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_1394_device_path_t *firewire
|
||||
= (grub_efi_1394_device_path_t *) dp;
|
||||
grub_printf ("/1394(%llx)",
|
||||
(unsigned long long) firewire->guid);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_USB_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_usb_device_path_t *usb
|
||||
= (grub_efi_usb_device_path_t *) dp;
|
||||
grub_printf ("/USB(%x,%x)",
|
||||
(unsigned) usb->parent_port_number,
|
||||
(unsigned) usb->usb_interface);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_USB_CLASS_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_usb_class_device_path_t *usb_class
|
||||
= (grub_efi_usb_class_device_path_t *) dp;
|
||||
grub_printf ("/USBClass(%x,%x,%x,%x,%x)",
|
||||
(unsigned) usb_class->vendor_id,
|
||||
(unsigned) usb_class->product_id,
|
||||
(unsigned) usb_class->device_class,
|
||||
(unsigned) usb_class->device_subclass,
|
||||
(unsigned) usb_class->device_protocol);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_I2O_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_i2o_device_path_t *i2o
|
||||
= (grub_efi_i2o_device_path_t *) dp;
|
||||
grub_printf ("/I2O(%x)", (unsigned) i2o->tid);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_mac_address_device_path_t *mac
|
||||
= (grub_efi_mac_address_device_path_t *) dp;
|
||||
grub_printf ("/MacAddr(%02x:%02x:%02x:%02x:%02x:%02x,%x)",
|
||||
(unsigned) mac->mac_address[0],
|
||||
(unsigned) mac->mac_address[1],
|
||||
(unsigned) mac->mac_address[2],
|
||||
(unsigned) mac->mac_address[3],
|
||||
(unsigned) mac->mac_address[4],
|
||||
(unsigned) mac->mac_address[5],
|
||||
(unsigned) mac->if_type);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_ipv4_device_path_t *ipv4
|
||||
= (grub_efi_ipv4_device_path_t *) dp;
|
||||
grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)",
|
||||
(unsigned) ipv4->local_ip_address[0],
|
||||
(unsigned) ipv4->local_ip_address[1],
|
||||
(unsigned) ipv4->local_ip_address[2],
|
||||
(unsigned) ipv4->local_ip_address[3],
|
||||
(unsigned) ipv4->remote_ip_address[0],
|
||||
(unsigned) ipv4->remote_ip_address[1],
|
||||
(unsigned) ipv4->remote_ip_address[2],
|
||||
(unsigned) ipv4->remote_ip_address[3],
|
||||
(unsigned) ipv4->local_port,
|
||||
(unsigned) ipv4->remote_port,
|
||||
(unsigned) ipv4->protocol,
|
||||
(unsigned) ipv4->static_ip_address);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_ipv6_device_path_t *ipv6
|
||||
= (grub_efi_ipv6_device_path_t *) dp;
|
||||
grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)",
|
||||
(unsigned) ipv6->local_ip_address[0],
|
||||
(unsigned) ipv6->local_ip_address[1],
|
||||
(unsigned) ipv6->local_ip_address[2],
|
||||
(unsigned) ipv6->local_ip_address[3],
|
||||
(unsigned) ipv6->local_ip_address[4],
|
||||
(unsigned) ipv6->local_ip_address[5],
|
||||
(unsigned) ipv6->local_ip_address[6],
|
||||
(unsigned) ipv6->local_ip_address[7],
|
||||
(unsigned) ipv6->remote_ip_address[0],
|
||||
(unsigned) ipv6->remote_ip_address[1],
|
||||
(unsigned) ipv6->remote_ip_address[2],
|
||||
(unsigned) ipv6->remote_ip_address[3],
|
||||
(unsigned) ipv6->remote_ip_address[4],
|
||||
(unsigned) ipv6->remote_ip_address[5],
|
||||
(unsigned) ipv6->remote_ip_address[6],
|
||||
(unsigned) ipv6->remote_ip_address[7],
|
||||
(unsigned) ipv6->local_port,
|
||||
(unsigned) ipv6->remote_port,
|
||||
(unsigned) ipv6->protocol,
|
||||
(unsigned) ipv6->static_ip_address);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_infiniband_device_path_t *ib
|
||||
= (grub_efi_infiniband_device_path_t *) dp;
|
||||
grub_printf ("/InfiniBand(%x,%llx,%llx,%llx)",
|
||||
(unsigned) ib->port_gid[0], /* XXX */
|
||||
(unsigned long long) ib->remote_id,
|
||||
(unsigned long long) ib->target_port_id,
|
||||
(unsigned long long) ib->device_id);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_UART_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_uart_device_path_t *uart
|
||||
= (grub_efi_uart_device_path_t *) dp;
|
||||
grub_printf ("/UART(%llu,%u,%x,%x)",
|
||||
(unsigned long long) uart->baud_rate,
|
||||
uart->data_bits,
|
||||
uart->parity,
|
||||
uart->stop_bits);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_SATA_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_sata_device_path_t *sata;
|
||||
sata = (grub_efi_sata_device_path_t *) dp;
|
||||
grub_printf ("/Sata(%x,%x,%x)",
|
||||
sata->hba_port,
|
||||
sata->multiplier_port,
|
||||
sata->lun);
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE:
|
||||
dump_vendor_path ("Messaging",
|
||||
(grub_efi_vendor_device_path_t *) dp);
|
||||
break;
|
||||
default:
|
||||
grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_MEDIA_DEVICE_PATH_TYPE:
|
||||
switch (subtype)
|
||||
{
|
||||
case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_hard_drive_device_path_t *hd = (grub_efi_hard_drive_device_path_t *) dp;
|
||||
grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x%02x%02x%02x%02x,%x,%x)",
|
||||
hd->partition_number,
|
||||
(unsigned long long) hd->partition_start,
|
||||
(unsigned long long) hd->partition_size,
|
||||
(unsigned) hd->partition_signature[0],
|
||||
(unsigned) hd->partition_signature[1],
|
||||
(unsigned) hd->partition_signature[2],
|
||||
(unsigned) hd->partition_signature[3],
|
||||
(unsigned) hd->partition_signature[4],
|
||||
(unsigned) hd->partition_signature[5],
|
||||
(unsigned) hd->partition_signature[6],
|
||||
(unsigned) hd->partition_signature[7],
|
||||
(unsigned) hd->partmap_type,
|
||||
(unsigned) hd->signature_type);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_cdrom_device_path_t *cd
|
||||
= (grub_efi_cdrom_device_path_t *) dp;
|
||||
grub_printf ("/CD(%u,%llx,%llx)",
|
||||
cd->boot_entry,
|
||||
(unsigned long long) cd->partition_start,
|
||||
(unsigned long long) cd->partition_size);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE:
|
||||
dump_vendor_path ("Media",
|
||||
(grub_efi_vendor_device_path_t *) dp);
|
||||
break;
|
||||
case GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_file_path_device_path_t *fp;
|
||||
grub_uint8_t *buf;
|
||||
fp = (grub_efi_file_path_device_path_t *) dp;
|
||||
buf = grub_malloc ((len - 4) * 2 + 1);
|
||||
if (buf)
|
||||
{
|
||||
grub_efi_char16_t *dup_name = grub_malloc (len - 4);
|
||||
if (!dup_name)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_printf ("/File((null))");
|
||||
grub_free (buf);
|
||||
break;
|
||||
}
|
||||
*grub_utf16_to_utf8 (buf, grub_memcpy (dup_name, fp->path_name, len - 4),
|
||||
(len - 4) / sizeof (grub_efi_char16_t))
|
||||
= '\0';
|
||||
grub_free (dup_name);
|
||||
}
|
||||
else
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_printf ("/File(%s)", buf);
|
||||
grub_free (buf);
|
||||
}
|
||||
break;
|
||||
case GRUB_EFI_PROTOCOL_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_protocol_device_path_t *proto
|
||||
= (grub_efi_protocol_device_path_t *) dp;
|
||||
grub_printf ("/Protocol(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
|
||||
(unsigned) proto->guid.data1,
|
||||
(unsigned) proto->guid.data2,
|
||||
(unsigned) proto->guid.data3,
|
||||
(unsigned) proto->guid.data4[0],
|
||||
(unsigned) proto->guid.data4[1],
|
||||
(unsigned) proto->guid.data4[2],
|
||||
(unsigned) proto->guid.data4[3],
|
||||
(unsigned) proto->guid.data4[4],
|
||||
(unsigned) proto->guid.data4[5],
|
||||
(unsigned) proto->guid.data4[6],
|
||||
(unsigned) proto->guid.data4[7]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
grub_printf ("/UnknownMedia(%x)", (unsigned) subtype);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GRUB_EFI_BIOS_DEVICE_PATH_TYPE:
|
||||
switch (subtype)
|
||||
{
|
||||
case GRUB_EFI_BIOS_DEVICE_PATH_SUBTYPE:
|
||||
{
|
||||
grub_efi_bios_device_path_t *bios
|
||||
= (grub_efi_bios_device_path_t *) dp;
|
||||
grub_printf ("/BIOS(%x,%x,%s)",
|
||||
(unsigned) bios->device_type,
|
||||
(unsigned) bios->status_flags,
|
||||
(char *) (dp + 1));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
grub_printf ("/UnknownBIOS(%x)", (unsigned) subtype);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
grub_printf ("/UnknownType(%x,%x)\n",
|
||||
(unsigned) type,
|
||||
(unsigned) subtype);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
|
||||
break;
|
||||
|
||||
dp = (grub_efi_device_path_t *) ((char *) dp + len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare device paths. */
|
||||
int
|
||||
grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1,
|
||||
const grub_efi_device_path_t *dp2)
|
||||
{
|
||||
if (! dp1 || ! dp2)
|
||||
/* Return non-zero. */
|
||||
return 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
grub_efi_uint8_t type1, type2;
|
||||
grub_efi_uint8_t subtype1, subtype2;
|
||||
grub_efi_uint16_t len1, len2;
|
||||
int ret;
|
||||
|
||||
type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
|
||||
type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
|
||||
|
||||
if (type1 != type2)
|
||||
return (int) type2 - (int) type1;
|
||||
|
||||
subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
|
||||
subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
|
||||
|
||||
if (subtype1 != subtype2)
|
||||
return (int) subtype1 - (int) subtype2;
|
||||
|
||||
len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
|
||||
len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
|
||||
|
||||
if (len1 != len2)
|
||||
return (int) len1 - (int) len2;
|
||||
|
||||
ret = grub_memcmp (dp1, dp2, len1);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
|
||||
break;
|
||||
|
||||
dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
|
||||
dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void * grub_efi_allocate_iso_buf(grub_uint64_t size)
|
||||
{
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_physical_address_t address = 0;
|
||||
grub_efi_uintn_t pages = GRUB_EFI_BYTES_TO_PAGES(size);
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)(unsigned long)address;
|
||||
}
|
256
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
Normal file
256
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/* file.c - file I/O functions */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,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/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/net.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
void (*EXPORT_VAR (grub_grubnet_fini)) (void);
|
||||
|
||||
grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX];
|
||||
|
||||
/* Get the device part of the filename NAME. It is enclosed by parentheses. */
|
||||
char *
|
||||
grub_file_get_device_name (const char *name)
|
||||
{
|
||||
if (name[0] == '(')
|
||||
{
|
||||
char *p = grub_strchr (name, ')');
|
||||
char *ret;
|
||||
|
||||
if (! p)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILENAME, N_("missing `%c' symbol"), ')');
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = (char *) grub_malloc (p - name);
|
||||
if (! ret)
|
||||
return 0;
|
||||
|
||||
grub_memcpy (ret, name + 1, p - name - 1);
|
||||
ret[p - name - 1] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Support mem:xxx:size:xxx format in chainloader */
|
||||
grub_file_t grub_memfile_open(const char *name);
|
||||
#define GRUB_MEMFILE_MEM "mem:"
|
||||
#define GRUB_MEMFILE_SIZE "size:"
|
||||
|
||||
grub_file_t grub_memfile_open(const char *name)
|
||||
{
|
||||
char *size = NULL;
|
||||
grub_file_t file = 0;
|
||||
|
||||
file = (grub_file_t)grub_zalloc(sizeof(*file));
|
||||
if (NULL == file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->name = grub_strdup(name);
|
||||
file->data = (void *)grub_strtoul(name + grub_strlen(GRUB_MEMFILE_MEM), NULL, 0);
|
||||
|
||||
size = grub_strstr(name, GRUB_MEMFILE_SIZE);
|
||||
file->size = (grub_off_t)grub_strtoul(size + grub_strlen(GRUB_MEMFILE_SIZE), NULL, 0);
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return file;
|
||||
}
|
||||
|
||||
grub_file_t
|
||||
grub_file_open (const char *name, enum grub_file_type type)
|
||||
{
|
||||
grub_device_t device = 0;
|
||||
grub_file_t file = 0, last_file = 0;
|
||||
char *device_name;
|
||||
const char *file_name;
|
||||
grub_file_filter_id_t filter;
|
||||
|
||||
/* <DESC> : mem:xxx:size:xxx format in chainloader */
|
||||
if (grub_strncmp(name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) {
|
||||
return grub_memfile_open(name);
|
||||
}
|
||||
|
||||
device_name = grub_file_get_device_name (name);
|
||||
if (grub_errno)
|
||||
goto fail;
|
||||
|
||||
/* Get the file part of NAME. */
|
||||
file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL;
|
||||
if (file_name)
|
||||
file_name++;
|
||||
else
|
||||
file_name = name;
|
||||
|
||||
device = grub_device_open (device_name);
|
||||
grub_free (device_name);
|
||||
if (! device)
|
||||
goto fail;
|
||||
|
||||
file = (grub_file_t) grub_zalloc (sizeof (*file));
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
||||
file->device = device;
|
||||
|
||||
/* In case of relative pathnames and non-Unix systems (like Windows)
|
||||
* name of host files may not start with `/'. Blocklists for host files
|
||||
* are meaningless as well (for a start, host disk does not allow any direct
|
||||
* access - it is just a marker). So skip host disk in this case.
|
||||
*/
|
||||
if (device->disk && file_name[0] != '/'
|
||||
#if defined(GRUB_UTIL) || defined(GRUB_MACHINE_EMU)
|
||||
&& grub_strcmp (device->disk->name, "host")
|
||||
#endif
|
||||
)
|
||||
/* This is a block list. */
|
||||
file->fs = &grub_fs_blocklist;
|
||||
else
|
||||
{
|
||||
file->fs = grub_fs_probe (device);
|
||||
if (! file->fs)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE)
|
||||
goto fail;
|
||||
|
||||
file->name = grub_strdup (name);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters);
|
||||
filter++)
|
||||
if (grub_file_filters[filter])
|
||||
{
|
||||
last_file = file;
|
||||
file = grub_file_filters[filter] (file, type);
|
||||
if (file && file != last_file)
|
||||
{
|
||||
file->name = grub_strdup (name);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
if (!file)
|
||||
grub_file_close (last_file);
|
||||
|
||||
return file;
|
||||
|
||||
fail:
|
||||
if (device)
|
||||
grub_device_close (device);
|
||||
|
||||
/* if (net) grub_net_close (net); */
|
||||
|
||||
grub_free (file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_disk_read_hook_t grub_file_progress_hook;
|
||||
|
||||
grub_ssize_t
|
||||
grub_file_read (grub_file_t file, void *buf, grub_size_t len)
|
||||
{
|
||||
grub_ssize_t res;
|
||||
grub_disk_read_hook_t read_hook;
|
||||
void *read_hook_data;
|
||||
|
||||
if (file->offset > file->size)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
N_("attempt to read past the end of file"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if (len > file->size - file->offset)
|
||||
len = file->size - file->offset;
|
||||
|
||||
/* Prevent an overflow. */
|
||||
if ((grub_ssize_t) len < 0)
|
||||
len >>= 1;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if (grub_strncmp(file->name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) {
|
||||
grub_memcpy(buf, (grub_uint8_t *)(file->data) + file->offset, len);
|
||||
file->offset += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
read_hook = file->read_hook;
|
||||
read_hook_data = file->read_hook_data;
|
||||
if (!file->read_hook)
|
||||
{
|
||||
file->read_hook = grub_file_progress_hook;
|
||||
file->read_hook_data = file;
|
||||
file->progress_offset = file->offset;
|
||||
}
|
||||
res = (file->fs->fs_read) (file, buf, len);
|
||||
file->read_hook = read_hook;
|
||||
file->read_hook_data = read_hook_data;
|
||||
if (res > 0)
|
||||
file->offset += res;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_file_close (grub_file_t file)
|
||||
{
|
||||
if (file->fs && file->fs->fs_close)
|
||||
(file->fs->fs_close) (file);
|
||||
|
||||
if (file->device)
|
||||
grub_device_close (file->device);
|
||||
grub_free (file->name);
|
||||
grub_free (file);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_off_t
|
||||
grub_file_seek (grub_file_t file, grub_off_t offset)
|
||||
{
|
||||
grub_off_t old;
|
||||
|
||||
if (offset > file->size)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
N_("attempt to seek outside of the file"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
old = file->offset;
|
||||
file->offset = offset;
|
||||
|
||||
return old;
|
||||
}
|
304
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c
Normal file
304
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/* fs.c - filesystem manager */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,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/disk.h>
|
||||
#include <grub/net.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
grub_fs_t grub_fs_list = 0;
|
||||
|
||||
grub_fs_autoload_hook_t grub_fs_autoload_hook = 0;
|
||||
|
||||
/* Helper for grub_fs_probe. */
|
||||
static int
|
||||
probe_dummy_iter (const char *filename __attribute__ ((unused)),
|
||||
const struct grub_dirhook_info *info __attribute__ ((unused)),
|
||||
void *data __attribute__ ((unused)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_fs_t
|
||||
grub_fs_probe (grub_device_t device)
|
||||
{
|
||||
grub_fs_t p;
|
||||
const char *first_probe;
|
||||
grub_size_t len;
|
||||
|
||||
if (device->disk)
|
||||
{
|
||||
/* Make it sure not to have an infinite recursive calls. */
|
||||
static int count = 0;
|
||||
|
||||
first_probe = grub_env_get("ventoy_fs_probe");
|
||||
if (!first_probe)
|
||||
{
|
||||
first_probe = "iso9660";
|
||||
}
|
||||
len = grub_strlen(first_probe);
|
||||
|
||||
/* use iso9660 first */
|
||||
for (p = grub_fs_list; p; p = p->next)
|
||||
{
|
||||
if (grub_strncmp(p->name, first_probe, len) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p)
|
||||
{
|
||||
grub_dprintf ("fs", "Detecting %s...\n", p->name);
|
||||
|
||||
/* This is evil: newly-created just mounted BtrFS after copying all
|
||||
GRUB files has a very peculiar unrecoverable corruption which
|
||||
will be fixed at sync but we'd rather not do a global sync and
|
||||
syncing just files doesn't seem to help. Relax the check for
|
||||
this time. */
|
||||
#ifdef GRUB_UTIL
|
||||
if (grub_strcmp (p->name, "btrfs") == 0)
|
||||
{
|
||||
char *label = 0;
|
||||
p->fs_uuid (device, &label);
|
||||
if (label)
|
||||
grub_free (label);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
(p->fs_dir) (device, "/", probe_dummy_iter, NULL);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
return p;
|
||||
|
||||
grub_error_push ();
|
||||
grub_dprintf ("fs", "%s detection failed.\n", p->name);
|
||||
grub_error_pop ();
|
||||
|
||||
if (grub_errno != GRUB_ERR_BAD_FS
|
||||
&& grub_errno != GRUB_ERR_OUT_OF_RANGE)
|
||||
return 0;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
for (p = grub_fs_list; p; p = p->next)
|
||||
{
|
||||
grub_dprintf ("fs", "Detecting %s...\n", p->name);
|
||||
|
||||
/* This is evil: newly-created just mounted BtrFS after copying all
|
||||
GRUB files has a very peculiar unrecoverable corruption which
|
||||
will be fixed at sync but we'd rather not do a global sync and
|
||||
syncing just files doesn't seem to help. Relax the check for
|
||||
this time. */
|
||||
#ifdef GRUB_UTIL
|
||||
if (grub_strcmp (p->name, "btrfs") == 0)
|
||||
{
|
||||
char *label = 0;
|
||||
p->fs_uuid (device, &label);
|
||||
if (label)
|
||||
grub_free (label);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
(p->fs_dir) (device, "/", probe_dummy_iter, NULL);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
return p;
|
||||
|
||||
grub_error_push ();
|
||||
grub_dprintf ("fs", "%s detection failed.\n", p->name);
|
||||
grub_error_pop ();
|
||||
|
||||
if (grub_errno != GRUB_ERR_BAD_FS
|
||||
&& grub_errno != GRUB_ERR_OUT_OF_RANGE)
|
||||
return 0;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Let's load modules automatically. */
|
||||
if (grub_fs_autoload_hook && count == 0)
|
||||
{
|
||||
count++;
|
||||
|
||||
while (grub_fs_autoload_hook ())
|
||||
{
|
||||
p = grub_fs_list;
|
||||
|
||||
(p->fs_dir) (device, "/", probe_dummy_iter, NULL);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
count--;
|
||||
return p;
|
||||
}
|
||||
|
||||
if (grub_errno != GRUB_ERR_BAD_FS
|
||||
&& grub_errno != GRUB_ERR_OUT_OF_RANGE)
|
||||
{
|
||||
count--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
count--;
|
||||
}
|
||||
}
|
||||
else if (device->net && device->net->fs)
|
||||
return device->net->fs;
|
||||
|
||||
grub_error (GRUB_ERR_UNKNOWN_FS, N_("unknown filesystem"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Block list support routines. */
|
||||
|
||||
struct grub_fs_block
|
||||
{
|
||||
grub_disk_addr_t offset;
|
||||
unsigned long length;
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
grub_fs_blocklist_open (grub_file_t file, const char *name)
|
||||
{
|
||||
char *p = (char *) name;
|
||||
unsigned num = 0;
|
||||
unsigned i;
|
||||
grub_disk_t disk = file->device->disk;
|
||||
struct grub_fs_block *blocks;
|
||||
|
||||
/* First, count the number of blocks. */
|
||||
do
|
||||
{
|
||||
num++;
|
||||
p = grub_strchr (p, ',');
|
||||
if (p)
|
||||
p++;
|
||||
}
|
||||
while (p);
|
||||
|
||||
/* Allocate a block list. */
|
||||
blocks = grub_zalloc (sizeof (struct grub_fs_block) * (num + 1));
|
||||
if (! blocks)
|
||||
return 0;
|
||||
|
||||
file->size = 0;
|
||||
p = (char *) name;
|
||||
for (i = 0; i < num; i++)
|
||||
{
|
||||
if (*p != '+')
|
||||
{
|
||||
blocks[i].offset = grub_strtoull (p, &p, 0);
|
||||
if (grub_errno != GRUB_ERR_NONE || *p != '+')
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILENAME,
|
||||
N_("invalid file name `%s'"), name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
p++;
|
||||
blocks[i].length = grub_strtoul (p, &p, 0);
|
||||
if (grub_errno != GRUB_ERR_NONE
|
||||
|| blocks[i].length == 0
|
||||
|| (*p && *p != ',' && ! grub_isspace (*p)))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILENAME,
|
||||
N_("invalid file name `%s'"), name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (disk->total_sectors < blocks[i].offset + blocks[i].length)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILENAME, "beyond the total sectors");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file->size += (blocks[i].length << GRUB_DISK_SECTOR_BITS);
|
||||
p++;
|
||||
}
|
||||
|
||||
file->data = blocks;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
fail:
|
||||
grub_free (blocks);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
struct grub_fs_block *p;
|
||||
grub_disk_addr_t sector;
|
||||
grub_off_t offset;
|
||||
grub_ssize_t ret = 0;
|
||||
|
||||
if (len > file->size - file->offset)
|
||||
len = file->size - file->offset;
|
||||
|
||||
sector = (file->offset >> GRUB_DISK_SECTOR_BITS);
|
||||
offset = (file->offset & (GRUB_DISK_SECTOR_SIZE - 1));
|
||||
for (p = file->data; p->length && len > 0; p++)
|
||||
{
|
||||
if (sector < p->length)
|
||||
{
|
||||
grub_size_t size;
|
||||
|
||||
size = len;
|
||||
if (((size + offset + GRUB_DISK_SECTOR_SIZE - 1)
|
||||
>> GRUB_DISK_SECTOR_BITS) > p->length - sector)
|
||||
size = ((p->length - sector) << GRUB_DISK_SECTOR_BITS) - offset;
|
||||
|
||||
if (grub_disk_read (file->device->disk, p->offset + sector, offset,
|
||||
size, buf) != GRUB_ERR_NONE)
|
||||
return -1;
|
||||
|
||||
ret += size;
|
||||
len -= size;
|
||||
sector -= ((size + offset) >> GRUB_DISK_SECTOR_BITS);
|
||||
offset = ((size + offset) & (GRUB_DISK_SECTOR_SIZE - 1));
|
||||
}
|
||||
else
|
||||
sector -= p->length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct grub_fs grub_fs_blocklist =
|
||||
{
|
||||
.name = "blocklist",
|
||||
.fs_dir = 0,
|
||||
.fs_open = grub_fs_blocklist_open,
|
||||
.fs_read = grub_fs_blocklist_read,
|
||||
.fs_close = 0,
|
||||
.next = 0
|
||||
};
|
312
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c
Normal file
312
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/* main.c - the kernel main routine */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,2005,2006,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/kernel.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/reader.h>
|
||||
#include <grub/parser.h>
|
||||
|
||||
#ifdef GRUB_MACHINE_PCBIOS
|
||||
#include <grub/machine/memory.h>
|
||||
#endif
|
||||
|
||||
grub_addr_t
|
||||
grub_modules_get_end (void)
|
||||
{
|
||||
struct grub_module_info *modinfo;
|
||||
|
||||
modinfo = (struct grub_module_info *) grub_modbase;
|
||||
|
||||
/* Check if there are any modules. */
|
||||
if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
|
||||
return grub_modbase;
|
||||
|
||||
return grub_modbase + modinfo->size;
|
||||
}
|
||||
|
||||
/* Load all modules in core. */
|
||||
static void
|
||||
grub_load_modules (void)
|
||||
{
|
||||
struct grub_module_header *header;
|
||||
FOR_MODULES (header)
|
||||
{
|
||||
/* Not an ELF module, skip. */
|
||||
if (header->type != OBJ_TYPE_ELF)
|
||||
continue;
|
||||
|
||||
if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
|
||||
(header->size - sizeof (struct grub_module_header))))
|
||||
grub_fatal ("%s", grub_errmsg);
|
||||
|
||||
if (grub_errno)
|
||||
grub_print_error ();
|
||||
}
|
||||
}
|
||||
|
||||
static char *load_config;
|
||||
|
||||
static void
|
||||
grub_load_config (void)
|
||||
{
|
||||
struct grub_module_header *header;
|
||||
FOR_MODULES (header)
|
||||
{
|
||||
/* Not an embedded config, skip. */
|
||||
if (header->type != OBJ_TYPE_CONFIG)
|
||||
continue;
|
||||
|
||||
load_config = grub_malloc (header->size - sizeof (struct grub_module_header) + 1);
|
||||
if (!load_config)
|
||||
{
|
||||
grub_print_error ();
|
||||
break;
|
||||
}
|
||||
grub_memcpy (load_config, (char *) header +
|
||||
sizeof (struct grub_module_header),
|
||||
header->size - sizeof (struct grub_module_header));
|
||||
load_config[header->size - sizeof (struct grub_module_header)] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write hook for the environment variables of root. Remove surrounding
|
||||
parentheses, if any. */
|
||||
static char *
|
||||
grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
|
||||
const char *val)
|
||||
{
|
||||
/* XXX Is it better to check the existence of the device? */
|
||||
grub_size_t len = grub_strlen (val);
|
||||
|
||||
if (val[0] == '(' && val[len - 1] == ')')
|
||||
return grub_strndup (val + 1, len - 2);
|
||||
|
||||
return grub_strdup (val);
|
||||
}
|
||||
|
||||
static void
|
||||
grub_set_prefix_and_root (void)
|
||||
{
|
||||
char *device = NULL;
|
||||
char *path = NULL;
|
||||
char *fwdevice = NULL;
|
||||
char *fwpath = NULL;
|
||||
char *prefix = NULL;
|
||||
struct grub_module_header *header;
|
||||
|
||||
FOR_MODULES (header)
|
||||
if (header->type == OBJ_TYPE_PREFIX)
|
||||
prefix = (char *) header + sizeof (struct grub_module_header);
|
||||
|
||||
grub_register_variable_hook ("root", 0, grub_env_write_root);
|
||||
|
||||
grub_machine_get_bootlocation (&fwdevice, &fwpath);
|
||||
|
||||
if (fwdevice)
|
||||
{
|
||||
char *cmdpath;
|
||||
|
||||
cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
|
||||
if (cmdpath)
|
||||
{
|
||||
grub_env_set ("cmdpath", cmdpath);
|
||||
grub_env_export ("cmdpath");
|
||||
grub_free (cmdpath);
|
||||
}
|
||||
}
|
||||
|
||||
if (prefix)
|
||||
{
|
||||
char *pptr = NULL;
|
||||
if (prefix[0] == '(')
|
||||
{
|
||||
pptr = grub_strrchr (prefix, ')');
|
||||
if (pptr)
|
||||
{
|
||||
device = grub_strndup (prefix + 1, pptr - prefix - 1);
|
||||
pptr++;
|
||||
}
|
||||
}
|
||||
if (!pptr)
|
||||
pptr = prefix;
|
||||
if (pptr[0])
|
||||
path = grub_strdup (pptr);
|
||||
}
|
||||
|
||||
if (!device && fwdevice)
|
||||
device = fwdevice;
|
||||
else if (fwdevice && (device[0] == ',' || !device[0]))
|
||||
{
|
||||
/* We have a partition, but still need to fill in the drive. */
|
||||
char *comma, *new_device;
|
||||
|
||||
for (comma = fwdevice; *comma; )
|
||||
{
|
||||
if (comma[0] == '\\' && comma[1] == ',')
|
||||
{
|
||||
comma += 2;
|
||||
continue;
|
||||
}
|
||||
if (*comma == ',')
|
||||
break;
|
||||
comma++;
|
||||
}
|
||||
if (*comma)
|
||||
{
|
||||
char *drive = grub_strndup (fwdevice, comma - fwdevice);
|
||||
new_device = grub_xasprintf ("%s%s", drive, device);
|
||||
grub_free (drive);
|
||||
}
|
||||
else
|
||||
new_device = grub_xasprintf ("%s%s", fwdevice, device);
|
||||
|
||||
grub_free (fwdevice);
|
||||
grub_free (device);
|
||||
device = new_device;
|
||||
}
|
||||
else
|
||||
grub_free (fwdevice);
|
||||
if (fwpath && !path)
|
||||
{
|
||||
grub_size_t len = grub_strlen (fwpath);
|
||||
while (len > 1 && fwpath[len - 1] == '/')
|
||||
fwpath[--len] = 0;
|
||||
if (len >= sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1
|
||||
&& grub_memcmp (fwpath + len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1), GRUB_TARGET_CPU "-" GRUB_PLATFORM,
|
||||
sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1) == 0)
|
||||
fwpath[len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1)] = 0;
|
||||
path = fwpath;
|
||||
}
|
||||
else
|
||||
grub_free (fwpath);
|
||||
if (device)
|
||||
{
|
||||
char *prefix_set;
|
||||
|
||||
prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
|
||||
if (prefix_set)
|
||||
{
|
||||
grub_env_set ("prefix", prefix_set);
|
||||
grub_free (prefix_set);
|
||||
}
|
||||
grub_env_set ("root", device);
|
||||
}
|
||||
|
||||
grub_free (device);
|
||||
grub_free (path);
|
||||
grub_print_error ();
|
||||
}
|
||||
|
||||
/* Load the normal mode module and execute the normal mode if possible. */
|
||||
static void
|
||||
grub_load_normal_mode (void)
|
||||
{
|
||||
/* Load the module. */
|
||||
grub_dl_load ("normal");
|
||||
|
||||
/* Print errors if any. */
|
||||
grub_print_error ();
|
||||
grub_errno = 0;
|
||||
|
||||
grub_command_execute ("normal", 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
reclaim_module_space (void)
|
||||
{
|
||||
grub_addr_t modstart, modend;
|
||||
|
||||
if (!grub_modbase)
|
||||
return;
|
||||
|
||||
#ifdef GRUB_MACHINE_PCBIOS
|
||||
modstart = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR;
|
||||
#else
|
||||
modstart = grub_modbase;
|
||||
#endif
|
||||
modend = grub_modules_get_end ();
|
||||
grub_modbase = 0;
|
||||
|
||||
#if GRUB_KERNEL_PRELOAD_SPACE_REUSABLE
|
||||
grub_mm_init_region ((void *) modstart, modend - modstart);
|
||||
#else
|
||||
(void) modstart;
|
||||
(void) modend;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The main routine. */
|
||||
void __attribute__ ((noreturn))
|
||||
grub_main (void)
|
||||
{
|
||||
/* First of all, initialize the machine. */
|
||||
grub_machine_init ();
|
||||
|
||||
grub_boot_time ("After machine init.");
|
||||
|
||||
/* Hello. */
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
|
||||
//grub_printf ("Welcome to GRUB!\n\n");
|
||||
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
|
||||
|
||||
grub_load_config ();
|
||||
|
||||
grub_boot_time ("Before loading embedded modules.");
|
||||
|
||||
/* Load pre-loaded modules and free the space. */
|
||||
grub_register_exported_symbols ();
|
||||
#ifdef GRUB_LINKER_HAVE_INIT
|
||||
grub_arch_dl_init_linker ();
|
||||
#endif
|
||||
grub_load_modules ();
|
||||
|
||||
grub_boot_time ("After loading embedded modules.");
|
||||
|
||||
/* It is better to set the root device as soon as possible,
|
||||
for convenience. */
|
||||
grub_set_prefix_and_root ();
|
||||
grub_env_export ("root");
|
||||
grub_env_export ("prefix");
|
||||
|
||||
/* Reclaim space used for modules. */
|
||||
reclaim_module_space ();
|
||||
|
||||
grub_boot_time ("After reclaiming module space.");
|
||||
|
||||
grub_register_core_commands ();
|
||||
|
||||
grub_boot_time ("Before execution of embedded config.");
|
||||
|
||||
if (load_config)
|
||||
grub_parser_execute (load_config);
|
||||
|
||||
grub_boot_time ("After execution of embedded config. Attempt to go to normal mode");
|
||||
|
||||
grub_load_normal_mode ();
|
||||
grub_rescue_run ();
|
||||
}
|
118
GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c
Normal file
118
GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/* cmdline.c - linux command line handling */
|
||||
/*
|
||||
* 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/lib/cmdline.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
static unsigned int check_arg (char *c, int *has_space)
|
||||
{
|
||||
int space = 0;
|
||||
unsigned int size = 0;
|
||||
|
||||
while (*c)
|
||||
{
|
||||
if (*c == '\\' || *c == '\'' || *c == '"')
|
||||
size++;
|
||||
else if (*c == ' ')
|
||||
space = 1;
|
||||
|
||||
size++;
|
||||
c++;
|
||||
}
|
||||
|
||||
if (space)
|
||||
size += 2;
|
||||
|
||||
if (has_space)
|
||||
*has_space = space;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned int grub_loader_cmdline_size (int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
unsigned int size = 0;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
size += check_arg (argv[i], 0);
|
||||
size++; /* Separator space or NULL. */
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_create_loader_cmdline (int argc, char *argv[], char *buf,
|
||||
grub_size_t size, enum grub_verify_string_type type)
|
||||
{
|
||||
int i, space;
|
||||
unsigned int arg_size;
|
||||
char *c, *orig_buf = buf;
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
c = argv[i];
|
||||
arg_size = check_arg(argv[i], &space);
|
||||
arg_size++; /* Separator space or NULL. */
|
||||
|
||||
if (size < arg_size)
|
||||
break;
|
||||
|
||||
size -= arg_size;
|
||||
|
||||
if (space)
|
||||
*buf++ = '"';
|
||||
|
||||
while (*c)
|
||||
{
|
||||
if (*c == '\\' && *(c+1) == 'x' &&
|
||||
grub_isxdigit(*(c+2)) && grub_isxdigit(*(c+3)))
|
||||
{
|
||||
*buf++ = *c++;
|
||||
*buf++ = *c++;
|
||||
*buf++ = *c++;
|
||||
*buf++ = *c++;
|
||||
continue;
|
||||
}
|
||||
else if (*c == '\\' || *c == '\'' || *c == '"')
|
||||
*buf++ = '\\';
|
||||
|
||||
*buf++ = *c;
|
||||
c++;
|
||||
}
|
||||
|
||||
if (space)
|
||||
*buf++ = '"';
|
||||
|
||||
*buf++ = ' ';
|
||||
}
|
||||
|
||||
/* Replace last space with null. */
|
||||
if (i)
|
||||
buf--;
|
||||
|
||||
*buf = 0;
|
||||
|
||||
return grub_verify_string (orig_buf, type);
|
||||
}
|
428
GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c
Normal file
428
GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c
Normal file
@@ -0,0 +1,428 @@
|
||||
/* chainloader.c - boot another boot loader */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2004,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/>.
|
||||
*/
|
||||
|
||||
/* TODO: support load options. */
|
||||
|
||||
#include <grub/loader.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/charset.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/disk.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/net.h>
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
#include <grub/macho.h>
|
||||
#include <grub/i386/macho.h>
|
||||
#endif
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static grub_dl_t my_mod;
|
||||
|
||||
static grub_efi_physical_address_t address;
|
||||
static grub_efi_uintn_t pages;
|
||||
static grub_efi_device_path_t *file_path;
|
||||
static grub_efi_handle_t image_handle;
|
||||
static grub_efi_char16_t *cmdline;
|
||||
|
||||
static grub_err_t
|
||||
grub_chainloader_unload (void)
|
||||
{
|
||||
grub_efi_boot_services_t *b;
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
efi_call_1 (b->unload_image, image_handle);
|
||||
efi_call_2 (b->free_pages, address, pages);
|
||||
|
||||
grub_free (file_path);
|
||||
grub_free (cmdline);
|
||||
cmdline = 0;
|
||||
file_path = 0;
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_chainloader_boot (void)
|
||||
{
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_uintn_t exit_data_size;
|
||||
grub_efi_char16_t *exit_data = NULL;
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
if (exit_data)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = grub_malloc (exit_data_size * 4 + 1);
|
||||
if (buf)
|
||||
{
|
||||
*grub_utf16_to_utf8 ((grub_uint8_t *) buf,
|
||||
exit_data, exit_data_size) = 0;
|
||||
|
||||
grub_error (GRUB_ERR_BAD_OS, buf);
|
||||
grub_free (buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
grub_error (GRUB_ERR_BAD_OS, "unknown error");
|
||||
}
|
||||
|
||||
if (exit_data)
|
||||
efi_call_1 (b->free_pool, exit_data);
|
||||
|
||||
grub_loader_unset ();
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_file_path (grub_efi_file_path_device_path_t *fp,
|
||||
const char *str, grub_efi_uint16_t len)
|
||||
{
|
||||
grub_efi_char16_t *p, *path_name;
|
||||
grub_efi_uint16_t size;
|
||||
|
||||
fp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
|
||||
fp->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
|
||||
|
||||
path_name = grub_malloc (len * GRUB_MAX_UTF16_PER_UTF8 * sizeof (*path_name));
|
||||
if (!path_name)
|
||||
return;
|
||||
|
||||
size = grub_utf8_to_utf16 (path_name, len * GRUB_MAX_UTF16_PER_UTF8,
|
||||
(const grub_uint8_t *) str, len, 0);
|
||||
for (p = path_name; p < path_name + size; p++)
|
||||
if (*p == '/')
|
||||
*p = '\\';
|
||||
|
||||
grub_memcpy (fp->path_name, path_name, size * sizeof (*fp->path_name));
|
||||
/* File Path is NULL terminated */
|
||||
fp->path_name[size++] = '\0';
|
||||
fp->header.length = size * sizeof (grub_efi_char16_t) + sizeof (*fp);
|
||||
grub_free (path_name);
|
||||
}
|
||||
|
||||
static grub_efi_device_path_t *
|
||||
make_file_path (grub_efi_device_path_t *dp, const char *filename)
|
||||
{
|
||||
char *dir_start;
|
||||
char *dir_end;
|
||||
grub_size_t size;
|
||||
grub_efi_device_path_t *d;
|
||||
|
||||
dir_start = grub_strchr (filename, ')');
|
||||
if (! dir_start)
|
||||
dir_start = (char *) filename;
|
||||
else
|
||||
dir_start++;
|
||||
|
||||
dir_end = grub_strrchr (dir_start, '/');
|
||||
if (! dir_end)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILENAME, "invalid EFI file path");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
d = dp;
|
||||
while (1)
|
||||
{
|
||||
size += GRUB_EFI_DEVICE_PATH_LENGTH (d);
|
||||
if ((GRUB_EFI_END_ENTIRE_DEVICE_PATH (d)))
|
||||
break;
|
||||
d = GRUB_EFI_NEXT_DEVICE_PATH (d);
|
||||
}
|
||||
|
||||
/* File Path is NULL terminated. Allocate space for 2 extra characters */
|
||||
/* FIXME why we split path in two components? */
|
||||
file_path = grub_malloc (size
|
||||
+ ((grub_strlen (dir_start) + 2)
|
||||
* GRUB_MAX_UTF16_PER_UTF8
|
||||
* sizeof (grub_efi_char16_t))
|
||||
+ sizeof (grub_efi_file_path_device_path_t) * 2);
|
||||
if (! file_path)
|
||||
return 0;
|
||||
|
||||
grub_memcpy (file_path, dp, size);
|
||||
|
||||
/* Fill the file path for the directory. */
|
||||
d = (grub_efi_device_path_t *) ((char *) file_path
|
||||
+ ((char *) d - (char *) dp));
|
||||
//grub_efi_print_device_path (d);
|
||||
copy_file_path ((grub_efi_file_path_device_path_t *) d,
|
||||
dir_start, dir_end - dir_start);
|
||||
|
||||
/* Fill the file path for the file. */
|
||||
d = GRUB_EFI_NEXT_DEVICE_PATH (d);
|
||||
copy_file_path ((grub_efi_file_path_device_path_t *) d,
|
||||
dir_end + 1, grub_strlen (dir_end + 1));
|
||||
|
||||
/* Fill the end of device path nodes. */
|
||||
d = GRUB_EFI_NEXT_DEVICE_PATH (d);
|
||||
d->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
|
||||
d->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
|
||||
d->length = sizeof (*d);
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file = 0;
|
||||
grub_ssize_t size;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_boot_services_t *b;
|
||||
grub_device_t dev = 0;
|
||||
grub_efi_device_path_t *dp = 0;
|
||||
grub_efi_loaded_image_t *loaded_image;
|
||||
char *filename;
|
||||
void *boot_image = 0;
|
||||
grub_efi_handle_t dev_handle = 0;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
filename = argv[0];
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
/* Initialize some global variables. */
|
||||
address = 0;
|
||||
image_handle = 0;
|
||||
file_path = 0;
|
||||
|
||||
b = grub_efi_system_table->boot_services;
|
||||
|
||||
file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE);
|
||||
if (! file)
|
||||
goto fail;
|
||||
|
||||
/* Get the root device's device path. */
|
||||
dev = grub_device_open (0);
|
||||
if (! dev)
|
||||
goto fail;
|
||||
|
||||
if (dev->disk)
|
||||
dev_handle = grub_efidisk_get_device_handle (dev->disk);
|
||||
else if (dev->net && dev->net->server)
|
||||
{
|
||||
grub_net_network_level_address_t addr;
|
||||
struct grub_net_network_level_interface *inf;
|
||||
grub_net_network_level_address_t gateway;
|
||||
grub_err_t err;
|
||||
|
||||
err = grub_net_resolve_address (dev->net->server, &addr);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = grub_net_route_address (addr, &gateway, &inf);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
dev_handle = grub_efinet_get_device_handle (inf->card);
|
||||
}
|
||||
|
||||
if (dev_handle)
|
||||
dp = grub_efi_get_device_path (dev_handle);
|
||||
|
||||
if (! dp)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_DEVICE, "not a valid root device");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
file_path = make_file_path (dp, filename);
|
||||
if (! file_path)
|
||||
goto fail;
|
||||
|
||||
//grub_printf ("file path: ");
|
||||
//grub_efi_print_device_path (file_path);
|
||||
|
||||
size = grub_file_size (file);
|
||||
if (!size)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
filename);
|
||||
goto fail;
|
||||
}
|
||||
pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
|
||||
|
||||
status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
|
||||
GRUB_EFI_LOADER_CODE,
|
||||
pages, &address);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
grub_dprintf ("chain", "Failed to allocate %u pages\n",
|
||||
(unsigned int) pages);
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
boot_image = (void *) ((grub_addr_t) address);
|
||||
if (grub_file_read (file, boot_image, size) != size)
|
||||
{
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
filename);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
|
||||
{
|
||||
struct grub_macho_fat_header *head = boot_image;
|
||||
if (head->magic
|
||||
== grub_cpu_to_le32_compile_time (GRUB_MACHO_FAT_EFI_MAGIC))
|
||||
{
|
||||
grub_uint32_t i;
|
||||
struct grub_macho_fat_arch *archs
|
||||
= (struct grub_macho_fat_arch *) (head + 1);
|
||||
for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++)
|
||||
{
|
||||
if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype))
|
||||
break;
|
||||
}
|
||||
if (i == grub_cpu_to_le32 (head->nfat_arch))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "no compatible arch found");
|
||||
goto fail;
|
||||
}
|
||||
if (grub_cpu_to_le32 (archs[i].offset)
|
||||
> ~grub_cpu_to_le32 (archs[i].size)
|
||||
|| grub_cpu_to_le32 (archs[i].offset)
|
||||
+ grub_cpu_to_le32 (archs[i].size)
|
||||
> (grub_size_t) size)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
filename);
|
||||
goto fail;
|
||||
}
|
||||
boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset);
|
||||
size = grub_cpu_to_le32 (archs[i].size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
|
||||
boot_image, size,
|
||||
&image_handle);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
if (status == GRUB_EFI_OUT_OF_RESOURCES)
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
|
||||
else
|
||||
grub_error (GRUB_ERR_BAD_OS, "cannot load image");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* LoadImage does not set a device handler when the image is
|
||||
loaded from memory, so it is necessary to set it explicitly here.
|
||||
This is a mess. */
|
||||
loaded_image = grub_efi_get_loaded_image (image_handle);
|
||||
if (! loaded_image)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
|
||||
goto fail;
|
||||
}
|
||||
loaded_image->device_handle = dev_handle;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
int i, len;
|
||||
grub_efi_char16_t *p16;
|
||||
|
||||
for (i = 1, len = 0; i < argc; i++)
|
||||
len += grub_strlen (argv[i]) + 1;
|
||||
|
||||
len *= sizeof (grub_efi_char16_t);
|
||||
cmdline = p16 = grub_malloc (len);
|
||||
if (! cmdline)
|
||||
goto fail;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
char *p8;
|
||||
|
||||
p8 = argv[i];
|
||||
while (*p8)
|
||||
*(p16++) = *(p8++);
|
||||
|
||||
*(p16++) = ' ';
|
||||
}
|
||||
*(--p16) = 0;
|
||||
|
||||
loaded_image->load_options = cmdline;
|
||||
loaded_image->load_options_size = len;
|
||||
}
|
||||
|
||||
grub_file_close (file);
|
||||
grub_device_close (dev);
|
||||
|
||||
grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
||||
if (file)
|
||||
grub_file_close (file);
|
||||
|
||||
grub_free (file_path);
|
||||
|
||||
if (address)
|
||||
efi_call_2 (b->free_pages, address, pages);
|
||||
|
||||
grub_dl_unref (my_mod);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT(chainloader)
|
||||
{
|
||||
cmd = grub_register_command ("chainloader", grub_cmd_chainloader,
|
||||
0, N_("Load another boot loader."));
|
||||
my_mod = mod;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(chainloader)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
}
|
214
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c
Normal file
214
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/* env.c - Environment variables */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/env.h>
|
||||
#include <grub/env_private.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
struct menu_pointer
|
||||
{
|
||||
grub_menu_t menu;
|
||||
struct menu_pointer *prev;
|
||||
};
|
||||
|
||||
static struct menu_pointer initial_menu;
|
||||
static struct menu_pointer *current_menu = &initial_menu;
|
||||
|
||||
void
|
||||
grub_env_unset_menu (void)
|
||||
{
|
||||
current_menu->menu = NULL;
|
||||
}
|
||||
|
||||
grub_menu_t
|
||||
grub_env_get_menu (void)
|
||||
{
|
||||
return current_menu->menu;
|
||||
}
|
||||
|
||||
void
|
||||
grub_env_set_menu (grub_menu_t nmenu)
|
||||
{
|
||||
current_menu->menu = nmenu;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_env_new_context (int export_all)
|
||||
{
|
||||
struct grub_env_context *context;
|
||||
int i;
|
||||
struct menu_pointer *menu;
|
||||
|
||||
context = grub_zalloc (sizeof (*context));
|
||||
if (! context)
|
||||
return grub_errno;
|
||||
menu = grub_zalloc (sizeof (*menu));
|
||||
if (! menu)
|
||||
{
|
||||
grub_free (context);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
context->prev = grub_current_context;
|
||||
grub_current_context = context;
|
||||
|
||||
menu->prev = current_menu;
|
||||
current_menu = menu;
|
||||
|
||||
/* Copy exported variables. */
|
||||
for (i = 0; i < HASHSZ; i++)
|
||||
{
|
||||
struct grub_env_var *var;
|
||||
|
||||
for (var = context->prev->vars[i]; var; var = var->next)
|
||||
if (var->global || export_all)
|
||||
{
|
||||
if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_env_context_close ();
|
||||
return grub_errno;
|
||||
}
|
||||
grub_env_export (var->name);
|
||||
grub_register_variable_hook (var->name, var->read_hook, var->write_hook);
|
||||
}
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_env_context_open (void)
|
||||
{
|
||||
return grub_env_new_context (1);
|
||||
}
|
||||
|
||||
int grub_extractor_level = 0;
|
||||
|
||||
grub_err_t
|
||||
grub_env_extractor_open (int source)
|
||||
{
|
||||
grub_extractor_level++;
|
||||
return grub_env_new_context (source);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_env_context_close (void)
|
||||
{
|
||||
struct grub_env_context *context;
|
||||
int i;
|
||||
struct menu_pointer *menu;
|
||||
|
||||
if (! grub_current_context->prev)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"cannot close the initial context");
|
||||
|
||||
/* Free the variables associated with this context. */
|
||||
for (i = 0; i < HASHSZ; i++)
|
||||
{
|
||||
struct grub_env_var *p, *q;
|
||||
|
||||
for (p = grub_current_context->vars[i]; p; p = q)
|
||||
{
|
||||
q = p->next;
|
||||
grub_free (p->name);
|
||||
grub_free (p->value);
|
||||
grub_free (p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the previous context. */
|
||||
context = grub_current_context->prev;
|
||||
grub_free (grub_current_context);
|
||||
grub_current_context = context;
|
||||
|
||||
menu = current_menu->prev;
|
||||
if (current_menu->menu)
|
||||
grub_normal_free_menu (current_menu->menu);
|
||||
grub_free (current_menu);
|
||||
current_menu = menu;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_env_extractor_close (int source)
|
||||
{
|
||||
grub_menu_t menu = NULL;
|
||||
grub_menu_entry_t *last;
|
||||
grub_err_t err;
|
||||
|
||||
if (source)
|
||||
{
|
||||
menu = grub_env_get_menu ();
|
||||
grub_env_unset_menu ();
|
||||
}
|
||||
err = grub_env_context_close ();
|
||||
|
||||
if (source && menu)
|
||||
{
|
||||
grub_menu_t menu2;
|
||||
menu2 = grub_env_get_menu ();
|
||||
|
||||
last = &menu2->entry_list;
|
||||
while (*last)
|
||||
last = &(*last)->next;
|
||||
|
||||
*last = menu->entry_list;
|
||||
menu2->size += menu->size;
|
||||
}
|
||||
|
||||
grub_extractor_level--;
|
||||
return err;
|
||||
}
|
||||
|
||||
static grub_command_t export_cmd;
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_export (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc < 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("one argument expected"));
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
grub_env_export (args[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_context_init (void)
|
||||
{
|
||||
export_cmd = grub_register_command ("export", grub_cmd_export,
|
||||
N_("ENVVAR [ENVVAR] ..."),
|
||||
N_("Export variables."));
|
||||
}
|
||||
|
||||
void
|
||||
grub_context_fini (void)
|
||||
{
|
||||
grub_unregister_command (export_cmd);
|
||||
}
|
998
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c
Normal file
998
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c
Normal file
@@ -0,0 +1,998 @@
|
||||
/* menu.c - General supporting functionality for menus. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 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/normal.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/auth.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/script_sh.h>
|
||||
#include <grub/gfxterm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
int g_ventoy_menu_refresh = 0;
|
||||
int g_ventoy_memdisk_mode = 0;
|
||||
int g_ventoy_iso_raw = 0;
|
||||
int g_ventoy_iso_uefi_drv = 0;
|
||||
int g_ventoy_last_entry = 0;
|
||||
|
||||
/* Time to delay after displaying an error message about a default/fallback
|
||||
entry failing to boot. */
|
||||
#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
|
||||
|
||||
grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu,
|
||||
int nested) = NULL;
|
||||
|
||||
enum timeout_style {
|
||||
TIMEOUT_STYLE_MENU,
|
||||
TIMEOUT_STYLE_COUNTDOWN,
|
||||
TIMEOUT_STYLE_HIDDEN
|
||||
};
|
||||
|
||||
struct timeout_style_name {
|
||||
const char *name;
|
||||
enum timeout_style style;
|
||||
} timeout_style_names[] = {
|
||||
{"menu", TIMEOUT_STYLE_MENU},
|
||||
{"countdown", TIMEOUT_STYLE_COUNTDOWN},
|
||||
{"hidden", TIMEOUT_STYLE_HIDDEN},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
/* Wait until the user pushes any key so that the user
|
||||
can see what happened. */
|
||||
void
|
||||
grub_wait_after_message (void)
|
||||
{
|
||||
grub_uint64_t endtime;
|
||||
grub_xputs ("\n");
|
||||
grub_printf_ (N_("Press any key to continue..."));
|
||||
grub_refresh ();
|
||||
|
||||
endtime = grub_get_time_ms () + 10000;
|
||||
|
||||
while (grub_get_time_ms () < endtime
|
||||
&& grub_getkey_noblock () == GRUB_TERM_NO_KEY);
|
||||
|
||||
grub_xputs ("\n");
|
||||
}
|
||||
|
||||
/* Get a menu entry by its index in the entry list. */
|
||||
grub_menu_entry_t
|
||||
grub_menu_get_entry (grub_menu_t menu, int no)
|
||||
{
|
||||
grub_menu_entry_t e;
|
||||
|
||||
for (e = menu->entry_list; e && no > 0; e = e->next, no--)
|
||||
;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/* Get the index of a menu entry associated with a given hotkey, or -1. */
|
||||
static int
|
||||
get_entry_index_by_hotkey (grub_menu_t menu, int hotkey)
|
||||
{
|
||||
grub_menu_entry_t entry;
|
||||
int i;
|
||||
|
||||
for (i = 0, entry = menu->entry_list; i < menu->size;
|
||||
i++, entry = entry->next)
|
||||
if (entry->hotkey == hotkey)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return the timeout style. If the variable "timeout_style" is not set or
|
||||
invalid, default to TIMEOUT_STYLE_MENU. */
|
||||
static enum timeout_style
|
||||
get_timeout_style (void)
|
||||
{
|
||||
const char *val;
|
||||
struct timeout_style_name *style_name;
|
||||
|
||||
val = grub_env_get ("timeout_style");
|
||||
if (!val)
|
||||
return TIMEOUT_STYLE_MENU;
|
||||
|
||||
for (style_name = timeout_style_names; style_name->name; style_name++)
|
||||
if (grub_strcmp (style_name->name, val) == 0)
|
||||
return style_name->style;
|
||||
|
||||
return TIMEOUT_STYLE_MENU;
|
||||
}
|
||||
|
||||
/* Return the current timeout. If the variable "timeout" is not set or
|
||||
invalid, return -1. */
|
||||
int
|
||||
grub_menu_get_timeout (void)
|
||||
{
|
||||
const char *val;
|
||||
int timeout;
|
||||
|
||||
val = grub_env_get ("timeout");
|
||||
if (! val)
|
||||
return -1;
|
||||
|
||||
grub_error_push ();
|
||||
|
||||
timeout = (int) grub_strtoul (val, 0, 0);
|
||||
|
||||
/* If the value is invalid, unset the variable. */
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_env_unset ("timeout");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
timeout = -1;
|
||||
}
|
||||
|
||||
grub_error_pop ();
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/* Set current timeout in the variable "timeout". */
|
||||
void
|
||||
grub_menu_set_timeout (int timeout)
|
||||
{
|
||||
/* Ignore TIMEOUT if it is zero, because it will be unset really soon. */
|
||||
if (timeout > 0)
|
||||
{
|
||||
char buf[16];
|
||||
|
||||
grub_snprintf (buf, sizeof (buf), "%d", timeout);
|
||||
grub_env_set ("timeout", buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first entry number from the value of the environment variable NAME,
|
||||
which is a space-separated list of non-negative integers. The entry number
|
||||
which is returned is stripped from the value of NAME. If no entry number
|
||||
can be found, -1 is returned. */
|
||||
static int
|
||||
get_and_remove_first_entry_number (const char *name)
|
||||
{
|
||||
const char *val;
|
||||
char *tail;
|
||||
int entry;
|
||||
|
||||
val = grub_env_get (name);
|
||||
if (! val)
|
||||
return -1;
|
||||
|
||||
grub_error_push ();
|
||||
|
||||
entry = (int) grub_strtoul (val, &tail, 0);
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
/* Skip whitespace to find the next digit. */
|
||||
while (*tail && grub_isspace (*tail))
|
||||
tail++;
|
||||
grub_env_set (name, tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_env_unset (name);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
entry = -1;
|
||||
}
|
||||
|
||||
grub_error_pop ();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Run a menu entry. */
|
||||
static void
|
||||
grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
|
||||
{
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
int errs_before;
|
||||
grub_menu_t menu = NULL;
|
||||
char *optr, *buf, *oldchosen = NULL, *olddefault = NULL;
|
||||
const char *ptr, *chosen, *def;
|
||||
grub_size_t sz = 0;
|
||||
|
||||
if (entry->restricted)
|
||||
err = grub_auth_check_authentication (entry->users);
|
||||
|
||||
if (err)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
errs_before = grub_err_printed_errors;
|
||||
|
||||
chosen = grub_env_get ("chosen");
|
||||
def = grub_env_get ("default");
|
||||
|
||||
if (entry->submenu)
|
||||
{
|
||||
grub_env_context_open ();
|
||||
menu = grub_zalloc (sizeof (*menu));
|
||||
if (! menu)
|
||||
return;
|
||||
grub_env_set_menu (menu);
|
||||
if (auto_boot)
|
||||
grub_env_set ("timeout", "0");
|
||||
}
|
||||
|
||||
for (ptr = entry->id; *ptr; ptr++)
|
||||
sz += (*ptr == '>') ? 2 : 1;
|
||||
if (chosen)
|
||||
{
|
||||
oldchosen = grub_strdup (chosen);
|
||||
if (!oldchosen)
|
||||
grub_print_error ();
|
||||
}
|
||||
if (def)
|
||||
{
|
||||
olddefault = grub_strdup (def);
|
||||
if (!olddefault)
|
||||
grub_print_error ();
|
||||
}
|
||||
sz++;
|
||||
if (chosen)
|
||||
sz += grub_strlen (chosen);
|
||||
sz++;
|
||||
buf = grub_malloc (sz);
|
||||
if (!buf)
|
||||
grub_print_error ();
|
||||
else
|
||||
{
|
||||
optr = buf;
|
||||
if (chosen)
|
||||
{
|
||||
optr = grub_stpcpy (optr, chosen);
|
||||
*optr++ = '>';
|
||||
}
|
||||
for (ptr = entry->id; *ptr; ptr++)
|
||||
{
|
||||
if (*ptr == '>')
|
||||
*optr++ = '>';
|
||||
*optr++ = *ptr;
|
||||
}
|
||||
*optr = 0;
|
||||
grub_env_set ("chosen", buf);
|
||||
grub_env_export ("chosen");
|
||||
grub_free (buf);
|
||||
}
|
||||
|
||||
for (ptr = def; ptr && *ptr; ptr++)
|
||||
{
|
||||
if (ptr[0] == '>' && ptr[1] == '>')
|
||||
{
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
if (ptr[0] == '>')
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr && ptr[0] && ptr[1])
|
||||
grub_env_set ("default", ptr + 1);
|
||||
else
|
||||
grub_env_unset ("default");
|
||||
|
||||
grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args);
|
||||
|
||||
if (errs_before != grub_err_printed_errors)
|
||||
grub_wait_after_message ();
|
||||
|
||||
errs_before = grub_err_printed_errors;
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||
/* Implicit execution of boot, only if something is loaded. */
|
||||
grub_command_execute ("boot", 0, 0);
|
||||
|
||||
if (errs_before != grub_err_printed_errors)
|
||||
grub_wait_after_message ();
|
||||
|
||||
if (entry->submenu)
|
||||
{
|
||||
if (menu && menu->size)
|
||||
{
|
||||
grub_show_menu (menu, 1, auto_boot);
|
||||
grub_normal_free_menu (menu);
|
||||
}
|
||||
grub_env_context_close ();
|
||||
}
|
||||
if (oldchosen)
|
||||
grub_env_set ("chosen", oldchosen);
|
||||
else
|
||||
grub_env_unset ("chosen");
|
||||
if (olddefault)
|
||||
grub_env_set ("default", olddefault);
|
||||
else
|
||||
grub_env_unset ("default");
|
||||
grub_env_unset ("timeout");
|
||||
}
|
||||
|
||||
/* Execute ENTRY from the menu MENU, falling back to entries specified
|
||||
in the environment variable "fallback" if it fails. CALLBACK is a
|
||||
pointer to a struct of function pointers which are used to allow the
|
||||
caller provide feedback to the user. */
|
||||
static void
|
||||
grub_menu_execute_with_fallback (grub_menu_t menu,
|
||||
grub_menu_entry_t entry,
|
||||
int autobooted,
|
||||
grub_menu_execute_callback_t callback,
|
||||
void *callback_data)
|
||||
{
|
||||
int fallback_entry;
|
||||
|
||||
callback->notify_booting (entry, callback_data);
|
||||
|
||||
grub_menu_execute_entry (entry, 1);
|
||||
|
||||
/* Deal with fallback entries. */
|
||||
while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
|
||||
>= 0)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
entry = grub_menu_get_entry (menu, fallback_entry);
|
||||
callback->notify_fallback (entry, callback_data);
|
||||
grub_menu_execute_entry (entry, 1);
|
||||
/* If the function call to execute the entry returns at all, then this is
|
||||
taken to indicate a boot failure. For menu entries that do something
|
||||
other than actually boot an operating system, this could assume
|
||||
incorrectly that something failed. */
|
||||
}
|
||||
|
||||
if (!autobooted)
|
||||
callback->notify_failure (callback_data);
|
||||
}
|
||||
|
||||
static struct grub_menu_viewer *viewers;
|
||||
|
||||
static void
|
||||
menu_set_chosen_entry (int entry)
|
||||
{
|
||||
struct grub_menu_viewer *cur;
|
||||
for (cur = viewers; cur; cur = cur->next)
|
||||
cur->set_chosen_entry (entry, cur->data);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_print_timeout (int timeout)
|
||||
{
|
||||
struct grub_menu_viewer *cur;
|
||||
for (cur = viewers; cur; cur = cur->next)
|
||||
cur->print_timeout (timeout, cur->data);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_fini (void)
|
||||
{
|
||||
struct grub_menu_viewer *cur, *next;
|
||||
for (cur = viewers; cur; cur = next)
|
||||
{
|
||||
next = cur->next;
|
||||
cur->fini (cur->data);
|
||||
grub_free (cur);
|
||||
}
|
||||
viewers = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_init (int entry, grub_menu_t menu, int nested)
|
||||
{
|
||||
struct grub_term_output *term;
|
||||
int gfxmenu = 0;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
if (term->fullscreen)
|
||||
{
|
||||
if (grub_env_get ("theme"))
|
||||
{
|
||||
if (!grub_gfxmenu_try_hook)
|
||||
{
|
||||
grub_dl_load ("gfxmenu");
|
||||
grub_print_error ();
|
||||
}
|
||||
if (grub_gfxmenu_try_hook)
|
||||
{
|
||||
grub_err_t err;
|
||||
err = grub_gfxmenu_try_hook (entry, menu, nested);
|
||||
if(!err)
|
||||
{
|
||||
gfxmenu = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
grub_error (GRUB_ERR_BAD_MODULE,
|
||||
N_("module `%s' isn't loaded"),
|
||||
"gfxmenu");
|
||||
grub_print_error ();
|
||||
grub_wait_after_message ();
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
term->fullscreen ();
|
||||
break;
|
||||
}
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
||||
if (grub_strcmp (term->name, "gfxterm") == 0 && gfxmenu)
|
||||
continue;
|
||||
|
||||
err = grub_menu_try_text (term, entry, menu, nested);
|
||||
if(!err)
|
||||
continue;
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_timeout (void)
|
||||
{
|
||||
struct grub_menu_viewer *cur;
|
||||
for (cur = viewers; cur; cur = cur->next)
|
||||
cur->clear_timeout (cur->data);
|
||||
}
|
||||
|
||||
void
|
||||
grub_menu_register_viewer (struct grub_menu_viewer *viewer)
|
||||
{
|
||||
viewer->next = viewers;
|
||||
viewers = viewer;
|
||||
}
|
||||
|
||||
static int
|
||||
menuentry_eq (const char *id, const char *spec)
|
||||
{
|
||||
const char *ptr1, *ptr2;
|
||||
ptr1 = id;
|
||||
ptr2 = spec;
|
||||
while (1)
|
||||
{
|
||||
if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
|
||||
return 1;
|
||||
if (*ptr2 == '>' && ptr2[1] != '>')
|
||||
return 0;
|
||||
if (*ptr2 == '>')
|
||||
ptr2++;
|
||||
if (*ptr1 != *ptr2)
|
||||
return 0;
|
||||
if (*ptr1 == 0)
|
||||
return 1;
|
||||
ptr1++;
|
||||
ptr2++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the entry number from the variable NAME. */
|
||||
static int
|
||||
get_entry_number (grub_menu_t menu, const char *name)
|
||||
{
|
||||
const char *val;
|
||||
int entry;
|
||||
|
||||
val = grub_env_get (name);
|
||||
if (! val)
|
||||
return -1;
|
||||
|
||||
grub_error_push ();
|
||||
|
||||
entry = (int) grub_strtoul (val, 0, 0);
|
||||
|
||||
if (grub_errno == GRUB_ERR_BAD_NUMBER)
|
||||
{
|
||||
/* See if the variable matches the title of a menu entry. */
|
||||
grub_menu_entry_t e = menu->entry_list;
|
||||
int i;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
for (i = 0; e; i++)
|
||||
{
|
||||
if (menuentry_eq (e->title, val)
|
||||
|| menuentry_eq (e->id, val))
|
||||
{
|
||||
entry = i;
|
||||
break;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
if (! e)
|
||||
entry = -1;
|
||||
}
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
entry = -1;
|
||||
}
|
||||
|
||||
grub_error_pop ();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/* Check whether a second has elapsed since the last tick. If so, adjust
|
||||
the timer and return 1; otherwise, return 0. */
|
||||
static int
|
||||
has_second_elapsed (grub_uint64_t *saved_time)
|
||||
{
|
||||
grub_uint64_t current_time;
|
||||
|
||||
current_time = grub_get_time_ms ();
|
||||
if (current_time - *saved_time >= 1000)
|
||||
{
|
||||
*saved_time = current_time;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
print_countdown (struct grub_term_coordinate *pos, 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);
|
||||
grub_refresh ();
|
||||
}
|
||||
|
||||
#define GRUB_MENU_PAGE_SIZE 10
|
||||
|
||||
/* Show the menu and handle menu entry selection. Returns the menu entry
|
||||
index that should be executed or -1 if no entry should be executed (e.g.,
|
||||
Esc pressed to exit a sub-menu or switching menu viewers).
|
||||
If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
|
||||
entry to be executed is a result of an automatic default selection because
|
||||
of the timeout. */
|
||||
static int
|
||||
run_menu (grub_menu_t menu, int nested, int *auto_boot)
|
||||
{
|
||||
const char *cmdstr;
|
||||
grub_uint64_t saved_time;
|
||||
int default_entry,current_entry;
|
||||
int timeout;
|
||||
enum timeout_style timeout_style;
|
||||
|
||||
default_entry = get_entry_number (menu, "default");
|
||||
|
||||
if (g_ventoy_last_entry >= 0 && g_ventoy_last_entry < menu->size) {
|
||||
default_entry = g_ventoy_last_entry;
|
||||
}
|
||||
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
|
||||
the first entry. */
|
||||
else if (default_entry < 0 || default_entry >= menu->size)
|
||||
default_entry = 0;
|
||||
|
||||
timeout = grub_menu_get_timeout ();
|
||||
if (timeout < 0)
|
||||
/* If there is no timeout, the "countdown" and "hidden" styles result in
|
||||
the system doing nothing and providing no or very little indication
|
||||
why. Technically this is what the user asked for, but it's not very
|
||||
useful and likely to be a source of confusion, so we disallow this. */
|
||||
grub_env_unset ("timeout_style");
|
||||
|
||||
timeout_style = get_timeout_style ();
|
||||
|
||||
if (timeout_style == TIMEOUT_STYLE_COUNTDOWN
|
||||
|| timeout_style == TIMEOUT_STYLE_HIDDEN)
|
||||
{
|
||||
static struct grub_term_coordinate *pos;
|
||||
int entry = -1;
|
||||
|
||||
if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
|
||||
{
|
||||
pos = grub_term_save_pos ();
|
||||
print_countdown (pos, timeout);
|
||||
}
|
||||
|
||||
/* Enter interruptible sleep until Escape or a menu hotkey is pressed,
|
||||
or the timeout expires. */
|
||||
saved_time = grub_get_time_ms ();
|
||||
while (1)
|
||||
{
|
||||
int key;
|
||||
|
||||
key = grub_getkey_noblock ();
|
||||
if (key != GRUB_TERM_NO_KEY)
|
||||
{
|
||||
entry = get_entry_index_by_hotkey (menu, key);
|
||||
if (entry >= 0)
|
||||
break;
|
||||
}
|
||||
if (key == GRUB_TERM_ESC)
|
||||
{
|
||||
timeout = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout > 0 && has_second_elapsed (&saved_time))
|
||||
{
|
||||
timeout--;
|
||||
if (timeout_style == TIMEOUT_STYLE_COUNTDOWN)
|
||||
print_countdown (pos, timeout);
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
/* We will fall through to auto-booting the default entry. */
|
||||
break;
|
||||
}
|
||||
|
||||
grub_env_unset ("timeout");
|
||||
grub_env_unset ("timeout_style");
|
||||
if (entry >= 0)
|
||||
{
|
||||
*auto_boot = 0;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* If timeout is 0, drawing is pointless (and ugly). */
|
||||
if (timeout == 0)
|
||||
{
|
||||
*auto_boot = 1;
|
||||
return default_entry;
|
||||
}
|
||||
|
||||
current_entry = default_entry;
|
||||
|
||||
refresh:
|
||||
menu_init (current_entry, menu, nested);
|
||||
|
||||
/* Initialize the time. */
|
||||
saved_time = grub_get_time_ms ();
|
||||
|
||||
timeout = grub_menu_get_timeout ();
|
||||
|
||||
if (timeout > 0)
|
||||
menu_print_timeout (timeout);
|
||||
else
|
||||
clear_timeout ();
|
||||
|
||||
while (1)
|
||||
{
|
||||
int c;
|
||||
timeout = grub_menu_get_timeout ();
|
||||
|
||||
if (grub_normal_exit_level)
|
||||
return -1;
|
||||
|
||||
if (timeout > 0 && has_second_elapsed (&saved_time))
|
||||
{
|
||||
timeout--;
|
||||
grub_menu_set_timeout (timeout);
|
||||
menu_print_timeout (timeout);
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
grub_env_unset ("timeout");
|
||||
*auto_boot = 1;
|
||||
menu_fini ();
|
||||
return default_entry;
|
||||
}
|
||||
|
||||
c = grub_getkey_noblock ();
|
||||
|
||||
/* Negative values are returned on error. */
|
||||
if ((c != GRUB_TERM_NO_KEY) && (c > 0))
|
||||
{
|
||||
if (timeout >= 0)
|
||||
{
|
||||
grub_env_unset ("timeout");
|
||||
grub_env_unset ("fallback");
|
||||
clear_timeout ();
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case GRUB_TERM_KEY_HOME:
|
||||
case GRUB_TERM_CTRL | 'a':
|
||||
current_entry = 0;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_KEY_END:
|
||||
case GRUB_TERM_CTRL | 'e':
|
||||
current_entry = menu->size - 1;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_KEY_UP:
|
||||
case GRUB_TERM_CTRL | 'p':
|
||||
case '^':
|
||||
if (current_entry > 0)
|
||||
current_entry--;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_CTRL | 'n':
|
||||
case GRUB_TERM_KEY_DOWN:
|
||||
case 'v':
|
||||
if (current_entry < menu->size - 1)
|
||||
current_entry++;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_CTRL | 'g':
|
||||
case GRUB_TERM_KEY_PPAGE:
|
||||
if (current_entry < GRUB_MENU_PAGE_SIZE)
|
||||
current_entry = 0;
|
||||
else
|
||||
current_entry -= GRUB_MENU_PAGE_SIZE;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case GRUB_TERM_CTRL | 'c':
|
||||
case GRUB_TERM_KEY_NPAGE:
|
||||
if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
|
||||
current_entry += GRUB_MENU_PAGE_SIZE;
|
||||
else
|
||||
current_entry = menu->size - 1;
|
||||
menu_set_chosen_entry (current_entry);
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
case '\r':
|
||||
// case GRUB_TERM_KEY_RIGHT:
|
||||
case GRUB_TERM_CTRL | 'f':
|
||||
menu_fini ();
|
||||
*auto_boot = 0;
|
||||
return current_entry;
|
||||
|
||||
case GRUB_TERM_ESC:
|
||||
if (nested)
|
||||
{
|
||||
menu_fini ();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
menu_fini ();
|
||||
grub_cmdline_run (1, 0);
|
||||
goto refresh;
|
||||
|
||||
case 'e':
|
||||
menu_fini ();
|
||||
{
|
||||
grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
|
||||
if (e)
|
||||
grub_menu_entry_run (e);
|
||||
}
|
||||
goto refresh;
|
||||
|
||||
case GRUB_TERM_KEY_F2:
|
||||
cmdstr = grub_env_get("VTOY_F2_CMD");
|
||||
if (cmdstr)
|
||||
{
|
||||
menu_fini ();
|
||||
grub_script_execute_sourcecode(cmdstr);
|
||||
goto refresh;
|
||||
}
|
||||
break;
|
||||
case GRUB_TERM_KEY_F3:
|
||||
cmdstr = grub_env_get("VTOY_F3_CMD");
|
||||
if (cmdstr)
|
||||
{
|
||||
menu_fini ();
|
||||
grub_script_execute_sourcecode(cmdstr);
|
||||
goto refresh;
|
||||
}
|
||||
break;
|
||||
case GRUB_TERM_KEY_F4:
|
||||
cmdstr = grub_env_get("VTOY_F4_CMD");
|
||||
if (cmdstr)
|
||||
{
|
||||
menu_fini ();
|
||||
grub_script_execute_sourcecode(cmdstr);
|
||||
goto refresh;
|
||||
}
|
||||
break;
|
||||
case GRUB_TERM_KEY_F5:
|
||||
cmdstr = grub_env_get("VTOY_F5_CMD");
|
||||
if (cmdstr)
|
||||
{
|
||||
menu_fini ();
|
||||
grub_script_execute_sourcecode(cmdstr);
|
||||
goto refresh;
|
||||
}
|
||||
break;
|
||||
case GRUB_TERM_KEY_F6:
|
||||
cmdstr = grub_env_get("VTOY_F6_CMD");
|
||||
if (cmdstr)
|
||||
{
|
||||
menu_fini ();
|
||||
grub_script_execute_sourcecode(cmdstr);
|
||||
goto refresh;
|
||||
}
|
||||
break;
|
||||
case GRUB_TERM_KEY_F7:
|
||||
cmdstr = grub_env_get("VTOY_F7_CMD");
|
||||
if (cmdstr)
|
||||
{
|
||||
menu_fini ();
|
||||
grub_script_execute_sourcecode(cmdstr);
|
||||
goto refresh;
|
||||
}
|
||||
break;
|
||||
case GRUB_TERM_KEY_F1:
|
||||
menu_fini ();
|
||||
g_ventoy_memdisk_mode = 1 - g_ventoy_memdisk_mode;
|
||||
g_ventoy_menu_refresh = 1;
|
||||
goto refresh;
|
||||
|
||||
case (GRUB_TERM_CTRL | 'i'):
|
||||
menu_fini ();
|
||||
g_ventoy_iso_raw = 1 - g_ventoy_iso_raw;
|
||||
g_ventoy_menu_refresh = 1;
|
||||
goto refresh;
|
||||
|
||||
case (GRUB_TERM_CTRL | 'u'):
|
||||
menu_fini ();
|
||||
g_ventoy_iso_uefi_drv = 1 - g_ventoy_iso_uefi_drv;
|
||||
g_ventoy_menu_refresh = 1;
|
||||
goto refresh;
|
||||
|
||||
default:
|
||||
{
|
||||
int entry;
|
||||
|
||||
entry = get_entry_index_by_hotkey (menu, c);
|
||||
if (entry >= 0)
|
||||
{
|
||||
menu_fini ();
|
||||
*auto_boot = 0;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Never reach here. */
|
||||
}
|
||||
|
||||
/* Callback invoked immediately before a menu entry is executed. */
|
||||
static void
|
||||
notify_booting (grub_menu_entry_t entry,
|
||||
void *userdata __attribute__((unused)))
|
||||
{
|
||||
grub_printf (" ");
|
||||
grub_printf_ (N_("Booting `%s'"), entry->title);
|
||||
grub_printf ("\n\n");
|
||||
}
|
||||
|
||||
/* Callback invoked when a default menu entry executed because of a timeout
|
||||
has failed and an attempt will be made to execute the next fallback
|
||||
entry, ENTRY. */
|
||||
static void
|
||||
notify_fallback (grub_menu_entry_t entry,
|
||||
void *userdata __attribute__((unused)))
|
||||
{
|
||||
grub_printf ("\n ");
|
||||
grub_printf_ (N_("Falling back to `%s'"), entry->title);
|
||||
grub_printf ("\n\n");
|
||||
grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
|
||||
}
|
||||
|
||||
/* Callback invoked when a menu entry has failed and there is no remaining
|
||||
fallback entry to attempt. */
|
||||
static void
|
||||
notify_execution_failure (void *userdata __attribute__((unused)))
|
||||
{
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
grub_printf ("\n ");
|
||||
grub_printf_ (N_("Failed to boot both default and fallback entries.\n"));
|
||||
grub_wait_after_message ();
|
||||
}
|
||||
|
||||
/* Callbacks used by the text menu to provide user feedback when menu entries
|
||||
are executed. */
|
||||
static struct grub_menu_execute_callback execution_callback =
|
||||
{
|
||||
.notify_booting = notify_booting,
|
||||
.notify_fallback = notify_fallback,
|
||||
.notify_failure = notify_execution_failure
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
show_menu (grub_menu_t menu, int nested, int autobooted)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int boot_entry;
|
||||
grub_menu_entry_t e;
|
||||
int auto_boot;
|
||||
|
||||
boot_entry = run_menu (menu, nested, &auto_boot);
|
||||
if (boot_entry < 0)
|
||||
break;
|
||||
|
||||
g_ventoy_last_entry = boot_entry;
|
||||
|
||||
e = grub_menu_get_entry (menu, boot_entry);
|
||||
if (! e)
|
||||
continue; /* Menu is empty. */
|
||||
|
||||
grub_cls ();
|
||||
|
||||
if (auto_boot)
|
||||
grub_menu_execute_with_fallback (menu, e, autobooted,
|
||||
&execution_callback, 0);
|
||||
else
|
||||
grub_menu_execute_entry (e, 0);
|
||||
if (autobooted)
|
||||
break;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_show_menu (grub_menu_t menu, int nested, int autoboot)
|
||||
{
|
||||
grub_err_t err1, err2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
err1 = show_menu (menu, nested, autoboot);
|
||||
autoboot = 0;
|
||||
grub_print_error ();
|
||||
|
||||
if (grub_normal_exit_level)
|
||||
break;
|
||||
|
||||
err2 = grub_auth_check_authentication (NULL);
|
||||
if (err2)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return err1;
|
||||
}
|
605
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c
Normal file
605
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c
Normal file
@@ -0,0 +1,605 @@
|
||||
/* menu_text.c - Basic text menu implementation. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/normal.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/charset.h>
|
||||
|
||||
static grub_uint8_t grub_color_menu_normal;
|
||||
static grub_uint8_t grub_color_menu_highlight;
|
||||
|
||||
struct menu_viewer_data
|
||||
{
|
||||
int first, offset;
|
||||
struct grub_term_screen_geometry geo;
|
||||
enum {
|
||||
TIMEOUT_UNKNOWN,
|
||||
TIMEOUT_NORMAL,
|
||||
TIMEOUT_TERSE,
|
||||
TIMEOUT_TERSE_NO_MARGIN
|
||||
} timeout_msg;
|
||||
grub_menu_t menu;
|
||||
struct grub_term_output *term;
|
||||
};
|
||||
|
||||
static inline int
|
||||
grub_term_cursor_x (const struct grub_term_screen_geometry *geo)
|
||||
{
|
||||
return (geo->first_entry_x + geo->entry_width);
|
||||
}
|
||||
|
||||
grub_size_t
|
||||
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
grub_ssize_t width = 0;
|
||||
|
||||
while (str < last_position)
|
||||
{
|
||||
struct grub_unicode_glyph glyph;
|
||||
glyph.ncomb = 0;
|
||||
str += grub_unicode_aglomerate_comb (str, last_position - str, &glyph);
|
||||
width += grub_term_getcharwidth (term, &glyph);
|
||||
grub_unicode_destroy_glyph (&glyph);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
static int
|
||||
grub_print_message_indented_real (const char *msg, int margin_left,
|
||||
int margin_right,
|
||||
struct grub_term_output *term, int dry_run)
|
||||
{
|
||||
grub_uint32_t *unicode_msg;
|
||||
grub_uint32_t *last_position;
|
||||
grub_size_t msg_len = grub_strlen (msg) + 2;
|
||||
int ret = 0;
|
||||
|
||||
unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t));
|
||||
|
||||
if (!unicode_msg)
|
||||
return 0;
|
||||
|
||||
msg_len = grub_utf8_to_ucs4 (unicode_msg, msg_len,
|
||||
(grub_uint8_t *) msg, -1, 0);
|
||||
|
||||
last_position = unicode_msg + msg_len;
|
||||
*last_position = 0;
|
||||
|
||||
if (dry_run)
|
||||
ret = grub_ucs4_count_lines (unicode_msg, last_position, margin_left,
|
||||
margin_right, term);
|
||||
else
|
||||
grub_print_ucs4_menu (unicode_msg, last_position, margin_left,
|
||||
margin_right, term, 0, -1, 0, 0);
|
||||
|
||||
grub_free (unicode_msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
grub_print_message_indented (const char *msg, int margin_left, int margin_right,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
grub_print_message_indented_real (msg, margin_left, margin_right, term, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo)
|
||||
{
|
||||
int i;
|
||||
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
|
||||
geo->first_entry_y - 1 });
|
||||
grub_putcode (GRUB_UNICODE_CORNER_UL, term);
|
||||
for (i = 0; i < geo->entry_width + 1; i++)
|
||||
grub_putcode (GRUB_UNICODE_HLINE, term);
|
||||
grub_putcode (GRUB_UNICODE_CORNER_UR, term);
|
||||
|
||||
for (i = 0; i < geo->num_entries; i++)
|
||||
{
|
||||
grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
|
||||
geo->first_entry_y + i });
|
||||
grub_putcode (GRUB_UNICODE_VLINE, term);
|
||||
grub_term_gotoxy (term,
|
||||
(struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1,
|
||||
geo->first_entry_y + i });
|
||||
grub_putcode (GRUB_UNICODE_VLINE, term);
|
||||
}
|
||||
|
||||
grub_term_gotoxy (term,
|
||||
(struct grub_term_coordinate) { geo->first_entry_x - 1,
|
||||
geo->first_entry_y - 1 + geo->num_entries + 1 });
|
||||
grub_putcode (GRUB_UNICODE_CORNER_LL, term);
|
||||
for (i = 0; i < geo->entry_width + 1; i++)
|
||||
grub_putcode (GRUB_UNICODE_HLINE, term);
|
||||
grub_putcode (GRUB_UNICODE_CORNER_LR, term);
|
||||
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_term_gotoxy (term,
|
||||
(struct grub_term_coordinate) { geo->first_entry_x - 1,
|
||||
(geo->first_entry_y - 1 + geo->num_entries
|
||||
+ GRUB_TERM_MARGIN + 1) });
|
||||
}
|
||||
|
||||
static int
|
||||
print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
|
||||
{
|
||||
int ret = 0;
|
||||
grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
if (edit)
|
||||
{
|
||||
ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \
|
||||
supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \
|
||||
command-line or ESC to discard edits and return to the GRUB menu."),
|
||||
STANDARD_MARGIN, STANDARD_MARGIN,
|
||||
term, dry_run);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *msg_translated;
|
||||
|
||||
msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
|
||||
"entry is highlighted."),
|
||||
GRUB_UNICODE_UPARROW,
|
||||
GRUB_UNICODE_DOWNARROW);
|
||||
if (!msg_translated)
|
||||
return 0;
|
||||
ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN,
|
||||
STANDARD_MARGIN, term, dry_run);
|
||||
|
||||
grub_free (msg_translated);
|
||||
|
||||
if (nested)
|
||||
{
|
||||
ret += grub_print_message_indented_real
|
||||
(_("Press enter to boot the selected OS, "
|
||||
"`e' to edit the commands before booting "
|
||||
"or `c' for a command-line. ESC to return previous menu."),
|
||||
STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||||
|
||||
ret += grub_print_message_indented_real(grub_env_get("VTOY_TEXT_MENU_VER"),
|
||||
STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||||
|
||||
ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||||
ret += grub_print_message_indented_real(grub_env_get("VTOY_HOTKEY_TIP"),
|
||||
STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
print_entry (int y, int highlight, grub_menu_entry_t entry,
|
||||
const struct menu_viewer_data *data)
|
||||
{
|
||||
const char *title;
|
||||
grub_size_t title_len;
|
||||
grub_ssize_t len;
|
||||
grub_uint32_t *unicode_title;
|
||||
grub_ssize_t i;
|
||||
grub_uint8_t old_color_normal, old_color_highlight;
|
||||
|
||||
title = entry ? entry->title : "";
|
||||
title_len = grub_strlen (title);
|
||||
unicode_title = grub_malloc (title_len * sizeof (*unicode_title));
|
||||
if (! unicode_title)
|
||||
/* XXX How to show this error? */
|
||||
return;
|
||||
|
||||
len = grub_utf8_to_ucs4 (unicode_title, title_len,
|
||||
(grub_uint8_t *) title, -1, 0);
|
||||
if (len < 0)
|
||||
{
|
||||
/* It is an invalid sequence. */
|
||||
grub_free (unicode_title);
|
||||
return;
|
||||
}
|
||||
|
||||
old_color_normal = grub_term_normal_color;
|
||||
old_color_highlight = grub_term_highlight_color;
|
||||
grub_term_normal_color = grub_color_menu_normal;
|
||||
grub_term_highlight_color = grub_color_menu_highlight;
|
||||
grub_term_setcolorstate (data->term, highlight
|
||||
? GRUB_TERM_COLOR_HIGHLIGHT
|
||||
: GRUB_TERM_COLOR_NORMAL);
|
||||
|
||||
grub_term_gotoxy (data->term, (struct grub_term_coordinate) {
|
||||
data->geo.first_entry_x, y });
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (unicode_title[i] == '\n' || unicode_title[i] == '\b'
|
||||
|| unicode_title[i] == '\r' || unicode_title[i] == '\e')
|
||||
unicode_title[i] = ' ';
|
||||
|
||||
if (data->geo.num_entries > 1)
|
||||
grub_putcode (highlight ? '*' : ' ', data->term);
|
||||
|
||||
grub_print_ucs4_menu (unicode_title,
|
||||
unicode_title + len,
|
||||
0,
|
||||
data->geo.right_margin,
|
||||
data->term, 0, 1,
|
||||
GRUB_UNICODE_RIGHTARROW, 0);
|
||||
|
||||
grub_term_setcolorstate (data->term, GRUB_TERM_COLOR_NORMAL);
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) {
|
||||
grub_term_cursor_x (&data->geo), y });
|
||||
|
||||
grub_term_normal_color = old_color_normal;
|
||||
grub_term_highlight_color = old_color_highlight;
|
||||
|
||||
grub_term_setcolorstate (data->term, GRUB_TERM_COLOR_NORMAL);
|
||||
grub_free (unicode_title);
|
||||
}
|
||||
|
||||
static void
|
||||
print_entries (grub_menu_t menu, const struct menu_viewer_data *data)
|
||||
{
|
||||
grub_menu_entry_t e;
|
||||
int i;
|
||||
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) {
|
||||
data->geo.first_entry_x + data->geo.entry_width
|
||||
+ data->geo.border + 1,
|
||||
data->geo.first_entry_y });
|
||||
|
||||
if (data->geo.num_entries != 1)
|
||||
{
|
||||
if (data->first)
|
||||
grub_putcode (GRUB_UNICODE_UPARROW, data->term);
|
||||
else
|
||||
grub_putcode (' ', data->term);
|
||||
}
|
||||
e = grub_menu_get_entry (menu, data->first);
|
||||
|
||||
for (i = 0; i < data->geo.num_entries; i++)
|
||||
{
|
||||
print_entry (data->geo.first_entry_y + i, data->offset == i,
|
||||
e, data);
|
||||
if (e)
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) { data->geo.first_entry_x + data->geo.entry_width
|
||||
+ data->geo.border + 1,
|
||||
data->geo.first_entry_y + data->geo.num_entries - 1 });
|
||||
if (data->geo.num_entries == 1)
|
||||
{
|
||||
if (data->first && e)
|
||||
grub_putcode (GRUB_UNICODE_UPDOWNARROW, data->term);
|
||||
else if (data->first)
|
||||
grub_putcode (GRUB_UNICODE_UPARROW, data->term);
|
||||
else if (e)
|
||||
grub_putcode (GRUB_UNICODE_DOWNARROW, data->term);
|
||||
else
|
||||
grub_putcode (' ', data->term);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e)
|
||||
grub_putcode (GRUB_UNICODE_DOWNARROW, data->term);
|
||||
else
|
||||
grub_putcode (' ', data->term);
|
||||
}
|
||||
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) { grub_term_cursor_x (&data->geo),
|
||||
data->geo.first_entry_y + data->offset });
|
||||
}
|
||||
|
||||
/* Initialize the screen. If NESTED is non-zero, assume that this menu
|
||||
is run from another menu or a command-line. If EDIT is non-zero, show
|
||||
a message for the menu entry editor. */
|
||||
void
|
||||
grub_menu_init_page (int nested, int edit,
|
||||
struct grub_term_screen_geometry *geo,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
grub_uint8_t old_color_normal, old_color_highlight;
|
||||
int msg_num_lines;
|
||||
int bottom_message = 1;
|
||||
int empty_lines = 1;
|
||||
int version_msg = 1;
|
||||
|
||||
geo->border = 1;
|
||||
geo->first_entry_x = 1 /* margin */ + 1 /* border */;
|
||||
geo->entry_width = grub_term_width (term) - 5;
|
||||
|
||||
geo->first_entry_y = 2 /* two empty lines*/
|
||||
+ 1 /* GNU GRUB version text */ + 1 /* top border */;
|
||||
|
||||
geo->timeout_lines = 2;
|
||||
|
||||
/* 3 lines for timeout message and bottom margin. 2 lines for the border. */
|
||||
geo->num_entries = grub_term_height (term) - geo->first_entry_y
|
||||
- 1 /* bottom border */
|
||||
- 1 /* empty line before info message*/
|
||||
- geo->timeout_lines /* timeout */
|
||||
- 1 /* empty final line */;
|
||||
msg_num_lines = print_message (nested, edit, term, 1);
|
||||
if (geo->num_entries - msg_num_lines < 3
|
||||
|| geo->entry_width < 10)
|
||||
{
|
||||
geo->num_entries += 4;
|
||||
geo->first_entry_y -= 2;
|
||||
empty_lines = 0;
|
||||
geo->first_entry_x -= 1;
|
||||
geo->entry_width += 1;
|
||||
}
|
||||
if (geo->num_entries - msg_num_lines < 3
|
||||
|| geo->entry_width < 10)
|
||||
{
|
||||
geo->num_entries += 2;
|
||||
geo->first_entry_y -= 1;
|
||||
geo->first_entry_x -= 1;
|
||||
geo->entry_width += 2;
|
||||
geo->border = 0;
|
||||
}
|
||||
|
||||
if (geo->entry_width <= 0)
|
||||
geo->entry_width = 1;
|
||||
|
||||
if (geo->num_entries - msg_num_lines < 3
|
||||
&& geo->timeout_lines == 2)
|
||||
{
|
||||
geo->timeout_lines = 1;
|
||||
geo->num_entries++;
|
||||
}
|
||||
|
||||
if (geo->num_entries - msg_num_lines < 3)
|
||||
{
|
||||
geo->num_entries += 1;
|
||||
geo->first_entry_y -= 1;
|
||||
version_msg = 0;
|
||||
}
|
||||
|
||||
if (geo->num_entries - msg_num_lines >= 2)
|
||||
geo->num_entries -= msg_num_lines;
|
||||
else
|
||||
bottom_message = 0;
|
||||
|
||||
/* By default, use the same colors for the menu. */
|
||||
old_color_normal = grub_term_normal_color;
|
||||
old_color_highlight = grub_term_highlight_color;
|
||||
grub_color_menu_normal = grub_term_normal_color;
|
||||
grub_color_menu_highlight = grub_term_highlight_color;
|
||||
|
||||
/* Then give user a chance to replace them. */
|
||||
grub_parse_color_name_pair (&grub_color_menu_normal,
|
||||
grub_env_get ("menu_color_normal"));
|
||||
grub_parse_color_name_pair (&grub_color_menu_highlight,
|
||||
grub_env_get ("menu_color_highlight"));
|
||||
|
||||
if (version_msg)
|
||||
grub_normal_init_page (term, empty_lines);
|
||||
else
|
||||
grub_term_cls (term);
|
||||
|
||||
grub_term_normal_color = grub_color_menu_normal;
|
||||
grub_term_highlight_color = grub_color_menu_highlight;
|
||||
if (geo->border)
|
||||
draw_border (term, geo);
|
||||
grub_term_normal_color = old_color_normal;
|
||||
grub_term_highlight_color = old_color_highlight;
|
||||
geo->timeout_y = geo->first_entry_y + geo->num_entries
|
||||
+ geo->border + empty_lines;
|
||||
if (bottom_message)
|
||||
{
|
||||
grub_term_gotoxy (term,
|
||||
(struct grub_term_coordinate) { GRUB_TERM_MARGIN,
|
||||
geo->timeout_y });
|
||||
|
||||
print_message (nested, edit, term, 0);
|
||||
geo->timeout_y += msg_num_lines;
|
||||
}
|
||||
geo->right_margin = grub_term_width (term)
|
||||
- geo->first_entry_x
|
||||
- geo->entry_width - 1;
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_print_timeout (int timeout, void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
char *msg_translated = 0;
|
||||
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) { 0, data->geo.timeout_y });
|
||||
|
||||
if (data->timeout_msg == TIMEOUT_TERSE
|
||||
|| data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN)
|
||||
msg_translated = grub_xasprintf (_("%ds"), timeout);
|
||||
else
|
||||
msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout);
|
||||
if (!msg_translated)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->timeout_msg == TIMEOUT_UNKNOWN)
|
||||
{
|
||||
data->timeout_msg = grub_print_message_indented_real (msg_translated,
|
||||
3, 1, data->term, 1)
|
||||
<= data->geo.timeout_lines ? TIMEOUT_NORMAL : TIMEOUT_TERSE;
|
||||
if (data->timeout_msg == TIMEOUT_TERSE)
|
||||
{
|
||||
grub_free (msg_translated);
|
||||
msg_translated = grub_xasprintf (_("%ds"), timeout);
|
||||
if (grub_term_width (data->term) < 10)
|
||||
data->timeout_msg = TIMEOUT_TERSE_NO_MARGIN;
|
||||
}
|
||||
}
|
||||
|
||||
grub_print_message_indented (msg_translated,
|
||||
data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN ? 0 : 3,
|
||||
data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN ? 0 : 1,
|
||||
data->term);
|
||||
grub_free (msg_translated);
|
||||
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) {
|
||||
grub_term_cursor_x (&data->geo),
|
||||
data->geo.first_entry_y + data->offset });
|
||||
grub_term_refresh (data->term);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_set_chosen_entry (int entry, void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
int oldoffset = data->offset;
|
||||
int complete_redraw = 0;
|
||||
|
||||
data->offset = entry - data->first;
|
||||
if (data->offset > data->geo.num_entries - 1)
|
||||
{
|
||||
data->first = entry - (data->geo.num_entries - 1);
|
||||
data->offset = data->geo.num_entries - 1;
|
||||
complete_redraw = 1;
|
||||
}
|
||||
if (data->offset < 0)
|
||||
{
|
||||
data->offset = 0;
|
||||
data->first = entry;
|
||||
complete_redraw = 1;
|
||||
}
|
||||
if (complete_redraw)
|
||||
print_entries (data->menu, data);
|
||||
else
|
||||
{
|
||||
print_entry (data->geo.first_entry_y + oldoffset, 0,
|
||||
grub_menu_get_entry (data->menu, data->first + oldoffset),
|
||||
data);
|
||||
print_entry (data->geo.first_entry_y + data->offset, 1,
|
||||
grub_menu_get_entry (data->menu, data->first + data->offset),
|
||||
data);
|
||||
}
|
||||
grub_term_refresh (data->term);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_fini (void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
|
||||
grub_term_setcursor (data->term, 1);
|
||||
grub_term_cls (data->term);
|
||||
grub_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
menu_text_clear_timeout (void *dataptr)
|
||||
{
|
||||
struct menu_viewer_data *data = dataptr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data->geo.timeout_lines;i++)
|
||||
{
|
||||
grub_term_gotoxy (data->term, (struct grub_term_coordinate) {
|
||||
0, data->geo.timeout_y + i });
|
||||
grub_print_spaces (data->term, grub_term_width (data->term) - 1);
|
||||
}
|
||||
if (data->geo.num_entries <= 5 && !data->geo.border)
|
||||
{
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) {
|
||||
data->geo.first_entry_x + data->geo.entry_width
|
||||
+ data->geo.border + 1,
|
||||
data->geo.first_entry_y + data->geo.num_entries - 1
|
||||
});
|
||||
grub_putcode (' ', data->term);
|
||||
|
||||
data->geo.timeout_lines = 0;
|
||||
data->geo.num_entries++;
|
||||
print_entries (data->menu, data);
|
||||
}
|
||||
grub_term_gotoxy (data->term,
|
||||
(struct grub_term_coordinate) {
|
||||
grub_term_cursor_x (&data->geo),
|
||||
data->geo.first_entry_y + data->offset });
|
||||
grub_term_refresh (data->term);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_menu_try_text (struct grub_term_output *term,
|
||||
int entry, grub_menu_t menu, int nested)
|
||||
{
|
||||
struct menu_viewer_data *data;
|
||||
struct grub_menu_viewer *instance;
|
||||
|
||||
instance = grub_zalloc (sizeof (*instance));
|
||||
if (!instance)
|
||||
return grub_errno;
|
||||
|
||||
data = grub_zalloc (sizeof (*data));
|
||||
if (!data)
|
||||
{
|
||||
grub_free (instance);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
data->term = term;
|
||||
instance->data = data;
|
||||
instance->set_chosen_entry = menu_text_set_chosen_entry;
|
||||
instance->print_timeout = menu_text_print_timeout;
|
||||
instance->clear_timeout = menu_text_clear_timeout;
|
||||
instance->fini = menu_text_fini;
|
||||
|
||||
data->menu = menu;
|
||||
|
||||
data->offset = entry;
|
||||
data->first = 0;
|
||||
|
||||
grub_term_setcursor (data->term, 0);
|
||||
grub_menu_init_page (nested, 0, &data->geo, data->term);
|
||||
|
||||
if (data->offset > data->geo.num_entries - 1)
|
||||
{
|
||||
data->first = data->offset - (data->geo.num_entries - 1);
|
||||
data->offset = data->geo.num_entries - 1;
|
||||
}
|
||||
|
||||
print_entries (menu, data);
|
||||
grub_term_refresh (data->term);
|
||||
grub_menu_register_viewer (instance);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
194
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c
Normal file
194
GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/* misc.c - miscellaneous functions */
|
||||
/*
|
||||
* 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/normal.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/datetime.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/partition.h>
|
||||
|
||||
static const char *grub_human_sizes[3][6] =
|
||||
{
|
||||
/* This algorithm in reality would work only up to (2^64) / 100 B = 81 PiB.
|
||||
Put here all possible suffixes it can produce so no array bounds check
|
||||
is needed.
|
||||
*/
|
||||
/* TRANSLATORS: that's the list of binary unit prefixes. */
|
||||
{ N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB")},
|
||||
/* TRANSLATORS: that's the list of binary unit prefixes. */
|
||||
{ "", N_("KB"), N_("MB"), N_("GB"), N_("TB"), N_("PB") },
|
||||
/* TRANSLATORS: that's the list of binary unit prefixes. */
|
||||
{ N_("B/s"), N_("KiB/s"), N_("MiB/s"), N_("GiB/s"), N_("TiB/s"), N_("PiB/s"), },
|
||||
};
|
||||
|
||||
const char *
|
||||
grub_get_human_size (grub_uint64_t size, enum grub_human_size_type type)
|
||||
{
|
||||
grub_uint64_t fsize;
|
||||
unsigned units = 0;
|
||||
static char buf[30];
|
||||
const char *umsg;
|
||||
|
||||
if (type != GRUB_HUMAN_SIZE_SPEED)
|
||||
fsize = size * 100ULL;
|
||||
else
|
||||
fsize = size;
|
||||
|
||||
/* Since 2^64 / 1024^5 < 102400, this can give at most 5 iterations.
|
||||
So units <=5, so impossible to go past the end of array.
|
||||
*/
|
||||
while (fsize >= 102400)
|
||||
{
|
||||
fsize = (fsize + 512) / 1024;
|
||||
units++;
|
||||
}
|
||||
|
||||
umsg = _(grub_human_sizes[type][units]);
|
||||
|
||||
if (units || type == GRUB_HUMAN_SIZE_SPEED)
|
||||
{
|
||||
grub_uint64_t whole, fraction;
|
||||
|
||||
whole = grub_divmod64 (fsize, 100, &fraction);
|
||||
grub_snprintf (buf, sizeof (buf),
|
||||
"%" PRIuGRUB_UINT64_T
|
||||
".%02" PRIuGRUB_UINT64_T "%s", whole, fraction,
|
||||
umsg);
|
||||
}
|
||||
else
|
||||
grub_snprintf (buf, sizeof (buf), "%llu%s", (unsigned long long) size,
|
||||
umsg);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Print the information on the device NAME. */
|
||||
grub_err_t
|
||||
grub_normal_print_device_info (const char *name)
|
||||
{
|
||||
grub_device_t dev;
|
||||
char *p;
|
||||
|
||||
p = grub_strchr (name, ',');
|
||||
if (p)
|
||||
{
|
||||
grub_xputs ("\t");
|
||||
grub_printf_ (N_("Partition %s:"), name);
|
||||
grub_xputs (" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_printf_ (N_("Device %s:"), name);
|
||||
grub_xputs (" ");
|
||||
}
|
||||
|
||||
dev = grub_device_open (name);
|
||||
if (! dev)
|
||||
grub_printf ("%s", _("Filesystem cannot be accessed"));
|
||||
else if (dev->disk)
|
||||
{
|
||||
grub_fs_t fs;
|
||||
|
||||
fs = grub_fs_probe (dev);
|
||||
/* Ignore all errors. */
|
||||
grub_errno = 0;
|
||||
|
||||
if (fs)
|
||||
{
|
||||
const char *fsname = fs->name;
|
||||
if (grub_strcmp (fsname, "ext2") == 0)
|
||||
fsname = "ext*";
|
||||
grub_printf_ (N_("Filesystem type %s"), fsname);
|
||||
if (fs->fs_label)
|
||||
{
|
||||
char *label;
|
||||
(fs->fs_label) (dev, &label);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
if (label && grub_strlen (label))
|
||||
{
|
||||
grub_xputs (" ");
|
||||
grub_printf_ (N_("- Label `%s'"), label);
|
||||
}
|
||||
grub_free (label);
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
if (fs->fs_mtime)
|
||||
{
|
||||
grub_int32_t tm;
|
||||
struct grub_datetime datetime;
|
||||
(fs->fs_mtime) (dev, &tm);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
grub_unixtime2datetime (tm, &datetime);
|
||||
grub_xputs (" ");
|
||||
/* TRANSLATORS: Arguments are year, month, day, hour, minute,
|
||||
second, day of the week (translated). */
|
||||
grub_printf_ (N_("- Last modification time %d-%02d-%02d "
|
||||
"%02d:%02d:%02d %s"),
|
||||
datetime.year, datetime.month, datetime.day,
|
||||
datetime.hour, datetime.minute, datetime.second,
|
||||
grub_get_weekday_name (&datetime));
|
||||
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
if (fs->fs_uuid)
|
||||
{
|
||||
char *uuid;
|
||||
(fs->fs_uuid) (dev, &uuid);
|
||||
if (grub_errno == GRUB_ERR_NONE)
|
||||
{
|
||||
if (uuid && grub_strlen (uuid))
|
||||
grub_printf (", UUID %s", uuid);
|
||||
grub_free (uuid);
|
||||
}
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
grub_printf ("%s", _("No known filesystem detected"));
|
||||
|
||||
if (dev->disk->partition)
|
||||
grub_printf (_(" - Partition start at %llu%sKiB"),
|
||||
(unsigned long long) (grub_partition_get_start (dev->disk->partition) >> 1),
|
||||
(grub_partition_get_start (dev->disk->partition) & 1) ? ".5" : "" );
|
||||
else
|
||||
grub_printf_ (N_(" - Sector size %uB"), 1 << dev->disk->log_sector_size);
|
||||
if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN)
|
||||
grub_puts_ (N_(" - Total size unknown"));
|
||||
else
|
||||
grub_printf (_(" - Total size %llu%sKiB"),
|
||||
(unsigned long long) (grub_disk_get_size (dev->disk) >> 1),
|
||||
/* TRANSLATORS: Replace dot with appropriate decimal separator for
|
||||
your language. */
|
||||
(grub_disk_get_size (dev->disk) & 1) ? _(".5") : "");
|
||||
}
|
||||
|
||||
if (dev)
|
||||
grub_device_close (dev);
|
||||
|
||||
grub_xputs ("\n");
|
||||
return grub_errno;
|
||||
}
|
207
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c
Normal file
207
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Huffman alphabets
|
||||
*
|
||||
*/
|
||||
|
||||
#include "wimboot.h"
|
||||
#include "huffman.h"
|
||||
|
||||
/**
|
||||
* Transcribe binary value (for debugging)
|
||||
*
|
||||
* @v value Value
|
||||
* @v bits Length of value (in bits)
|
||||
* @ret string Transcribed value
|
||||
*/
|
||||
const char * huffman_bin ( unsigned long value, unsigned int bits ) {
|
||||
static char buf[ ( 8 * sizeof ( value ) ) + 1 /* NUL */ ];
|
||||
char *out = buf;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( bits < sizeof ( buf ) );
|
||||
|
||||
/* Transcribe value */
|
||||
while ( bits-- )
|
||||
*(out++) = ( ( value & ( 1 << bits ) ) ? '1' : '0' );
|
||||
*out = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump Huffman alphabet (for debugging)
|
||||
*
|
||||
* @v alphabet Huffman alphabet
|
||||
*/
|
||||
static void __attribute__ (( unused ))
|
||||
huffman_dump_alphabet ( struct huffman_alphabet *alphabet ) {
|
||||
struct huffman_symbols *sym;
|
||||
unsigned int bits;
|
||||
unsigned int huf;
|
||||
unsigned int i;
|
||||
|
||||
(void)huf;
|
||||
|
||||
/* Dump symbol table for each utilised length */
|
||||
for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
|
||||
sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
|
||||
sym = &alphabet->huf[ bits - 1 ];
|
||||
if ( sym->freq == 0 )
|
||||
continue;
|
||||
huf = ( sym->start >> sym->shift );
|
||||
DBG ( "Huffman length %d start \"%s\" freq %d:", bits,
|
||||
huffman_bin ( huf, sym->bits ), sym->freq );
|
||||
for ( i = 0 ; i < sym->freq ; i++ ) {
|
||||
DBG ( " %03x", sym->raw[ huf + i ] );
|
||||
}
|
||||
DBG ( "\n" );
|
||||
}
|
||||
|
||||
/* Dump quick lookup table */
|
||||
DBG ( "Huffman quick lookup:" );
|
||||
for ( i = 0 ; i < ( sizeof ( alphabet->lookup ) /
|
||||
sizeof ( alphabet->lookup[0] ) ) ; i++ ) {
|
||||
DBG ( " %d", ( alphabet->lookup[i] + 1 ) );
|
||||
}
|
||||
DBG ( "\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct Huffman alphabet
|
||||
*
|
||||
* @v alphabet Huffman alphabet
|
||||
* @v lengths Symbol length table
|
||||
* @v count Number of symbols
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int huffman_alphabet ( struct huffman_alphabet *alphabet,
|
||||
uint8_t *lengths, unsigned int count ) {
|
||||
struct huffman_symbols *sym;
|
||||
unsigned int huf;
|
||||
unsigned int cum_freq;
|
||||
unsigned int bits;
|
||||
unsigned int raw;
|
||||
unsigned int adjustment;
|
||||
unsigned int prefix;
|
||||
int empty;
|
||||
int complete;
|
||||
|
||||
/* Clear symbol table */
|
||||
memset ( alphabet->huf, 0, sizeof ( alphabet->huf ) );
|
||||
|
||||
/* Count number of symbols with each Huffman-coded length */
|
||||
empty = 1;
|
||||
for ( raw = 0 ; raw < count ; raw++ ) {
|
||||
bits = lengths[raw];
|
||||
if ( bits ) {
|
||||
alphabet->huf[ bits - 1 ].freq++;
|
||||
empty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* In the degenerate case of having no symbols (i.e. an unused
|
||||
* alphabet), generate a trivial alphabet with exactly two
|
||||
* single-bit codes. This allows callers to avoid having to
|
||||
* check for this special case.
|
||||
*/
|
||||
if ( empty )
|
||||
alphabet->huf[0].freq = 2;
|
||||
|
||||
/* Populate Huffman-coded symbol table */
|
||||
huf = 0;
|
||||
cum_freq = 0;
|
||||
for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
|
||||
sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
|
||||
sym = &alphabet->huf[ bits - 1 ];
|
||||
sym->bits = bits;
|
||||
sym->shift = ( HUFFMAN_BITS - bits );
|
||||
sym->start = ( huf << sym->shift );
|
||||
sym->raw = &alphabet->raw[cum_freq];
|
||||
huf += sym->freq;
|
||||
if ( huf > ( 1U << bits ) ) {
|
||||
DBG ( "Huffman alphabet has too many symbols with "
|
||||
"lengths <=%d\n", bits );
|
||||
return -1;
|
||||
}
|
||||
huf <<= 1;
|
||||
cum_freq += sym->freq;
|
||||
}
|
||||
complete = ( huf == ( 1U << bits ) );
|
||||
|
||||
/* Populate raw symbol table */
|
||||
for ( raw = 0 ; raw < count ; raw++ ) {
|
||||
bits = lengths[raw];
|
||||
if ( bits ) {
|
||||
sym = &alphabet->huf[ bits - 1 ];
|
||||
*(sym->raw++) = raw;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust Huffman-coded symbol table raw pointers and populate
|
||||
* quick lookup table.
|
||||
*/
|
||||
for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
|
||||
sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
|
||||
sym = &alphabet->huf[ bits - 1 ];
|
||||
|
||||
/* Adjust raw pointer */
|
||||
sym->raw -= sym->freq; /* Reset to first symbol */
|
||||
adjustment = ( sym->start >> sym->shift );
|
||||
sym->raw -= adjustment; /* Adjust for quick indexing */
|
||||
|
||||
/* Populate quick lookup table */
|
||||
for ( prefix = ( sym->start >> HUFFMAN_QL_SHIFT ) ;
|
||||
prefix < ( 1 << HUFFMAN_QL_BITS ) ; prefix++ ) {
|
||||
alphabet->lookup[prefix] = ( bits - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that there are no invalid codes */
|
||||
if ( ! complete ) {
|
||||
DBG ( "Huffman alphabet is incomplete\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Huffman symbol set
|
||||
*
|
||||
* @v alphabet Huffman alphabet
|
||||
* @v huf Raw input value (normalised to HUFFMAN_BITS bits)
|
||||
* @ret sym Huffman symbol set
|
||||
*/
|
||||
struct huffman_symbols * huffman_sym ( struct huffman_alphabet *alphabet,
|
||||
unsigned int huf ) {
|
||||
struct huffman_symbols *sym;
|
||||
unsigned int lookup_index;
|
||||
|
||||
/* Find symbol set for this length */
|
||||
lookup_index = ( huf >> HUFFMAN_QL_SHIFT );
|
||||
sym = &alphabet->huf[ alphabet->lookup[ lookup_index ] ];
|
||||
while ( huf < sym->start )
|
||||
sym--;
|
||||
return sym;
|
||||
}
|
108
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h
Normal file
108
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef _HUFFMAN_H
|
||||
#define _HUFFMAN_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Huffman alphabets
|
||||
*
|
||||
*/
|
||||
|
||||
/** Maximum length of a Huffman symbol (in bits) */
|
||||
#define HUFFMAN_BITS 16
|
||||
|
||||
/** Raw huffman symbol */
|
||||
typedef uint16_t huffman_raw_symbol_t;
|
||||
|
||||
/** Quick lookup length for a Huffman symbol (in bits)
|
||||
*
|
||||
* This is a policy decision.
|
||||
*/
|
||||
#define HUFFMAN_QL_BITS 7
|
||||
|
||||
/** Quick lookup shift */
|
||||
#define HUFFMAN_QL_SHIFT ( HUFFMAN_BITS - HUFFMAN_QL_BITS )
|
||||
|
||||
/** A Huffman-coded set of symbols of a given length */
|
||||
struct huffman_symbols {
|
||||
/** Length of Huffman-coded symbols (in bits) */
|
||||
uint8_t bits;
|
||||
/** Shift to normalise symbols of this length to HUFFMAN_BITS bits */
|
||||
uint8_t shift;
|
||||
/** Number of Huffman-coded symbols having this length */
|
||||
uint16_t freq;
|
||||
/** First symbol of this length (normalised to HUFFMAN_BITS bits)
|
||||
*
|
||||
* Stored as a 32-bit value to allow the value
|
||||
* (1<<HUFFMAN_BITS ) to be used for empty sets of symbols
|
||||
* longer than the maximum utilised length.
|
||||
*/
|
||||
uint32_t start;
|
||||
/** Raw symbols having this length */
|
||||
huffman_raw_symbol_t *raw;
|
||||
};
|
||||
|
||||
/** A Huffman-coded alphabet */
|
||||
struct huffman_alphabet {
|
||||
/** Huffman-coded symbol set for each length */
|
||||
struct huffman_symbols huf[HUFFMAN_BITS];
|
||||
/** Quick lookup table */
|
||||
uint8_t lookup[ 1 << HUFFMAN_QL_BITS ];
|
||||
/** Raw symbols
|
||||
*
|
||||
* Ordered by Huffman-coded symbol length, then by symbol
|
||||
* value. This field has a variable length.
|
||||
*/
|
||||
huffman_raw_symbol_t raw[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Huffman symbol length
|
||||
*
|
||||
* @v sym Huffman symbol set
|
||||
* @ret len Length (in bits)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
huffman_len ( struct huffman_symbols *sym ) {
|
||||
|
||||
return sym->bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Huffman symbol value
|
||||
*
|
||||
* @v sym Huffman symbol set
|
||||
* @v huf Raw input value (normalised to HUFFMAN_BITS bits)
|
||||
* @ret raw Raw symbol value
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) huffman_raw_symbol_t
|
||||
huffman_raw ( struct huffman_symbols *sym, unsigned int huf ) {
|
||||
|
||||
return sym->raw[ huf >> sym->shift ];
|
||||
}
|
||||
|
||||
extern int huffman_alphabet ( struct huffman_alphabet *alphabet,
|
||||
uint8_t *lengths, unsigned int count );
|
||||
extern struct huffman_symbols *
|
||||
huffman_sym ( struct huffman_alphabet *alphabet, unsigned int huf );
|
||||
|
||||
#endif /* _HUFFMAN_H */
|
666
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c
Normal file
666
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c
Normal file
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* LZX decompression
|
||||
*
|
||||
* This algorithm is derived jointly from the document "[MS-PATCH]:
|
||||
* LZX DELTA Compression and Decompression", available from
|
||||
*
|
||||
* http://msdn.microsoft.com/en-us/library/cc483133.aspx
|
||||
*
|
||||
* and from the file lzx-decompress.c in the wimlib source code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "wimboot.h"
|
||||
#include "huffman.h"
|
||||
#include "lzx.h"
|
||||
|
||||
/** Base positions, indexed by position slot */
|
||||
static unsigned int lzx_position_base[LZX_POSITION_SLOTS];
|
||||
|
||||
/**
|
||||
* Attempt to accumulate bits from LZX bitstream
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v bits Number of bits to accumulate
|
||||
* @v norm_value Accumulated value (normalised to 16 bits)
|
||||
*
|
||||
* Note that there may not be sufficient accumulated bits in the
|
||||
* bitstream; callers must check that sufficient bits are available
|
||||
* before using the value.
|
||||
*/
|
||||
static int lzx_accumulate ( struct lzx *lzx, unsigned int bits ) {
|
||||
const uint16_t *src16;
|
||||
|
||||
/* Accumulate more bits if required */
|
||||
if ( ( lzx->bits < bits ) &&
|
||||
( lzx->input.offset < lzx->input.len ) ) {
|
||||
src16 = (const uint16_t *)( ( char * ) lzx->input.data + lzx->input.offset );
|
||||
lzx->input.offset += sizeof ( *src16 );
|
||||
lzx->accumulator |= ( *src16 << ( 16 - lzx->bits ) );
|
||||
lzx->bits += 16;
|
||||
}
|
||||
|
||||
return ( lzx->accumulator >> 16 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume accumulated bits from LZX bitstream
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v bits Number of bits to consume
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_consume ( struct lzx *lzx, unsigned int bits ) {
|
||||
|
||||
/* Fail if insufficient bits are available */
|
||||
if ( lzx->bits < bits ) {
|
||||
DBG ( "LZX input overrun in %#zx/%#zx out %#zx)\n",
|
||||
lzx->input.offset, lzx->input.len, lzx->output.offset );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Consume bits */
|
||||
lzx->accumulator <<= bits;
|
||||
lzx->bits -= bits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bits from LZX bitstream
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v bits Number of bits to fetch
|
||||
* @ret value Value, or negative error
|
||||
*/
|
||||
static int lzx_getbits ( struct lzx *lzx, unsigned int bits ) {
|
||||
int norm_value;
|
||||
int rc;
|
||||
|
||||
/* Accumulate more bits if required */
|
||||
norm_value = lzx_accumulate ( lzx, bits );
|
||||
|
||||
/* Consume bits */
|
||||
if ( ( rc = lzx_consume ( lzx, bits ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return ( norm_value >> ( 16 - bits ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Align LZX bitstream for byte access
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v bits Minimum number of padding bits
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_align ( struct lzx *lzx, unsigned int bits ) {
|
||||
int pad;
|
||||
|
||||
/* Get padding bits */
|
||||
pad = lzx_getbits ( lzx, bits );
|
||||
if ( pad < 0 )
|
||||
return pad;
|
||||
|
||||
/* Consume all accumulated bits */
|
||||
lzx_consume ( lzx, lzx->bits );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bytes from LZX bitstream
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v data Data buffer, or NULL
|
||||
* @v len Length of data buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_getbytes ( struct lzx *lzx, void *data, size_t len ) {
|
||||
|
||||
/* Sanity check */
|
||||
if ( ( lzx->input.offset + len ) > lzx->input.len ) {
|
||||
DBG ( "LZX input overrun in %#zx/%#zx out %#zx)\n",
|
||||
lzx->input.offset, lzx->input.len, lzx->output.offset );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy data */
|
||||
if ( data )
|
||||
memcpy ( data, ( lzx->input.data + lzx->input.offset ), len );
|
||||
lzx->input.offset += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode LZX Huffman-coded symbol
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v alphabet Huffman alphabet
|
||||
* @ret raw Raw symbol, or negative error
|
||||
*/
|
||||
static int lzx_decode ( struct lzx *lzx, struct huffman_alphabet *alphabet ) {
|
||||
struct huffman_symbols *sym;
|
||||
int huf;
|
||||
int rc;
|
||||
|
||||
/* Accumulate sufficient bits */
|
||||
huf = lzx_accumulate ( lzx, HUFFMAN_BITS );
|
||||
if ( huf < 0 )
|
||||
return huf;
|
||||
|
||||
/* Decode symbol */
|
||||
sym = huffman_sym ( alphabet, huf );
|
||||
|
||||
/* Consume bits */
|
||||
if ( ( rc = lzx_consume ( lzx, huffman_len ( sym ) ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return huffman_raw ( sym, huf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Huffman alphabet from raw length table
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v count Number of symbols
|
||||
* @v bits Length of each length (in bits)
|
||||
* @v lengths Lengths table to fill in
|
||||
* @v alphabet Huffman alphabet to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_raw_alphabet ( struct lzx *lzx, unsigned int count,
|
||||
unsigned int bits, uint8_t *lengths,
|
||||
struct huffman_alphabet *alphabet ) {
|
||||
unsigned int i;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Read lengths */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
len = lzx_getbits ( lzx, bits );
|
||||
if ( len < 0 )
|
||||
return len;
|
||||
lengths[i] = len;
|
||||
}
|
||||
|
||||
/* Generate Huffman alphabet */
|
||||
if ( ( rc = huffman_alphabet ( alphabet, lengths, count ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate pretree
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @v count Number of symbols
|
||||
* @v lengths Lengths table to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_pretree ( struct lzx *lzx, unsigned int count,
|
||||
uint8_t *lengths ) {
|
||||
unsigned int i;
|
||||
unsigned int length;
|
||||
int dup = 0;
|
||||
int code;
|
||||
int rc;
|
||||
|
||||
/* Generate pretree alphabet */
|
||||
if ( ( rc = lzx_raw_alphabet ( lzx, LZX_PRETREE_CODES,
|
||||
LZX_PRETREE_BITS, lzx->pretree_lengths,
|
||||
&lzx->pretree ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Read lengths */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
|
||||
if ( dup ) {
|
||||
|
||||
/* Duplicate previous length */
|
||||
lengths[i] = lengths[ i - 1 ];
|
||||
dup--;
|
||||
|
||||
} else {
|
||||
|
||||
/* Get next code */
|
||||
code = lzx_decode ( lzx, &lzx->pretree );
|
||||
if ( code < 0 )
|
||||
return code;
|
||||
|
||||
/* Interpret code */
|
||||
if ( code <= 16 ) {
|
||||
length = ( ( lengths[i] - code + 17 ) % 17 );
|
||||
} else if ( code == 17 ) {
|
||||
length = 0;
|
||||
dup = lzx_getbits ( lzx, 4 );
|
||||
if ( dup < 0 )
|
||||
return dup;
|
||||
dup += 3;
|
||||
} else if ( code == 18 ) {
|
||||
length = 0;
|
||||
dup = lzx_getbits ( lzx, 5 );
|
||||
if ( dup < 0 )
|
||||
return dup;
|
||||
dup += 19;
|
||||
} else if ( code == 19 ) {
|
||||
length = 0;
|
||||
dup = lzx_getbits ( lzx, 1 );
|
||||
if ( dup < 0 )
|
||||
return dup;
|
||||
dup += 3;
|
||||
code = lzx_decode ( lzx, &lzx->pretree );
|
||||
if ( code < 0 )
|
||||
return code;
|
||||
length = ( ( lengths[i] - code + 17 ) % 17 );
|
||||
} else {
|
||||
DBG ( "Unrecognised pretree code %d\n", code );
|
||||
return -1;
|
||||
}
|
||||
lengths[i] = length;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
if ( dup ) {
|
||||
DBG ( "Pretree duplicate overrun\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate aligned offset Huffman alphabet
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_alignoffset_alphabet ( struct lzx *lzx ) {
|
||||
int rc;
|
||||
|
||||
/* Generate aligned offset alphabet */
|
||||
if ( ( rc = lzx_raw_alphabet ( lzx, LZX_ALIGNOFFSET_CODES,
|
||||
LZX_ALIGNOFFSET_BITS,
|
||||
lzx->alignoffset_lengths,
|
||||
&lzx->alignoffset ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate main Huffman alphabet
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_main_alphabet ( struct lzx *lzx ) {
|
||||
int rc;
|
||||
|
||||
/* Generate literal symbols pretree */
|
||||
if ( ( rc = lzx_pretree ( lzx, LZX_MAIN_LIT_CODES,
|
||||
lzx->main_lengths.literals ) ) != 0 ) {
|
||||
DBG ( "Could not construct main literal pretree\n" );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Generate remaining symbols pretree */
|
||||
if ( ( rc = lzx_pretree ( lzx, ( LZX_MAIN_CODES - LZX_MAIN_LIT_CODES ),
|
||||
lzx->main_lengths.remainder ) ) != 0 ) {
|
||||
DBG ( "Could not construct main remainder pretree\n" );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Generate Huffman alphabet */
|
||||
if ( ( rc = huffman_alphabet ( &lzx->main, lzx->main_lengths.literals,
|
||||
LZX_MAIN_CODES ) ) != 0 ) {
|
||||
DBG ( "Could not generate main alphabet\n" );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate length Huffman alphabet
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_length_alphabet ( struct lzx *lzx ) {
|
||||
int rc;
|
||||
|
||||
/* Generate pretree */
|
||||
if ( ( rc = lzx_pretree ( lzx, LZX_LENGTH_CODES,
|
||||
lzx->length_lengths ) ) != 0 ) {
|
||||
DBG ( "Could not generate length pretree\n" );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Generate Huffman alphabet */
|
||||
if ( ( rc = huffman_alphabet ( &lzx->length, lzx->length_lengths,
|
||||
LZX_LENGTH_CODES ) ) != 0 ) {
|
||||
DBG ( "Could not generate length alphabet\n" );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process LZX block header
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_block_header ( struct lzx *lzx ) {
|
||||
size_t block_len;
|
||||
int block_type;
|
||||
int default_len;
|
||||
int len_high;
|
||||
int len_low;
|
||||
int rc;
|
||||
|
||||
/* Get block type */
|
||||
block_type = lzx_getbits ( lzx, LZX_BLOCK_TYPE_BITS );
|
||||
if ( block_type < 0 )
|
||||
return block_type;
|
||||
lzx->block_type = block_type;
|
||||
|
||||
/* Check block length */
|
||||
default_len = lzx_getbits ( lzx, 1 );
|
||||
if ( default_len < 0 )
|
||||
return default_len;
|
||||
if ( default_len ) {
|
||||
block_len = LZX_DEFAULT_BLOCK_LEN;
|
||||
} else {
|
||||
len_high = lzx_getbits ( lzx, 8 );
|
||||
if ( len_high < 0 )
|
||||
return len_high;
|
||||
len_low = lzx_getbits ( lzx, 8 );
|
||||
if ( len_low < 0 )
|
||||
return len_low;
|
||||
block_len = ( ( len_high << 8 ) | len_low );
|
||||
}
|
||||
lzx->output.threshold = ( lzx->output.offset + block_len );
|
||||
|
||||
/* Handle block type */
|
||||
switch ( block_type ) {
|
||||
case LZX_BLOCK_ALIGNOFFSET :
|
||||
/* Generated aligned offset alphabet */
|
||||
if ( ( rc = lzx_alignoffset_alphabet ( lzx ) ) != 0 )
|
||||
return rc;
|
||||
/* Fall through */
|
||||
case LZX_BLOCK_VERBATIM :
|
||||
/* Generate main alphabet */
|
||||
if ( ( rc = lzx_main_alphabet ( lzx ) ) != 0 )
|
||||
return rc;
|
||||
/* Generate lengths alphabet */
|
||||
if ( ( rc = lzx_length_alphabet ( lzx ) ) != 0 )
|
||||
return rc;
|
||||
break;
|
||||
case LZX_BLOCK_UNCOMPRESSED :
|
||||
/* Align input stream */
|
||||
if ( ( rc = lzx_align ( lzx, 1 ) ) != 0 )
|
||||
return rc;
|
||||
/* Read new repeated offsets */
|
||||
if ( ( rc = lzx_getbytes ( lzx, &lzx->repeated_offset,
|
||||
sizeof ( lzx->repeated_offset )))!=0)
|
||||
return rc;
|
||||
break;
|
||||
default:
|
||||
DBG ( "Unrecognised block type %d\n", block_type );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process uncompressed data
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int lzx_uncompressed ( struct lzx *lzx ) {
|
||||
void *data;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Copy bytes */
|
||||
data = ( lzx->output.data ?
|
||||
( lzx->output.data + lzx->output.offset ) : NULL );
|
||||
len = ( lzx->output.threshold - lzx->output.offset );
|
||||
if ( ( rc = lzx_getbytes ( lzx, data, len ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Align input stream */
|
||||
if ( len % 2 )
|
||||
lzx->input.offset++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an LZX token
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Variable names are chosen to match the LZX specification
|
||||
* pseudo-code.
|
||||
*/
|
||||
static int lzx_token ( struct lzx *lzx ) {
|
||||
unsigned int length_header;
|
||||
unsigned int position_slot;
|
||||
unsigned int offset_bits;
|
||||
unsigned int i;
|
||||
size_t match_offset;
|
||||
size_t match_length;
|
||||
int verbatim_bits;
|
||||
int aligned_bits;
|
||||
int maindata;
|
||||
int length;
|
||||
uint8_t *copy;
|
||||
|
||||
/* Get maindata symelse*/
|
||||
maindata = lzx_decode ( lzx, &lzx->main );
|
||||
if ( maindata < 0 )
|
||||
return maindata;
|
||||
|
||||
/* Check for literals */
|
||||
if ( maindata < LZX_MAIN_LIT_CODES ) {
|
||||
if ( lzx->output.data )
|
||||
lzx->output.data[lzx->output.offset] = maindata;
|
||||
lzx->output.offset++;
|
||||
return 0;
|
||||
}
|
||||
maindata -= LZX_MAIN_LIT_CODES;
|
||||
|
||||
/* Calculate the match length */
|
||||
length_header = ( maindata & 7 );
|
||||
if ( length_header == 7 ) {
|
||||
length = lzx_decode ( lzx, &lzx->length );
|
||||
if ( length < 0 )
|
||||
return length;
|
||||
} else {
|
||||
length = 0;
|
||||
}
|
||||
match_length = ( length_header + 2 + length );
|
||||
|
||||
/* Calculate the position slot */
|
||||
position_slot = ( maindata >> 3 );
|
||||
if ( position_slot < LZX_REPEATED_OFFSETS ) {
|
||||
|
||||
/* Repeated offset */
|
||||
match_offset = lzx->repeated_offset[position_slot];
|
||||
lzx->repeated_offset[position_slot] = lzx->repeated_offset[0];
|
||||
lzx->repeated_offset[0] = match_offset;
|
||||
|
||||
} else {
|
||||
|
||||
/* Non-repeated offset */
|
||||
offset_bits = lzx_footer_bits ( position_slot );
|
||||
if ( ( lzx->block_type == LZX_BLOCK_ALIGNOFFSET ) &&
|
||||
( offset_bits >= 3 ) ) {
|
||||
verbatim_bits = lzx_getbits ( lzx, ( offset_bits - 3 ));
|
||||
if ( verbatim_bits < 0 )
|
||||
return verbatim_bits;
|
||||
verbatim_bits <<= 3;
|
||||
aligned_bits = lzx_decode ( lzx, &lzx->alignoffset );
|
||||
if ( aligned_bits < 0 )
|
||||
return aligned_bits;
|
||||
} else {
|
||||
verbatim_bits = lzx_getbits ( lzx, offset_bits );
|
||||
if ( verbatim_bits < 0 )
|
||||
return verbatim_bits;
|
||||
aligned_bits = 0;
|
||||
}
|
||||
match_offset = ( lzx_position_base[position_slot] +
|
||||
verbatim_bits + aligned_bits - 2 );
|
||||
|
||||
/* Update repeated offset list */
|
||||
for ( i = ( LZX_REPEATED_OFFSETS - 1 ) ; i > 0 ; i-- )
|
||||
lzx->repeated_offset[i] = lzx->repeated_offset[ i - 1 ];
|
||||
lzx->repeated_offset[0] = match_offset;
|
||||
}
|
||||
|
||||
/* Copy data */
|
||||
if ( match_offset > lzx->output.offset ) {
|
||||
DBG ( "LZX match underrun out 0x%x offset 0x%x len 0x%x\n",
|
||||
lzx->output.offset, match_offset, match_length );
|
||||
return -1;
|
||||
}
|
||||
if ( lzx->output.data ) {
|
||||
copy = &lzx->output.data[lzx->output.offset];
|
||||
for ( i = 0 ; i < match_length ; i++ )
|
||||
copy[i] = copy[ i - match_offset ];
|
||||
}
|
||||
lzx->output.offset += match_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate E8 jump addresses
|
||||
*
|
||||
* @v lzx Decompressor
|
||||
*/
|
||||
static void lzx_translate_jumps ( struct lzx *lzx ) {
|
||||
size_t offset;
|
||||
int32_t *target;
|
||||
|
||||
/* Sanity check */
|
||||
if ( lzx->output.offset < 10 )
|
||||
return;
|
||||
|
||||
/* Scan for jump instructions */
|
||||
for ( offset = 0 ; offset < ( lzx->output.offset - 10 ) ; offset++ ) {
|
||||
|
||||
/* Check for jump instruction */
|
||||
if ( lzx->output.data[offset] != 0xe8 )
|
||||
continue;
|
||||
|
||||
/* Translate jump target */
|
||||
target = ( ( int32_t * ) &lzx->output.data[ offset + 1 ] );
|
||||
if ( *target >= 0 ) {
|
||||
if ( *target < LZX_WIM_MAGIC_FILESIZE )
|
||||
*target -= offset;
|
||||
} else {
|
||||
if ( *target >= -( ( int32_t ) offset ) )
|
||||
*target += LZX_WIM_MAGIC_FILESIZE;
|
||||
}
|
||||
offset += sizeof ( *target );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress LZX-compressed data
|
||||
*
|
||||
* @v data Compressed data
|
||||
* @v len Length of compressed data
|
||||
* @v buf Decompression buffer, or NULL
|
||||
* @ret out_len Length of decompressed data, or negative error
|
||||
*/
|
||||
ssize_t lzx_decompress ( const void *data, size_t len, void *buf ) {
|
||||
struct lzx lzx;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( len % 2 ) {
|
||||
DBG ( "LZX cannot handle odd-length input data\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialise global state, if required */
|
||||
if ( ! lzx_position_base[ LZX_POSITION_SLOTS - 1 ] ) {
|
||||
for ( i = 1 ; i < LZX_POSITION_SLOTS ; i++ ) {
|
||||
lzx_position_base[i] =
|
||||
( lzx_position_base[i-1] +
|
||||
( 1 << lzx_footer_bits ( i - 1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise decompressor */
|
||||
memset ( &lzx, 0, sizeof ( lzx ) );
|
||||
lzx.input.data = data;
|
||||
lzx.input.len = len;
|
||||
lzx.output.data = buf;
|
||||
for ( i = 0 ; i < LZX_REPEATED_OFFSETS ; i++ )
|
||||
lzx.repeated_offset[i] = 1;
|
||||
|
||||
/* Process blocks */
|
||||
while ( lzx.input.offset < lzx.input.len ) {
|
||||
|
||||
/* Process block header */
|
||||
if ( ( rc = lzx_block_header ( &lzx ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Process block contents */
|
||||
if ( lzx.block_type == LZX_BLOCK_UNCOMPRESSED ) {
|
||||
|
||||
/* Copy uncompressed data */
|
||||
if ( ( rc = lzx_uncompressed ( &lzx ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
} else {
|
||||
|
||||
/* Process token stream */
|
||||
while ( lzx.output.offset < lzx.output.threshold ) {
|
||||
if ( ( rc = lzx_token ( &lzx ) ) != 0 )
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Postprocess to undo E8 jump compression */
|
||||
if ( lzx.output.data )
|
||||
lzx_translate_jumps ( &lzx );
|
||||
|
||||
return lzx.output.offset;
|
||||
}
|
179
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h
Normal file
179
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#ifndef _LZX_H
|
||||
#define _LZX_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* LZX decompression
|
||||
*
|
||||
*/
|
||||
|
||||
#include "huffman.h"
|
||||
|
||||
/** Number of aligned offset codes */
|
||||
#define LZX_ALIGNOFFSET_CODES 8
|
||||
|
||||
/** Aligned offset code length (in bits) */
|
||||
#define LZX_ALIGNOFFSET_BITS 3
|
||||
|
||||
/** Number of pretree codes */
|
||||
#define LZX_PRETREE_CODES 20
|
||||
|
||||
/** Pretree code length (in bits) */
|
||||
#define LZX_PRETREE_BITS 4
|
||||
|
||||
/** Number of literal main codes */
|
||||
#define LZX_MAIN_LIT_CODES 256
|
||||
|
||||
/** Number of position slots */
|
||||
#define LZX_POSITION_SLOTS 30
|
||||
|
||||
/** Number of main codes */
|
||||
#define LZX_MAIN_CODES ( LZX_MAIN_LIT_CODES + ( 8 * LZX_POSITION_SLOTS ) )
|
||||
|
||||
/** Number of length codes */
|
||||
#define LZX_LENGTH_CODES 249
|
||||
|
||||
/** Block type length (in bits) */
|
||||
#define LZX_BLOCK_TYPE_BITS 3
|
||||
|
||||
/** Default block length */
|
||||
#define LZX_DEFAULT_BLOCK_LEN 32768
|
||||
|
||||
/** Number of repeated offsets */
|
||||
#define LZX_REPEATED_OFFSETS 3
|
||||
|
||||
/** Don't ask */
|
||||
#define LZX_WIM_MAGIC_FILESIZE 12000000
|
||||
|
||||
/** Block types */
|
||||
enum lzx_block_type {
|
||||
/** Verbatim block */
|
||||
LZX_BLOCK_VERBATIM = 1,
|
||||
/** Aligned offset block */
|
||||
LZX_BLOCK_ALIGNOFFSET = 2,
|
||||
/** Uncompressed block */
|
||||
LZX_BLOCK_UNCOMPRESSED = 3,
|
||||
};
|
||||
|
||||
/** An LZX input stream */
|
||||
struct lzx_input_stream {
|
||||
/** Data */
|
||||
const uint8_t *data;
|
||||
/** Length */
|
||||
size_t len;
|
||||
/** Offset within stream */
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
/** An LZX output stream */
|
||||
struct lzx_output_stream {
|
||||
/** Data, or NULL */
|
||||
uint8_t *data;
|
||||
/** Offset within stream */
|
||||
size_t offset;
|
||||
/** End of current block within stream */
|
||||
size_t threshold;
|
||||
};
|
||||
|
||||
/** LZX decompressor */
|
||||
struct lzx {
|
||||
/** Input stream */
|
||||
struct lzx_input_stream input;
|
||||
/** Output stream */
|
||||
struct lzx_output_stream output;
|
||||
/** Accumulator */
|
||||
uint32_t accumulator;
|
||||
/** Number of bits in accumulator */
|
||||
unsigned int bits;
|
||||
/** Block type */
|
||||
enum lzx_block_type block_type;
|
||||
/** Repeated offsets */
|
||||
unsigned int repeated_offset[LZX_REPEATED_OFFSETS];
|
||||
|
||||
/** Aligned offset Huffman alphabet */
|
||||
struct huffman_alphabet alignoffset;
|
||||
/** Aligned offset raw symbols
|
||||
*
|
||||
* Must immediately follow the aligned offset Huffman
|
||||
* alphabet.
|
||||
*/
|
||||
huffman_raw_symbol_t alignoffset_raw[LZX_ALIGNOFFSET_CODES];
|
||||
/** Aligned offset code lengths */
|
||||
uint8_t alignoffset_lengths[LZX_ALIGNOFFSET_CODES];
|
||||
|
||||
/** Pretree Huffman alphabet */
|
||||
struct huffman_alphabet pretree;
|
||||
/** Pretree raw symbols
|
||||
*
|
||||
* Must immediately follow the pretree Huffman alphabet.
|
||||
*/
|
||||
huffman_raw_symbol_t pretree_raw[LZX_PRETREE_CODES];
|
||||
/** Preetree code lengths */
|
||||
uint8_t pretree_lengths[LZX_PRETREE_CODES];
|
||||
|
||||
/** Main Huffman alphabet */
|
||||
struct huffman_alphabet main;
|
||||
/** Main raw symbols
|
||||
*
|
||||
* Must immediately follow the main Huffman alphabet.
|
||||
*/
|
||||
huffman_raw_symbol_t main_raw[LZX_MAIN_CODES];
|
||||
/** Main code lengths */
|
||||
struct {
|
||||
/** Literals */
|
||||
uint8_t literals[LZX_MAIN_LIT_CODES];
|
||||
/** Remaining symbols */
|
||||
uint8_t remainder[ LZX_MAIN_CODES - LZX_MAIN_LIT_CODES ];
|
||||
} __attribute__ (( packed )) main_lengths;
|
||||
|
||||
/** Length Huffman alphabet */
|
||||
struct huffman_alphabet length;
|
||||
/** Length raw symbols
|
||||
*
|
||||
* Must immediately follow the length Huffman alphabet.
|
||||
*/
|
||||
huffman_raw_symbol_t length_raw[LZX_LENGTH_CODES];
|
||||
/** Length code lengths */
|
||||
uint8_t length_lengths[LZX_LENGTH_CODES];
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate number of footer bits for a given position slot
|
||||
*
|
||||
* @v position_slot Position slot
|
||||
* @ret footer_bits Number of footer bits
|
||||
*/
|
||||
static inline unsigned int lzx_footer_bits ( unsigned int position_slot ) {
|
||||
|
||||
if ( position_slot < 2 ) {
|
||||
return 0;
|
||||
} else if ( position_slot < 38 ) {
|
||||
return ( ( position_slot / 2 ) - 1 );
|
||||
} else {
|
||||
return 17;
|
||||
}
|
||||
}
|
||||
|
||||
extern ssize_t lzx_decompress ( const void *data, size_t len, void *buf );
|
||||
|
||||
#endif /* _LZX_H */
|
1868
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
Normal file
1868
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c
Normal file
File diff suppressed because it is too large
Load Diff
577
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h
Normal file
577
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h
Normal file
@@ -0,0 +1,577 @@
|
||||
/******************************************************************************
|
||||
* ventoy_def.h
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VENTOY_DEF_H__
|
||||
#define __VENTOY_DEF_H__
|
||||
|
||||
#define VTOY_MAX_SCRIPT_BUF (4 * 1024 * 1024)
|
||||
|
||||
#define VTOY_SIZE_1GB 1073741824
|
||||
|
||||
#define JSON_SUCCESS 0
|
||||
#define JSON_FAILED 1
|
||||
#define JSON_NOT_FOUND 2
|
||||
|
||||
#define ulong unsigned long
|
||||
#define ulonglong unsigned long long
|
||||
|
||||
#define vtoy_to_upper(c) (((char)(c) >= 'a' && (char)(c) <= 'z') ? ((char)(c) - 'a' + 'A') : (char)(c))
|
||||
|
||||
#define VENTOY_CMD_RETURN(err) grub_errno = (err); return (err)
|
||||
#define VENTOY_FILE_TYPE (GRUB_FILE_TYPE_NO_DECOMPRESS | GRUB_FILE_TYPE_LINUX_INITRD)
|
||||
|
||||
#define ventoy_env_op1(op, a) grub_env_##op(a)
|
||||
#define ventoy_env_op2(op, a, b) grub_env_##op((a), (b))
|
||||
|
||||
#define ventoy_get_env(key) ventoy_env_op1(get, key)
|
||||
#define ventoy_set_env(key, val) ventoy_env_op2(set, key, val)
|
||||
|
||||
typedef struct ventoy_initrd_ctx
|
||||
{
|
||||
const char *path_prefix;
|
||||
const char *dir_prefix;
|
||||
}ventoy_initrd_ctx;
|
||||
|
||||
typedef struct cmd_para
|
||||
{
|
||||
const char *name;
|
||||
grub_extcmd_func_t func;
|
||||
grub_command_flags_t flags;
|
||||
const struct grub_arg_option *parser;
|
||||
|
||||
const char *summary;
|
||||
const char *description;
|
||||
|
||||
grub_extcmd_t cmd;
|
||||
}cmd_para;
|
||||
|
||||
#define ventoy_align(value, align) (((value) + ((align) - 1)) & (~((align) - 1)))
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct cpio_newc_header
|
||||
{
|
||||
char c_magic[6];
|
||||
char c_ino[8];
|
||||
char c_mode[8];
|
||||
char c_uid[8];
|
||||
char c_gid[8];
|
||||
char c_nlink[8];
|
||||
char c_mtime[8];
|
||||
char c_filesize[8];
|
||||
char c_devmajor[8];
|
||||
char c_devminor[8];
|
||||
char c_rdevmajor[8];
|
||||
char c_rdevminor[8];
|
||||
char c_namesize[8];
|
||||
char c_check[8];
|
||||
}cpio_newc_header;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
#define cmd_raw_name ctxt->extcmd->cmd->name
|
||||
#define check_free(p, func) if (p) { func(p); p = NULL; }
|
||||
|
||||
typedef int (*grub_char_check_func)(int c);
|
||||
#define ventoy_is_decimal(str) ventoy_string_check(str, grub_isdigit)
|
||||
|
||||
|
||||
// El Torito Boot Record Volume Descriptor
|
||||
#pragma pack(1)
|
||||
typedef struct eltorito_descriptor
|
||||
{
|
||||
grub_uint8_t type;
|
||||
grub_uint8_t id[5];
|
||||
grub_uint8_t version;
|
||||
grub_uint8_t system_id[32];
|
||||
grub_uint8_t reserved[32];
|
||||
grub_uint32_t sector;
|
||||
}eltorito_descriptor;
|
||||
|
||||
typedef struct ventoy_iso9660_override
|
||||
{
|
||||
grub_uint32_t first_sector;
|
||||
grub_uint32_t first_sector_be;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t size_be;
|
||||
}ventoy_iso9660_override;
|
||||
|
||||
typedef struct ventoy_udf_override
|
||||
{
|
||||
grub_uint32_t length;
|
||||
grub_uint32_t position;
|
||||
}ventoy_udf_override;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
typedef struct img_info
|
||||
{
|
||||
char path[512];
|
||||
char name[256];
|
||||
int id;
|
||||
grub_uint64_t size;
|
||||
int select;
|
||||
|
||||
void *parent;
|
||||
|
||||
struct img_info *next;
|
||||
struct img_info *prev;
|
||||
}img_info;
|
||||
|
||||
typedef struct img_iterator_node
|
||||
{
|
||||
struct img_iterator_node *next;
|
||||
img_info **tail;
|
||||
char dir[400];
|
||||
int dirlen;
|
||||
int isocnt;
|
||||
int done;
|
||||
int select;
|
||||
|
||||
struct img_iterator_node *parent;
|
||||
struct img_iterator_node *firstchild;
|
||||
|
||||
void *firstiso;
|
||||
}img_iterator_node;
|
||||
|
||||
|
||||
|
||||
typedef struct initrd_info
|
||||
{
|
||||
char name[256];
|
||||
|
||||
grub_uint64_t offset;
|
||||
grub_uint64_t size;
|
||||
|
||||
grub_uint8_t iso_type; // 0: iso9660 1:udf
|
||||
grub_uint32_t udf_start_block;
|
||||
|
||||
grub_uint64_t override_offset;
|
||||
grub_uint32_t override_length;
|
||||
char override_data[32];
|
||||
|
||||
struct initrd_info *next;
|
||||
struct initrd_info *prev;
|
||||
}initrd_info;
|
||||
|
||||
extern initrd_info *g_initrd_img_list;
|
||||
extern initrd_info *g_initrd_img_tail;
|
||||
extern int g_initrd_img_count;
|
||||
extern int g_valid_initrd_count;
|
||||
|
||||
extern img_info *g_ventoy_img_list;
|
||||
extern int g_ventoy_img_count;
|
||||
|
||||
extern grub_uint8_t *g_ventoy_cpio_buf;
|
||||
extern grub_uint32_t g_ventoy_cpio_size;
|
||||
extern cpio_newc_header *g_ventoy_initrd_head;
|
||||
extern grub_uint8_t *g_ventoy_runtime_buf;
|
||||
|
||||
extern ventoy_guid g_ventoy_guid;
|
||||
|
||||
extern ventoy_img_chunk_list g_img_chunk_list;
|
||||
|
||||
extern int g_ventoy_debug;
|
||||
void ventoy_debug(const char *fmt, ...);
|
||||
#define debug(fmt, ...) if (g_ventoy_debug) ventoy_debug("[VTOY]: "fmt, __VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
#define FLAG_HEADER_RESERVED 0x00000001
|
||||
#define FLAG_HEADER_COMPRESSION 0x00000002
|
||||
#define FLAG_HEADER_READONLY 0x00000004
|
||||
#define FLAG_HEADER_SPANNED 0x00000008
|
||||
#define FLAG_HEADER_RESOURCE_ONLY 0x00000010
|
||||
#define FLAG_HEADER_METADATA_ONLY 0x00000020
|
||||
#define FLAG_HEADER_WRITE_IN_PROGRESS 0x00000040
|
||||
#define FLAG_HEADER_RP_FIX 0x00000080 // reparse point fixup
|
||||
#define FLAG_HEADER_COMPRESS_RESERVED 0x00010000
|
||||
#define FLAG_HEADER_COMPRESS_XPRESS 0x00020000
|
||||
#define FLAG_HEADER_COMPRESS_LZX 0x00040000
|
||||
|
||||
#define RESHDR_FLAG_FREE 0x01
|
||||
#define RESHDR_FLAG_METADATA 0x02
|
||||
#define RESHDR_FLAG_COMPRESSED 0x04
|
||||
#define RESHDR_FLAG_SPANNED 0x08
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* A WIM resource header */
|
||||
typedef struct wim_resource_header
|
||||
{
|
||||
grub_uint64_t size_in_wim:56; /* Compressed length */
|
||||
grub_uint64_t flags:8; /* flags */
|
||||
grub_uint64_t offset; /* Offset */
|
||||
grub_uint64_t raw_size; /* Uncompressed length */
|
||||
}wim_resource_header;
|
||||
|
||||
/* WIM resource header length mask */
|
||||
#define WIM_RESHDR_ZLEN_MASK 0x00ffffffffffffffULL
|
||||
|
||||
/* WIM resource header flags */
|
||||
typedef enum wim_resource_header_flags
|
||||
{
|
||||
WIM_RESHDR_METADATA = ( 0x02ULL << 56 ), /* Resource contains metadata */
|
||||
WIM_RESHDR_COMPRESSED = ( 0x04ULL << 56 ), /* Resource is compressed */
|
||||
WIM_RESHDR_PACKED_STREAMS = ( 0x10ULL << 56 ), /* Resource is compressed using packed streams */
|
||||
}wim_resource_header_flags;
|
||||
|
||||
#define WIM_HEAD_SIGNATURE "MSWIM\0\0"
|
||||
|
||||
/* WIM header */
|
||||
typedef struct wim_header
|
||||
{
|
||||
grub_uint8_t signature[8]; /* Signature */
|
||||
grub_uint32_t header_len; /* Header length */
|
||||
grub_uint32_t version; /* Verson */
|
||||
grub_uint32_t flags; /* Flags */
|
||||
grub_uint32_t chunk_len; /* Chunk length */
|
||||
grub_uint8_t guid[16]; /* GUID */
|
||||
grub_uint16_t part; /* Part number */
|
||||
grub_uint16_t parts; /* Total number of parts */
|
||||
grub_uint32_t images; /* number of images */
|
||||
wim_resource_header lookup; /* Lookup table */
|
||||
wim_resource_header xml; /* XML data */
|
||||
wim_resource_header metadata; /* Boot metadata */
|
||||
grub_uint32_t boot_index; /* Boot index */
|
||||
wim_resource_header integrity; /* Integrity table */
|
||||
grub_uint8_t reserved[60]; /* Reserved */
|
||||
} wim_header;
|
||||
|
||||
/* WIM header flags */
|
||||
typedef enum wim_header_flags
|
||||
{
|
||||
WIM_HDR_XPRESS = 0x00020000, /* WIM uses Xpress compresson */
|
||||
WIM_HDR_LZX = 0x00040000, /* WIM uses LZX compression */
|
||||
}wim_header_flags;
|
||||
|
||||
/* A WIM file hash */
|
||||
typedef struct wim_hash
|
||||
{
|
||||
/* SHA-1 hash */
|
||||
grub_uint8_t sha1[20];
|
||||
}wim_hash;
|
||||
|
||||
/* A WIM lookup table entry */
|
||||
typedef struct wim_lookup_entry
|
||||
{
|
||||
wim_resource_header resource; /* Resource header */
|
||||
grub_uint16_t part; /* Part number */
|
||||
grub_uint32_t refcnt; /* Reference count */
|
||||
wim_hash hash; /* Hash */
|
||||
}wim_lookup_entry;
|
||||
|
||||
/* WIM chunk length */
|
||||
#define WIM_CHUNK_LEN 32768
|
||||
|
||||
/* A WIM chunk buffer */
|
||||
typedef struct wim_chunk_buffer
|
||||
{
|
||||
grub_uint8_t data[WIM_CHUNK_LEN]; /*Data */
|
||||
}wim_chunk_buffer;
|
||||
|
||||
/* Security data */
|
||||
typedef struct wim_security_header
|
||||
{
|
||||
grub_uint32_t len; /* Length */
|
||||
grub_uint32_t count; /* Number of entries */
|
||||
}wim_security_header;
|
||||
|
||||
/* Directory entry */
|
||||
typedef struct wim_directory_entry
|
||||
{
|
||||
grub_uint64_t len; /* Length */
|
||||
grub_uint32_t attributes; /* Attributes */
|
||||
grub_uint32_t security; /* Security ID */
|
||||
grub_uint64_t subdir; /* Subdirectory offset */
|
||||
grub_uint8_t reserved1[16]; /* Reserved */
|
||||
grub_uint64_t created; /* Creation time */
|
||||
grub_uint64_t accessed; /* Last access time */
|
||||
grub_uint64_t written; /* Last written time */
|
||||
wim_hash hash; /* Hash */
|
||||
grub_uint8_t reserved2[12]; /* Reserved */
|
||||
grub_uint16_t streams; /* Streams */
|
||||
grub_uint16_t short_name_len; /* Short name length */
|
||||
grub_uint16_t name_len; /* Name length */
|
||||
}wim_directory_entry;
|
||||
|
||||
/** Normal file */
|
||||
#define WIM_ATTR_NORMAL 0x00000080UL
|
||||
|
||||
/** No security information exists for this file */
|
||||
#define WIM_NO_SECURITY 0xffffffffUL
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
typedef struct wim_tail
|
||||
{
|
||||
grub_uint32_t wim_raw_size;
|
||||
grub_uint32_t wim_align_size;
|
||||
|
||||
grub_uint8_t iso_type;
|
||||
grub_uint64_t file_offset;
|
||||
grub_uint32_t udf_start_block;
|
||||
grub_uint64_t fe_entry_size_offset;
|
||||
grub_uint64_t override_offset;
|
||||
grub_uint32_t override_len;
|
||||
grub_uint8_t override_data[32];
|
||||
|
||||
wim_header wim_header;
|
||||
|
||||
wim_hash bin_hash;
|
||||
grub_uint32_t jump_exe_len;
|
||||
grub_uint8_t *jump_bin_data;
|
||||
grub_uint32_t bin_raw_len;
|
||||
grub_uint32_t bin_align_len;
|
||||
|
||||
grub_uint8_t *new_meta_data;
|
||||
grub_uint32_t new_meta_len;
|
||||
grub_uint32_t new_meta_align_len;
|
||||
|
||||
grub_uint8_t *new_lookup_data;
|
||||
grub_uint32_t new_lookup_len;
|
||||
grub_uint32_t new_lookup_align_len;
|
||||
}wim_tail;
|
||||
|
||||
|
||||
|
||||
typedef enum _JSON_TYPE
|
||||
{
|
||||
JSON_TYPE_NUMBER = 0,
|
||||
JSON_TYPE_STRING,
|
||||
JSON_TYPE_BOOL,
|
||||
JSON_TYPE_ARRAY,
|
||||
JSON_TYPE_OBJECT,
|
||||
JSON_TYPE_NULL,
|
||||
JSON_TYPE_BUTT
|
||||
}JSON_TYPE;
|
||||
|
||||
|
||||
typedef struct _VTOY_JSON
|
||||
{
|
||||
struct _VTOY_JSON *pstPrev;
|
||||
struct _VTOY_JSON *pstNext;
|
||||
struct _VTOY_JSON *pstChild;
|
||||
|
||||
JSON_TYPE enDataType;
|
||||
union
|
||||
{
|
||||
char *pcStrVal;
|
||||
int iNumVal;
|
||||
grub_uint64_t lValue;
|
||||
}unData;
|
||||
|
||||
char *pcName;
|
||||
}VTOY_JSON;
|
||||
|
||||
typedef struct _JSON_PARSE
|
||||
{
|
||||
char *pcKey;
|
||||
void *pDataBuf;
|
||||
grub_uint32_t uiBufSize;
|
||||
}JSON_PARSE;
|
||||
|
||||
#define JSON_NEW_ITEM(pstJson, ret) \
|
||||
{ \
|
||||
(pstJson) = (VTOY_JSON *)grub_zalloc(sizeof(VTOY_JSON)); \
|
||||
if (NULL == (pstJson)) \
|
||||
{ \
|
||||
json_debug("Failed to alloc memory for json.\n"); \
|
||||
return (ret); \
|
||||
} \
|
||||
}
|
||||
|
||||
typedef int (*ventoy_plugin_entry_pf)(VTOY_JSON *json, const char *isodisk);
|
||||
|
||||
typedef struct plugin_entry
|
||||
{
|
||||
const char *key;
|
||||
ventoy_plugin_entry_pf entryfunc;
|
||||
}plugin_entry;
|
||||
|
||||
|
||||
void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param);
|
||||
grub_err_t ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file);
|
||||
int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector);
|
||||
grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name);
|
||||
grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...);
|
||||
int ventoy_is_file_exist(const char *fmt, ...);
|
||||
int ventoy_fill_data(grub_uint32_t buflen, char *buffer);
|
||||
grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_wimdows_locate_wim(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args);
|
||||
|
||||
VTOY_JSON *vtoy_json_find_item
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
JSON_TYPE enDataType,
|
||||
const char *szKey
|
||||
);
|
||||
int vtoy_json_parse_value
|
||||
(
|
||||
char *pcNewStart,
|
||||
char *pcRawStart,
|
||||
VTOY_JSON *pstJson,
|
||||
const char *pcData,
|
||||
const char **ppcEnd
|
||||
);
|
||||
VTOY_JSON * vtoy_json_create(void);
|
||||
int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData);
|
||||
|
||||
int vtoy_json_scan_parse
|
||||
(
|
||||
const VTOY_JSON *pstJson,
|
||||
grub_uint32_t uiParseNum,
|
||||
JSON_PARSE *pstJsonParse
|
||||
);
|
||||
|
||||
int vtoy_json_scan_array
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
VTOY_JSON **ppstArrayItem
|
||||
);
|
||||
|
||||
int vtoy_json_scan_array_ex
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
VTOY_JSON **ppstArrayItem
|
||||
);
|
||||
int vtoy_json_scan_object
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
VTOY_JSON **ppstObjectItem
|
||||
);
|
||||
int vtoy_json_get_int
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
int *piValue
|
||||
);
|
||||
int vtoy_json_get_uint
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint32_t *puiValue
|
||||
);
|
||||
int vtoy_json_get_uint64
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint64_t *pui64Value
|
||||
);
|
||||
int vtoy_json_get_bool
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint8_t *pbValue
|
||||
);
|
||||
int vtoy_json_get_string
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint32_t uiBufLen,
|
||||
char *pcBuf
|
||||
);
|
||||
const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey);
|
||||
int vtoy_json_destroy(VTOY_JSON *pstJson);
|
||||
|
||||
|
||||
grub_uint32_t CalculateCrc32
|
||||
(
|
||||
const void *Buffer,
|
||||
grub_uint32_t Length,
|
||||
grub_uint32_t InitValue
|
||||
);
|
||||
|
||||
static inline int ventoy_isspace (int c)
|
||||
{
|
||||
return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
|
||||
}
|
||||
|
||||
static inline int ventoy_is_word_end(int c)
|
||||
{
|
||||
return (c == 0 || c == ',' || ventoy_isspace(c));
|
||||
}
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct ventoy_part_table
|
||||
{
|
||||
grub_uint8_t Active; // 0x00 0x80
|
||||
|
||||
grub_uint8_t StartHead;
|
||||
grub_uint16_t StartSector : 6;
|
||||
grub_uint16_t StartCylinder : 10;
|
||||
|
||||
grub_uint8_t FsFlag;
|
||||
|
||||
grub_uint8_t EndHead;
|
||||
grub_uint16_t EndSector : 6;
|
||||
grub_uint16_t EndCylinder : 10;
|
||||
|
||||
grub_uint32_t StartSectorId;
|
||||
grub_uint32_t SectorCount;
|
||||
}ventoy_part_table;
|
||||
|
||||
typedef struct ventoy_mbr_head
|
||||
{
|
||||
grub_uint8_t BootCode[446];
|
||||
ventoy_part_table PartTbl[4];
|
||||
grub_uint8_t Byte55;
|
||||
grub_uint8_t ByteAA;
|
||||
}ventoy_mbr_head;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
typedef struct install_template
|
||||
{
|
||||
char isopath[256];
|
||||
char templatepath[256];
|
||||
|
||||
struct install_template *next;
|
||||
}install_template;
|
||||
|
||||
extern int g_ventoy_last_entry;
|
||||
extern int g_ventoy_memdisk_mode;
|
||||
extern int g_ventoy_iso_raw;
|
||||
extern int g_ventoy_iso_uefi_drv;
|
||||
|
||||
int ventoy_cmp_img(img_info *img1, img_info *img2);
|
||||
void ventoy_swap_img(img_info *img1, img_info *img2);
|
||||
char * ventoy_plugin_get_install_template(const char *isopath);
|
||||
void ventoy_plugin_dump_auto_install(void);
|
||||
int ventoy_fill_windows_rtdata(void *buf, char *isopath);
|
||||
|
||||
|
||||
#endif /* __VENTOY_DEF_H__ */
|
||||
|
736
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c
Normal file
736
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c
Normal file
@@ -0,0 +1,736 @@
|
||||
/******************************************************************************
|
||||
* ventoy_json.c
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <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>
|
||||
#include <grub/net.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/ventoy.h>
|
||||
#include "ventoy_def.h"
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static void json_debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, fmt);
|
||||
grub_vprintf (fmt, args);
|
||||
va_end (args);
|
||||
|
||||
grub_printf("\n");
|
||||
}
|
||||
|
||||
static void vtoy_json_free(VTOY_JSON *pstJsonHead)
|
||||
{
|
||||
VTOY_JSON *pstNext = NULL;
|
||||
|
||||
while (NULL != pstJsonHead)
|
||||
{
|
||||
pstNext = pstJsonHead->pstNext;
|
||||
if ((pstJsonHead->enDataType < JSON_TYPE_BUTT) && (NULL != pstJsonHead->pstChild))
|
||||
{
|
||||
vtoy_json_free(pstJsonHead->pstChild);
|
||||
}
|
||||
|
||||
grub_free(pstJsonHead);
|
||||
pstJsonHead = pstNext;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static char *vtoy_json_skip(const char *pcData)
|
||||
{
|
||||
while ((NULL != pcData) && ('\0' != *pcData) && (*pcData <= 32))
|
||||
{
|
||||
pcData++;
|
||||
}
|
||||
|
||||
return (char *)pcData;
|
||||
}
|
||||
|
||||
VTOY_JSON *vtoy_json_find_item
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
JSON_TYPE enDataType,
|
||||
const char *szKey
|
||||
)
|
||||
{
|
||||
while (NULL != pstJson)
|
||||
{
|
||||
if ((enDataType == pstJson->enDataType) &&
|
||||
(0 == grub_strcmp(szKey, pstJson->pcName)))
|
||||
{
|
||||
return pstJson;
|
||||
}
|
||||
pstJson = pstJson->pstNext;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int vtoy_json_parse_number
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *pcData,
|
||||
const char **ppcEnd
|
||||
)
|
||||
{
|
||||
unsigned long Value;
|
||||
|
||||
Value = grub_strtoul(pcData, (char **)ppcEnd, 10);
|
||||
if (*ppcEnd == pcData)
|
||||
{
|
||||
json_debug("Failed to parse json number %s.", pcData);
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pstJson->enDataType = JSON_TYPE_NUMBER;
|
||||
pstJson->unData.lValue = Value;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
static int vtoy_json_parse_string
|
||||
(
|
||||
char *pcNewStart,
|
||||
char *pcRawStart,
|
||||
VTOY_JSON *pstJson,
|
||||
const char *pcData,
|
||||
const char **ppcEnd
|
||||
)
|
||||
{
|
||||
grub_uint32_t uiLen = 0;
|
||||
const char *pcPos = NULL;
|
||||
const char *pcTmp = pcData + 1;
|
||||
|
||||
*ppcEnd = pcData;
|
||||
|
||||
if ('\"' != *pcData)
|
||||
{
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pcPos = grub_strchr(pcTmp, '\"');
|
||||
if ((NULL == pcPos) || (pcPos < pcTmp))
|
||||
{
|
||||
json_debug("Invalid string %s.", pcData);
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
*ppcEnd = pcPos + 1;
|
||||
uiLen = (grub_uint32_t)(unsigned long)(pcPos - pcTmp);
|
||||
|
||||
pstJson->enDataType = JSON_TYPE_STRING;
|
||||
pstJson->unData.pcStrVal = pcNewStart + (pcTmp - pcRawStart);
|
||||
pstJson->unData.pcStrVal[uiLen] = '\0';
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
static int vtoy_json_parse_array
|
||||
(
|
||||
char *pcNewStart,
|
||||
char *pcRawStart,
|
||||
VTOY_JSON *pstJson,
|
||||
const char *pcData,
|
||||
const char **ppcEnd
|
||||
)
|
||||
{
|
||||
int Ret = JSON_SUCCESS;
|
||||
VTOY_JSON *pstJsonChild = NULL;
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
const char *pcTmp = pcData + 1;
|
||||
|
||||
*ppcEnd = pcData;
|
||||
pstJson->enDataType = JSON_TYPE_ARRAY;
|
||||
|
||||
if ('[' != *pcData)
|
||||
{
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pcTmp = vtoy_json_skip(pcTmp);
|
||||
|
||||
if (']' == *pcTmp)
|
||||
{
|
||||
*ppcEnd = pcTmp + 1;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED);
|
||||
|
||||
Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse array child.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pstJsonChild = pstJson->pstChild;
|
||||
pcTmp = vtoy_json_skip(*ppcEnd);
|
||||
while ((NULL != pcTmp) && (',' == *pcTmp))
|
||||
{
|
||||
JSON_NEW_ITEM(pstJsonItem, JSON_FAILED);
|
||||
pstJsonChild->pstNext = pstJsonItem;
|
||||
pstJsonItem->pstPrev = pstJsonChild;
|
||||
pstJsonChild = pstJsonItem;
|
||||
|
||||
Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse array child.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
pcTmp = vtoy_json_skip(*ppcEnd);
|
||||
}
|
||||
|
||||
if ((NULL != pcTmp) && (']' == *pcTmp))
|
||||
{
|
||||
*ppcEnd = pcTmp + 1;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppcEnd = pcTmp;
|
||||
return JSON_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static int vtoy_json_parse_object
|
||||
(
|
||||
char *pcNewStart,
|
||||
char *pcRawStart,
|
||||
VTOY_JSON *pstJson,
|
||||
const char *pcData,
|
||||
const char **ppcEnd
|
||||
)
|
||||
{
|
||||
int Ret = JSON_SUCCESS;
|
||||
VTOY_JSON *pstJsonChild = NULL;
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
const char *pcTmp = pcData + 1;
|
||||
|
||||
*ppcEnd = pcData;
|
||||
pstJson->enDataType = JSON_TYPE_OBJECT;
|
||||
|
||||
if ('{' != *pcData)
|
||||
{
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pcTmp = vtoy_json_skip(pcTmp);
|
||||
if ('}' == *pcTmp)
|
||||
{
|
||||
*ppcEnd = pcTmp + 1;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED);
|
||||
|
||||
Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse array child.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pstJsonChild = pstJson->pstChild;
|
||||
pstJsonChild->pcName = pstJsonChild->unData.pcStrVal;
|
||||
pstJsonChild->unData.pcStrVal = NULL;
|
||||
|
||||
pcTmp = vtoy_json_skip(*ppcEnd);
|
||||
if ((NULL == pcTmp) || (':' != *pcTmp))
|
||||
{
|
||||
*ppcEnd = pcTmp;
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse array child.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pcTmp = vtoy_json_skip(*ppcEnd);
|
||||
while ((NULL != pcTmp) && (',' == *pcTmp))
|
||||
{
|
||||
JSON_NEW_ITEM(pstJsonItem, JSON_FAILED);
|
||||
pstJsonChild->pstNext = pstJsonItem;
|
||||
pstJsonItem->pstPrev = pstJsonChild;
|
||||
pstJsonChild = pstJsonItem;
|
||||
|
||||
Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse array child.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pcTmp = vtoy_json_skip(*ppcEnd);
|
||||
pstJsonChild->pcName = pstJsonChild->unData.pcStrVal;
|
||||
pstJsonChild->unData.pcStrVal = NULL;
|
||||
if ((NULL == pcTmp) || (':' != *pcTmp))
|
||||
{
|
||||
*ppcEnd = pcTmp;
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse array child.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
pcTmp = vtoy_json_skip(*ppcEnd);
|
||||
}
|
||||
|
||||
if ((NULL != pcTmp) && ('}' == *pcTmp))
|
||||
{
|
||||
*ppcEnd = pcTmp + 1;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppcEnd = pcTmp;
|
||||
return JSON_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
int vtoy_json_parse_value
|
||||
(
|
||||
char *pcNewStart,
|
||||
char *pcRawStart,
|
||||
VTOY_JSON *pstJson,
|
||||
const char *pcData,
|
||||
const char **ppcEnd
|
||||
)
|
||||
{
|
||||
pcData = vtoy_json_skip(pcData);
|
||||
|
||||
switch (*pcData)
|
||||
{
|
||||
case 'n':
|
||||
{
|
||||
if (0 == grub_strncmp(pcData, "null", 4))
|
||||
{
|
||||
pstJson->enDataType = JSON_TYPE_NULL;
|
||||
*ppcEnd = pcData + 4;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
if (0 == grub_strncmp(pcData, "false", 5))
|
||||
{
|
||||
pstJson->enDataType = JSON_TYPE_BOOL;
|
||||
pstJson->unData.lValue = 0;
|
||||
*ppcEnd = pcData + 5;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
{
|
||||
if (0 == grub_strncmp(pcData, "true", 4))
|
||||
{
|
||||
pstJson->enDataType = JSON_TYPE_BOOL;
|
||||
pstJson->unData.lValue = 1;
|
||||
*ppcEnd = pcData + 4;
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '\"':
|
||||
{
|
||||
return vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);
|
||||
}
|
||||
case '[':
|
||||
{
|
||||
return vtoy_json_parse_array(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);
|
||||
}
|
||||
case '{':
|
||||
{
|
||||
return vtoy_json_parse_object(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);
|
||||
}
|
||||
case '-':
|
||||
{
|
||||
return vtoy_json_parse_number(pstJson, pcData, ppcEnd);
|
||||
}
|
||||
default :
|
||||
{
|
||||
if (*pcData >= '0' && *pcData <= '9')
|
||||
{
|
||||
return vtoy_json_parse_number(pstJson, pcData, ppcEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ppcEnd = pcData;
|
||||
json_debug("Invalid json data %u.", (grub_uint8_t)(*pcData));
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
VTOY_JSON * vtoy_json_create(void)
|
||||
{
|
||||
VTOY_JSON *pstJson = NULL;
|
||||
|
||||
pstJson = (VTOY_JSON *)grub_zalloc(sizeof(VTOY_JSON));
|
||||
if (NULL == pstJson)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pstJson;
|
||||
}
|
||||
|
||||
int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData)
|
||||
{
|
||||
grub_uint32_t uiMemSize = 0;
|
||||
int Ret = JSON_SUCCESS;
|
||||
char *pcNewBuf = NULL;
|
||||
const char *pcEnd = NULL;
|
||||
|
||||
uiMemSize = grub_strlen(szJsonData) + 1;
|
||||
pcNewBuf = (char *)grub_malloc(uiMemSize);
|
||||
if (NULL == pcNewBuf)
|
||||
{
|
||||
json_debug("Failed to alloc new buf.");
|
||||
return JSON_FAILED;
|
||||
}
|
||||
grub_memcpy(pcNewBuf, szJsonData, uiMemSize);
|
||||
pcNewBuf[uiMemSize - 1] = 0;
|
||||
|
||||
Ret = vtoy_json_parse_value(pcNewBuf, (char *)szJsonData, pstJson, szJsonData, &pcEnd);
|
||||
if (JSON_SUCCESS != Ret)
|
||||
{
|
||||
json_debug("Failed to parse json data %s start=%p, end=%p:%s.",
|
||||
szJsonData, szJsonData, pcEnd, pcEnd);
|
||||
return JSON_FAILED;
|
||||
}
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_scan_parse
|
||||
(
|
||||
const VTOY_JSON *pstJson,
|
||||
grub_uint32_t uiParseNum,
|
||||
JSON_PARSE *pstJsonParse
|
||||
)
|
||||
{
|
||||
grub_uint32_t i = 0;
|
||||
const VTOY_JSON *pstJsonCur = NULL;
|
||||
JSON_PARSE *pstCurParse = NULL;
|
||||
|
||||
for (pstJsonCur = pstJson; NULL != pstJsonCur; pstJsonCur = pstJsonCur->pstNext)
|
||||
{
|
||||
if ((JSON_TYPE_OBJECT == pstJsonCur->enDataType) ||
|
||||
(JSON_TYPE_ARRAY == pstJsonCur->enDataType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0, pstCurParse = NULL; i < uiParseNum; i++)
|
||||
{
|
||||
if (0 == grub_strcmp(pstJsonParse[i].pcKey, pstJsonCur->pcName))
|
||||
{
|
||||
pstCurParse = pstJsonParse + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == pstCurParse)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (pstJsonCur->enDataType)
|
||||
{
|
||||
case JSON_TYPE_NUMBER:
|
||||
{
|
||||
if (sizeof(grub_uint32_t) == pstCurParse->uiBufSize)
|
||||
{
|
||||
*(grub_uint32_t *)(pstCurParse->pDataBuf) = (grub_uint32_t)pstJsonCur->unData.lValue;
|
||||
}
|
||||
else if (sizeof(grub_uint16_t) == pstCurParse->uiBufSize)
|
||||
{
|
||||
*(grub_uint16_t *)(pstCurParse->pDataBuf) = (grub_uint16_t)pstJsonCur->unData.lValue;
|
||||
}
|
||||
else if (sizeof(grub_uint8_t) == pstCurParse->uiBufSize)
|
||||
{
|
||||
*(grub_uint8_t *)(pstCurParse->pDataBuf) = (grub_uint8_t)pstJsonCur->unData.lValue;
|
||||
}
|
||||
else if ((pstCurParse->uiBufSize > sizeof(grub_uint64_t)))
|
||||
{
|
||||
grub_snprintf((char *)pstCurParse->pDataBuf, pstCurParse->uiBufSize, "%llu",
|
||||
(unsigned long long)(pstJsonCur->unData.lValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
json_debug("Invalid number data buf size %u.", pstCurParse->uiBufSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSON_TYPE_STRING:
|
||||
{
|
||||
grub_strncpy((char *)pstCurParse->pDataBuf, pstJsonCur->unData.pcStrVal, pstCurParse->uiBufSize);
|
||||
break;
|
||||
}
|
||||
case JSON_TYPE_BOOL:
|
||||
{
|
||||
*(grub_uint8_t *)(pstCurParse->pDataBuf) = (pstJsonCur->unData.lValue) > 0 ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
default :
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_scan_array
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
VTOY_JSON **ppstArrayItem
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*ppstArrayItem = pstJsonItem;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_scan_array_ex
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
VTOY_JSON **ppstArrayItem
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*ppstArrayItem = pstJsonItem->pstChild;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_scan_object
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
VTOY_JSON **ppstObjectItem
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_OBJECT, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*ppstObjectItem = pstJsonItem;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_get_int
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
int *piValue
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*piValue = (int)pstJsonItem->unData.lValue;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_get_uint
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint32_t *puiValue
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*puiValue = (grub_uint32_t)pstJsonItem->unData.lValue;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_get_uint64
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint64_t *pui64Value
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*pui64Value = (grub_uint64_t)pstJsonItem->unData.lValue;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_get_bool
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint8_t *pbValue
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_BOOL, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
*pbValue = pstJsonItem->unData.lValue > 0 ? 1 : 0;
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
int vtoy_json_get_string
|
||||
(
|
||||
VTOY_JSON *pstJson,
|
||||
const char *szKey,
|
||||
grub_uint32_t uiBufLen,
|
||||
char *pcBuf
|
||||
)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return JSON_NOT_FOUND;
|
||||
}
|
||||
|
||||
grub_strncpy(pcBuf, pstJsonItem->unData.pcStrVal, uiBufLen);
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey)
|
||||
{
|
||||
VTOY_JSON *pstJsonItem = NULL;
|
||||
|
||||
if ((NULL == pstJson) || (NULL == szKey))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey);
|
||||
if (NULL == pstJsonItem)
|
||||
{
|
||||
json_debug("Key %s is not found in json data.", szKey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pstJsonItem->unData.pcStrVal;
|
||||
}
|
||||
|
||||
int vtoy_json_destroy(VTOY_JSON *pstJson)
|
||||
{
|
||||
if (NULL == pstJson)
|
||||
{
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
||||
if (NULL != pstJson->pstChild)
|
||||
{
|
||||
vtoy_json_free(pstJson->pstChild);
|
||||
}
|
||||
|
||||
if (NULL != pstJson->pstNext)
|
||||
{
|
||||
vtoy_json_free(pstJson->pstNext);
|
||||
}
|
||||
|
||||
grub_free(pstJson);
|
||||
|
||||
return JSON_SUCCESS;
|
||||
}
|
||||
|
1113
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
Normal file
1113
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
278
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
Normal file
278
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/******************************************************************************
|
||||
* ventoy_plugin.c
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <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>
|
||||
#include <grub/net.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/ventoy.h>
|
||||
#include "ventoy_def.h"
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static install_template *g_install_template_head = NULL;
|
||||
|
||||
static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk)
|
||||
{
|
||||
VTOY_JSON *pNode = NULL;
|
||||
VTOY_JSON *pChild = NULL;
|
||||
|
||||
(void)isodisk;
|
||||
|
||||
if (json->enDataType != JSON_TYPE_ARRAY)
|
||||
{
|
||||
debug("Not array %d\n", json->enDataType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
|
||||
{
|
||||
if (pNode->enDataType == JSON_TYPE_OBJECT)
|
||||
{
|
||||
pChild = pNode->pstChild;
|
||||
if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal)
|
||||
{
|
||||
ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk)
|
||||
{
|
||||
const char *value;
|
||||
char filepath[256];
|
||||
|
||||
value = vtoy_json_get_string_ex(json->pstChild, "file");
|
||||
if (value)
|
||||
{
|
||||
if (value[0] == '/')
|
||||
{
|
||||
grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value);
|
||||
}
|
||||
|
||||
if (ventoy_is_file_exist(filepath) == 0)
|
||||
{
|
||||
debug("Theme file %s does not exist\n", filepath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("vtoy_theme %s\n", filepath);
|
||||
grub_env_set("vtoy_theme", filepath);
|
||||
}
|
||||
|
||||
value = vtoy_json_get_string_ex(json->pstChild, "gfxmode");
|
||||
if (value)
|
||||
{
|
||||
debug("vtoy_gfxmode %s\n", value);
|
||||
grub_env_set("vtoy_gfxmode", value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk)
|
||||
{
|
||||
const char *iso = NULL;
|
||||
const char *script = NULL;
|
||||
VTOY_JSON *pNode = NULL;
|
||||
install_template *node = NULL;
|
||||
install_template *next = NULL;
|
||||
|
||||
(void)isodisk;
|
||||
|
||||
if (json->enDataType != JSON_TYPE_ARRAY)
|
||||
{
|
||||
debug("Not array %d\n", json->enDataType);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (g_install_template_head)
|
||||
{
|
||||
for (node = g_install_template_head; node; node = next)
|
||||
{
|
||||
next = node->next;
|
||||
grub_free(node);
|
||||
}
|
||||
|
||||
g_install_template_head = NULL;
|
||||
}
|
||||
|
||||
for (pNode = json->pstChild; pNode; pNode = pNode->pstNext)
|
||||
{
|
||||
iso = vtoy_json_get_string_ex(pNode->pstChild, "image");
|
||||
if (iso && iso[0] == '/')
|
||||
{
|
||||
script = vtoy_json_get_string_ex(pNode->pstChild, "template");
|
||||
if (script && script[0] == '/')
|
||||
{
|
||||
node = grub_zalloc(sizeof(install_template));
|
||||
if (node)
|
||||
{
|
||||
grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso);
|
||||
grub_snprintf(node->templatepath, sizeof(node->templatepath), "%s", script);
|
||||
|
||||
if (g_install_template_head)
|
||||
{
|
||||
node->next = g_install_template_head;
|
||||
}
|
||||
|
||||
g_install_template_head = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static plugin_entry g_plugin_entries[] =
|
||||
{
|
||||
{ "control", ventoy_plugin_control_entry },
|
||||
{ "theme", ventoy_plugin_theme_entry },
|
||||
{ "auto_install", ventoy_plugin_auto_install_entry },
|
||||
};
|
||||
|
||||
static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk)
|
||||
{
|
||||
int i;
|
||||
VTOY_JSON *cur = json;
|
||||
|
||||
while (cur)
|
||||
{
|
||||
for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++)
|
||||
{
|
||||
if (grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0)
|
||||
{
|
||||
debug("Plugin entry for %s\n", g_plugin_entries[i].key);
|
||||
g_plugin_entries[i].entryfunc(cur, isodisk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cur = cur->pstNext;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
int ret = 0;
|
||||
char *buf = NULL;
|
||||
grub_file_t file;
|
||||
VTOY_JSON *json = NULL;
|
||||
|
||||
(void)ctxt;
|
||||
(void)argc;
|
||||
|
||||
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/ventoy/ventoy.json", args[0]);
|
||||
if (!file)
|
||||
{
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
debug("json configuration file size %d\n", (int)file->size);
|
||||
|
||||
buf = grub_malloc(file->size + 1);
|
||||
if (!buf)
|
||||
{
|
||||
grub_file_close(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf[file->size] = 0;
|
||||
grub_file_read(file, buf, file->size);
|
||||
grub_file_close(file);
|
||||
|
||||
json = vtoy_json_create();
|
||||
if (!json)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ret = vtoy_json_parse(json, buf);
|
||||
if (ret)
|
||||
{
|
||||
debug("Failed to parse json string %d\n", ret);
|
||||
grub_free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ventoy_parse_plugin_config(json->pstChild, args[0]);
|
||||
|
||||
vtoy_json_destroy(json);
|
||||
|
||||
grub_free(buf);
|
||||
|
||||
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
|
||||
}
|
||||
|
||||
|
||||
void ventoy_plugin_dump_auto_install(void)
|
||||
{
|
||||
install_template *node = NULL;
|
||||
|
||||
for (node = g_install_template_head; node; node = node->next)
|
||||
{
|
||||
grub_printf("IMAGE:<%s>\n", node->isopath);
|
||||
grub_printf("SCRIPT:<%s>\n\n", node->templatepath);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
char * ventoy_plugin_get_install_template(const char *isopath)
|
||||
{
|
||||
install_template *node = NULL;
|
||||
|
||||
for (node = g_install_template_head; node; node = node->next)
|
||||
{
|
||||
if (grub_strcmp(node->isopath, isopath) == 0)
|
||||
{
|
||||
return node->templatepath;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
959
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c
Normal file
959
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c
Normal file
@@ -0,0 +1,959 @@
|
||||
/******************************************************************************
|
||||
* ventoy_windows.c
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <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>
|
||||
#include <grub/net.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/ventoy.h>
|
||||
#include "ventoy_def.h"
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
wim_hash g_old_hash;
|
||||
wim_tail g_wim_data;
|
||||
|
||||
static wim_lookup_entry *g_replace_look = NULL;
|
||||
|
||||
grub_ssize_t lzx_decompress ( const void *data, grub_size_t len, void *buf );
|
||||
|
||||
static int wim_name_cmp(const char *search, grub_uint16_t *name, grub_uint16_t namelen)
|
||||
{
|
||||
char c1 = vtoy_to_upper(*search);
|
||||
char c2 = vtoy_to_upper(*name);
|
||||
|
||||
while (namelen > 0 && (c1 == c2))
|
||||
{
|
||||
search++;
|
||||
name++;
|
||||
namelen--;
|
||||
|
||||
c1 = vtoy_to_upper(*search);
|
||||
c2 = vtoy_to_upper(*name);
|
||||
}
|
||||
|
||||
if (namelen == 0 && *search == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ventoy_is_pe64(grub_uint8_t *buffer)
|
||||
{
|
||||
grub_uint32_t pe_off;
|
||||
|
||||
if (buffer[0] != 'M' || buffer[1] != 'Z')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pe_off = *(grub_uint32_t *)(buffer + 60);
|
||||
|
||||
if (buffer[pe_off] != 'P' || buffer[pe_off + 1] != 'E')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*(grub_uint16_t *)(buffer + pe_off + 24) == 0x020b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
(void)ctxt;
|
||||
(void)argc;
|
||||
(void)args;
|
||||
|
||||
check_free(g_wim_data.jump_bin_data, grub_free);
|
||||
check_free(g_wim_data.new_meta_data, grub_free);
|
||||
check_free(g_wim_data.new_lookup_data, grub_free);
|
||||
|
||||
grub_memset(&g_wim_data, 0, sizeof(g_wim_data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_load_jump_exe(const char *path, grub_uint8_t **data, grub_uint32_t *size, wim_hash *hash)
|
||||
{
|
||||
grub_uint32_t i;
|
||||
grub_uint32_t align;
|
||||
grub_file_t file;
|
||||
|
||||
debug("windows load jump %s\n", path);
|
||||
|
||||
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", path);
|
||||
if (!file)
|
||||
{
|
||||
debug("Can't open file %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
align = ventoy_align((int)file->size, 2048);
|
||||
|
||||
debug("file %s size:%d align:%u\n", path, (int)file->size, align);
|
||||
|
||||
*size = (grub_uint32_t)file->size;
|
||||
*data = (grub_uint8_t *)grub_malloc(align);
|
||||
if ((*data) == NULL)
|
||||
{
|
||||
debug("Failed to alloc memory size %u\n", align);
|
||||
goto end;
|
||||
}
|
||||
|
||||
grub_file_read(file, (*data), file->size);
|
||||
|
||||
if (hash)
|
||||
{
|
||||
grub_crypto_hash(GRUB_MD_SHA1, hash->sha1, (*data), file->size);
|
||||
|
||||
if (g_ventoy_debug)
|
||||
{
|
||||
debug("%s", "jump bin 64 hash: ");
|
||||
for (i = 0; i < sizeof(hash->sha1); i++)
|
||||
{
|
||||
ventoy_debug("%02x ", hash->sha1[i]);
|
||||
}
|
||||
ventoy_debug("\n");
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
grub_file_close(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_get_override_info(grub_file_t file)
|
||||
{
|
||||
grub_uint32_t start_block;
|
||||
grub_uint64_t file_offset;
|
||||
grub_uint64_t override_offset;
|
||||
grub_uint32_t override_len;
|
||||
grub_uint64_t fe_entry_size_offset;
|
||||
|
||||
if (grub_strcmp(file->fs->name, "iso9660") == 0)
|
||||
{
|
||||
g_wim_data.iso_type = 0;
|
||||
override_len = sizeof(ventoy_iso9660_override);
|
||||
override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
|
||||
|
||||
grub_file_read(file, &start_block, 1); // just read for hook trigger
|
||||
file_offset = grub_iso9660_get_last_read_pos(file);
|
||||
|
||||
debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n",
|
||||
(ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_wim_data.iso_type = 1;
|
||||
override_len = sizeof(ventoy_udf_override);
|
||||
override_offset = grub_udf_get_last_file_attr_offset(file, &start_block, &fe_entry_size_offset);
|
||||
|
||||
file_offset = grub_udf_get_file_offset(file);
|
||||
|
||||
debug("UDF wim size:%llu override_offset:%llu file_offset:%llu start_block=%u\n",
|
||||
(ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset, start_block);
|
||||
}
|
||||
|
||||
g_wim_data.file_offset = file_offset;
|
||||
g_wim_data.udf_start_block = start_block;
|
||||
g_wim_data.fe_entry_size_offset = fe_entry_size_offset;
|
||||
g_wim_data.override_offset = override_offset;
|
||||
g_wim_data.override_len = override_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_read_resource(grub_file_t fp, wim_resource_header *head, void **buffer)
|
||||
{
|
||||
int decompress_len = 0;
|
||||
int total_decompress = 0;
|
||||
grub_uint32_t i = 0;
|
||||
grub_uint32_t chunk_num = 0;
|
||||
grub_uint32_t chunk_size = 0;
|
||||
grub_uint32_t last_chunk_size = 0;
|
||||
grub_uint32_t last_decompress_size = 0;
|
||||
grub_uint32_t cur_offset = 0;
|
||||
grub_uint8_t *cur_dst = NULL;
|
||||
grub_uint8_t *buffer_compress = NULL;
|
||||
grub_uint8_t *buffer_decompress = NULL;
|
||||
grub_uint32_t *chunk_offset = NULL;
|
||||
|
||||
buffer_decompress = (grub_uint8_t *)grub_malloc(head->raw_size + head->size_in_wim);
|
||||
if (NULL == buffer_decompress)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_file_seek(fp, head->offset);
|
||||
|
||||
if (head->size_in_wim == head->raw_size)
|
||||
{
|
||||
grub_file_read(fp, buffer_decompress, head->size_in_wim);
|
||||
*buffer = buffer_decompress;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer_compress = buffer_decompress + head->raw_size;
|
||||
grub_file_read(fp, buffer_compress, head->size_in_wim);
|
||||
|
||||
chunk_num = (head->raw_size + WIM_CHUNK_LEN - 1) / WIM_CHUNK_LEN;
|
||||
cur_offset = (chunk_num - 1) * 4;
|
||||
chunk_offset = (grub_uint32_t *)buffer_compress;
|
||||
|
||||
cur_dst = buffer_decompress;
|
||||
|
||||
for (i = 0; i < chunk_num - 1; i++)
|
||||
{
|
||||
chunk_size = (i == 0) ? chunk_offset[i] : chunk_offset[i] - chunk_offset[i - 1];
|
||||
|
||||
if (WIM_CHUNK_LEN == chunk_size)
|
||||
{
|
||||
grub_memcpy(cur_dst, buffer_compress + cur_offset, chunk_size);
|
||||
decompress_len = (int)chunk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, chunk_size, cur_dst);
|
||||
}
|
||||
|
||||
//debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len);
|
||||
|
||||
total_decompress += decompress_len;
|
||||
cur_dst += decompress_len;
|
||||
cur_offset += chunk_size;
|
||||
}
|
||||
|
||||
/* last chunk */
|
||||
last_chunk_size = (grub_uint32_t)(head->size_in_wim - cur_offset);
|
||||
last_decompress_size = head->raw_size - total_decompress;
|
||||
|
||||
if (last_chunk_size < WIM_CHUNK_LEN && last_chunk_size == last_decompress_size)
|
||||
{
|
||||
debug("Last chunk %u uncompressed\n", last_chunk_size);
|
||||
grub_memcpy(cur_dst, buffer_compress + cur_offset, last_chunk_size);
|
||||
decompress_len = (int)last_chunk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst);
|
||||
}
|
||||
|
||||
cur_dst += decompress_len;
|
||||
total_decompress += decompress_len;
|
||||
|
||||
if (cur_dst != buffer_decompress + head->raw_size)
|
||||
{
|
||||
debug("head->size_in_wim:%llu head->raw_size:%llu cur_dst:%p buffer_decompress:%p total_decompress:%d\n",
|
||||
(ulonglong)head->size_in_wim, (ulonglong)head->raw_size, cur_dst, buffer_decompress, total_decompress);
|
||||
grub_free(buffer_decompress);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*buffer = buffer_decompress;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static wim_directory_entry * search_wim_dirent(wim_directory_entry *dir, const char *search_name)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (dir->len && dir->name_len)
|
||||
{
|
||||
if (wim_name_cmp(search_name, (grub_uint16_t *)(dir + 1), dir->name_len / 2) == 0)
|
||||
{
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
dir = (wim_directory_entry *)((grub_uint8_t *)dir + dir->len);
|
||||
} while(dir->len);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static wim_directory_entry * search_full_wim_dirent
|
||||
(
|
||||
void *meta_data,
|
||||
wim_directory_entry *dir,
|
||||
const char **path
|
||||
)
|
||||
{
|
||||
wim_directory_entry *subdir = NULL;
|
||||
wim_directory_entry *search = dir;
|
||||
|
||||
while (*path)
|
||||
{
|
||||
subdir = (wim_directory_entry *)((char *)meta_data + search->subdir);
|
||||
search = search_wim_dirent(subdir, *path);
|
||||
if (!search)
|
||||
{
|
||||
debug("%s search failed\n", *path);
|
||||
}
|
||||
|
||||
path++;
|
||||
}
|
||||
return search;
|
||||
}
|
||||
|
||||
static wim_directory_entry * search_replace_wim_dirent(void *meta_data, wim_directory_entry *dir)
|
||||
{
|
||||
wim_directory_entry *wim_dirent = NULL;
|
||||
const char *winpeshl_path[] = { "Windows", "System32", "winpeshl.exe", NULL };
|
||||
const char *pecmd_path[] = { "Windows", "System32", "PECMD.exe", NULL };
|
||||
|
||||
wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path);
|
||||
if (wim_dirent)
|
||||
{
|
||||
return wim_dirent;
|
||||
}
|
||||
|
||||
wim_dirent = search_full_wim_dirent(meta_data, dir, pecmd_path);
|
||||
if (wim_dirent)
|
||||
{
|
||||
return wim_dirent;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static wim_lookup_entry * ventoy_find_look_entry(wim_header *header, wim_lookup_entry *lookup, wim_hash *hash)
|
||||
{
|
||||
grub_uint32_t i = 0;
|
||||
|
||||
for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++)
|
||||
{
|
||||
if (grub_memcmp(&lookup[i].hash, hash, sizeof(wim_hash)) == 0)
|
||||
{
|
||||
return lookup + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static wim_lookup_entry * ventoy_find_meta_entry(wim_header *header, wim_lookup_entry *lookup)
|
||||
{
|
||||
grub_uint32_t i = 0;
|
||||
grub_uint32_t index = 0;;
|
||||
|
||||
if ((header == NULL) || (lookup == NULL))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++)
|
||||
{
|
||||
if (lookup[i].resource.flags & RESHDR_FLAG_METADATA)
|
||||
{
|
||||
index++;
|
||||
if (index == header->boot_index)
|
||||
{
|
||||
return lookup + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ventoy_update_all_hash(void *meta_data, wim_directory_entry *dir)
|
||||
{
|
||||
if ((meta_data == NULL) || (dir == NULL))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dir->len < sizeof(wim_directory_entry))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (dir->subdir == 0 && grub_memcmp(dir->hash.sha1, g_old_hash.sha1, sizeof(wim_hash)) == 0)
|
||||
{
|
||||
debug("find target file, name_len:%u upadte hash\n", dir->name_len);
|
||||
grub_memcpy(dir->hash.sha1, &(g_wim_data.bin_hash), sizeof(wim_hash));
|
||||
}
|
||||
|
||||
if (dir->subdir)
|
||||
{
|
||||
ventoy_update_all_hash(meta_data, (wim_directory_entry *)((char *)meta_data + dir->subdir));
|
||||
}
|
||||
|
||||
dir = (wim_directory_entry *)((char *)dir + dir->len);
|
||||
} while (dir->len >= sizeof(wim_directory_entry));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_cat_exe_file_data(grub_uint32_t exe_len, grub_uint8_t *exe_data)
|
||||
{
|
||||
int pe64 = 0;
|
||||
char file[256];
|
||||
grub_uint32_t jump_len = 0;
|
||||
grub_uint32_t jump_align = 0;
|
||||
grub_uint8_t *jump_data = NULL;
|
||||
|
||||
pe64 = ventoy_is_pe64(exe_data);
|
||||
|
||||
grub_snprintf(file, sizeof(file), "%s/vtoyjump%d.exe", grub_env_get("vtoy_path"), pe64 ? 64 : 32);
|
||||
ventoy_load_jump_exe(file, &jump_data, &jump_len, NULL);
|
||||
jump_align = ventoy_align(jump_len, 16);
|
||||
|
||||
g_wim_data.jump_exe_len = jump_len;
|
||||
g_wim_data.bin_raw_len = jump_align + sizeof(ventoy_os_param) + sizeof(ventoy_windows_data) + exe_len;
|
||||
g_wim_data.bin_align_len = ventoy_align(g_wim_data.bin_raw_len, 2048);
|
||||
|
||||
g_wim_data.jump_bin_data = grub_malloc(g_wim_data.bin_align_len);
|
||||
if (g_wim_data.jump_bin_data)
|
||||
{
|
||||
grub_memcpy(g_wim_data.jump_bin_data, jump_data, jump_len);
|
||||
grub_memcpy(g_wim_data.jump_bin_data + jump_align + sizeof(ventoy_os_param) + sizeof(ventoy_windows_data), exe_data, exe_len);
|
||||
}
|
||||
|
||||
debug("jump_exe_len:%u bin_raw_len:%u bin_align_len:%u\n",
|
||||
g_wim_data.jump_exe_len, g_wim_data.bin_raw_len, g_wim_data.bin_align_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ventoy_fill_windows_rtdata(void *buf, char *isopath)
|
||||
{
|
||||
char *pos = NULL;
|
||||
char *script = NULL;
|
||||
ventoy_windows_data *data = (ventoy_windows_data *)buf;
|
||||
|
||||
grub_memset(data, 0, sizeof(ventoy_windows_data));
|
||||
|
||||
pos = grub_strstr(isopath, "/");
|
||||
if (!pos)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
script = ventoy_plugin_get_install_template(pos);
|
||||
if (script)
|
||||
{
|
||||
debug("auto install script <%s>\n", script);
|
||||
grub_snprintf(data->auto_install_script, sizeof(data->auto_install_script) - 1, "%s", script);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("auto install script not found %p\n", pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_update_before_chain(ventoy_os_param *param, char *isopath)
|
||||
{
|
||||
grub_uint32_t jump_align = 0;
|
||||
wim_lookup_entry *meta_look = NULL;
|
||||
wim_security_header *security = NULL;
|
||||
wim_directory_entry *rootdir = NULL;
|
||||
wim_header *head = &(g_wim_data.wim_header);
|
||||
wim_lookup_entry *lookup = (wim_lookup_entry *)g_wim_data.new_lookup_data;
|
||||
|
||||
jump_align = ventoy_align(g_wim_data.jump_exe_len, 16);
|
||||
if (g_wim_data.jump_bin_data)
|
||||
{
|
||||
grub_memcpy(g_wim_data.jump_bin_data + jump_align, param, sizeof(ventoy_os_param));
|
||||
ventoy_fill_windows_rtdata(g_wim_data.jump_bin_data + jump_align + sizeof(ventoy_os_param), isopath);
|
||||
}
|
||||
|
||||
grub_crypto_hash(GRUB_MD_SHA1, g_wim_data.bin_hash.sha1, g_wim_data.jump_bin_data, g_wim_data.bin_raw_len);
|
||||
|
||||
security = (wim_security_header *)g_wim_data.new_meta_data;
|
||||
rootdir = (wim_directory_entry *)(g_wim_data.new_meta_data + ((security->len + 7) & 0xFFFFFFF8U));
|
||||
|
||||
/* update all winpeshl.exe dirent entry's hash */
|
||||
ventoy_update_all_hash(g_wim_data.new_meta_data, rootdir);
|
||||
|
||||
/* update winpeshl.exe lookup entry data (hash/offset/length) */
|
||||
if (g_replace_look)
|
||||
{
|
||||
debug("update replace lookup entry_id:%ld\n", ((long)g_replace_look - (long)lookup) / sizeof(wim_lookup_entry));
|
||||
g_replace_look->resource.raw_size = g_wim_data.bin_raw_len;
|
||||
g_replace_look->resource.size_in_wim = g_wim_data.bin_raw_len;
|
||||
g_replace_look->resource.flags = 0;
|
||||
g_replace_look->resource.offset = g_wim_data.wim_align_size;
|
||||
|
||||
grub_memcpy(g_replace_look->hash.sha1, g_wim_data.bin_hash.sha1, sizeof(wim_hash));
|
||||
}
|
||||
|
||||
/* update metadata's hash */
|
||||
meta_look = ventoy_find_meta_entry(head, lookup);
|
||||
if (meta_look)
|
||||
{
|
||||
debug("find meta lookup entry_id:%ld\n", ((long)meta_look - (long)lookup) / sizeof(wim_lookup_entry));
|
||||
grub_memcpy(&meta_look->resource, &head->metadata, sizeof(wim_resource_header));
|
||||
grub_crypto_hash(GRUB_MD_SHA1, meta_look->hash.sha1, g_wim_data.new_meta_data, g_wim_data.new_meta_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_err_t ventoy_cmd_wimdows_locate_wim(grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
int rc;
|
||||
grub_file_t file;
|
||||
grub_uint32_t exe_len;
|
||||
grub_uint8_t *exe_data = NULL;
|
||||
grub_uint8_t *decompress_data = NULL;
|
||||
wim_lookup_entry *lookup = NULL;
|
||||
wim_security_header *security = NULL;
|
||||
wim_directory_entry *rootdir = NULL;
|
||||
wim_directory_entry *search = NULL;
|
||||
wim_header *head = &(g_wim_data.wim_header);
|
||||
|
||||
(void)ctxt;
|
||||
(void)argc;
|
||||
|
||||
debug("windows locate wim start %s\n", args[0]);
|
||||
|
||||
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
|
||||
if (!file)
|
||||
{
|
||||
return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]);
|
||||
}
|
||||
|
||||
ventoy_get_override_info(file);
|
||||
|
||||
grub_file_seek(file, 0);
|
||||
grub_file_read(file, head, sizeof(wim_header));
|
||||
|
||||
if (grub_memcmp(head->signature, WIM_HEAD_SIGNATURE, sizeof(head->signature)))
|
||||
{
|
||||
debug("Not a valid wim file %s\n", (char *)head->signature);
|
||||
grub_file_close(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (head->flags & FLAG_HEADER_COMPRESS_XPRESS)
|
||||
{
|
||||
debug("Xpress compress is not supported 0x%x\n", head->flags);
|
||||
grub_file_close(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = ventoy_read_resource(file, &head->metadata, (void **)&decompress_data);
|
||||
if (rc)
|
||||
{
|
||||
grub_printf("failed to read meta data %d\n", rc);
|
||||
grub_file_close(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
security = (wim_security_header *)decompress_data;
|
||||
rootdir = (wim_directory_entry *)(decompress_data + ((security->len + 7) & 0xFFFFFFF8U));
|
||||
|
||||
/* search winpeshl.exe dirent entry */
|
||||
search = search_replace_wim_dirent(decompress_data, rootdir);
|
||||
if (!search)
|
||||
{
|
||||
debug("Failed to find replace file %p\n", search);
|
||||
grub_file_close(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
debug("find replace file at %p\n", search);
|
||||
|
||||
grub_memcpy(&g_old_hash, search->hash.sha1, sizeof(wim_hash));
|
||||
|
||||
debug("read lookup offset:%llu size:%llu\n", (ulonglong)head->lookup.offset, (ulonglong)head->lookup.raw_size);
|
||||
lookup = grub_malloc(head->lookup.raw_size);
|
||||
grub_file_seek(file, head->lookup.offset);
|
||||
grub_file_read(file, lookup, head->lookup.raw_size);
|
||||
|
||||
/* find and extact winpeshl.exe */
|
||||
g_replace_look = ventoy_find_look_entry(head, lookup, &g_old_hash);
|
||||
if (g_replace_look)
|
||||
{
|
||||
exe_len = (grub_uint32_t)g_replace_look->resource.raw_size;
|
||||
debug("find replace lookup entry_id:%ld raw_size:%u\n",
|
||||
((long)g_replace_look - (long)lookup) / sizeof(wim_lookup_entry), exe_len);
|
||||
|
||||
if (0 == ventoy_read_resource(file, &(g_replace_look->resource), (void **)&(exe_data)))
|
||||
{
|
||||
ventoy_cat_exe_file_data(exe_len, exe_data);
|
||||
grub_free(exe_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("failed to read replace file meta data %u\n", exe_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("failed to find lookup entry for replace file 0x%02x 0x%02x\n", g_old_hash.sha1[0], g_old_hash.sha1[1]);
|
||||
}
|
||||
|
||||
g_wim_data.wim_raw_size = (grub_uint32_t)file->size;
|
||||
g_wim_data.wim_align_size = ventoy_align(g_wim_data.wim_raw_size, 2048);
|
||||
|
||||
check_free(g_wim_data.new_meta_data, grub_free);
|
||||
g_wim_data.new_meta_data = decompress_data;
|
||||
g_wim_data.new_meta_len = head->metadata.raw_size;
|
||||
g_wim_data.new_meta_align_len = ventoy_align(g_wim_data.new_meta_len, 2048);
|
||||
|
||||
check_free(g_wim_data.new_lookup_data, grub_free);
|
||||
g_wim_data.new_lookup_data = (grub_uint8_t *)lookup;
|
||||
g_wim_data.new_lookup_len = (grub_uint32_t)head->lookup.raw_size;
|
||||
g_wim_data.new_lookup_align_len = ventoy_align(g_wim_data.new_lookup_len, 2048);
|
||||
|
||||
head->metadata.flags = RESHDR_FLAG_METADATA;
|
||||
head->metadata.offset = g_wim_data.wim_align_size + g_wim_data.bin_align_len;
|
||||
head->metadata.size_in_wim = g_wim_data.new_meta_len;
|
||||
head->metadata.raw_size = g_wim_data.new_meta_len;
|
||||
|
||||
head->lookup.flags = 0;
|
||||
head->lookup.offset = head->metadata.offset + g_wim_data.new_meta_align_len;
|
||||
head->lookup.size_in_wim = g_wim_data.new_lookup_len;
|
||||
head->lookup.raw_size = g_wim_data.new_lookup_len;
|
||||
|
||||
grub_file_close(file);
|
||||
|
||||
debug("%s", "windows locate wim finish\n");
|
||||
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
|
||||
}
|
||||
|
||||
static grub_uint32_t ventoy_get_override_chunk_num(void)
|
||||
{
|
||||
/* 1: block count in Partition Descriptor */
|
||||
/* 2: file_size in file_entry or extend_file_entry */
|
||||
/* 3: data_size and position in extend data short ad */
|
||||
/* 4: new wim file header */
|
||||
return 4;
|
||||
}
|
||||
|
||||
static void ventoy_windows_fill_override_data( grub_uint64_t isosize, void *override)
|
||||
{
|
||||
grub_uint32_t data32;
|
||||
grub_uint64_t data64;
|
||||
grub_uint64_t sector;
|
||||
grub_uint32_t new_wim_size;
|
||||
ventoy_override_chunk *cur;
|
||||
|
||||
sector = (isosize + 2047) / 2048;
|
||||
|
||||
cur = (ventoy_override_chunk *)override;
|
||||
|
||||
new_wim_size = g_wim_data.wim_align_size + g_wim_data.bin_align_len +
|
||||
g_wim_data.new_meta_align_len + g_wim_data.new_lookup_align_len;
|
||||
|
||||
if (g_wim_data.iso_type == 0)
|
||||
{
|
||||
ventoy_iso9660_override *dirent = (ventoy_iso9660_override *)g_wim_data.override_data;
|
||||
|
||||
dirent->first_sector = (grub_uint32_t)sector;
|
||||
dirent->size = new_wim_size;
|
||||
dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
|
||||
dirent->size_be = grub_swap_bytes32(dirent->size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ventoy_udf_override *udf = (ventoy_udf_override *)g_wim_data.override_data;
|
||||
udf->length = new_wim_size;
|
||||
udf->position = (grub_uint32_t)sector - g_wim_data.udf_start_block;
|
||||
}
|
||||
|
||||
//override 1: sector number in pd data
|
||||
cur->img_offset = grub_udf_get_last_pd_size_offset();
|
||||
cur->override_size = 4;
|
||||
data32 = sector - g_wim_data.udf_start_block + (new_wim_size / 2048);
|
||||
grub_memcpy(cur->override_data, &(data32), 4);
|
||||
|
||||
//override 2: filesize in file_entry
|
||||
cur++;
|
||||
cur->img_offset = g_wim_data.fe_entry_size_offset;
|
||||
cur->override_size = 8;
|
||||
data64 = new_wim_size;
|
||||
grub_memcpy(cur->override_data, &(data64), 8);
|
||||
|
||||
/* override 3: position and length in extend data */
|
||||
cur++;
|
||||
cur->img_offset = g_wim_data.override_offset;
|
||||
cur->override_size = g_wim_data.override_len;
|
||||
grub_memcpy(cur->override_data, g_wim_data.override_data, cur->override_size);
|
||||
|
||||
/* override 4: new wim file header */
|
||||
cur++;
|
||||
cur->img_offset = g_wim_data.file_offset;
|
||||
cur->override_size = sizeof(wim_header);
|
||||
grub_memcpy(cur->override_data, &(g_wim_data.wim_header), cur->override_size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void ventoy_windows_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
|
||||
{
|
||||
grub_uint64_t sector;
|
||||
grub_uint32_t offset;
|
||||
grub_uint32_t wim_secs;
|
||||
grub_uint32_t mem_secs;
|
||||
char *override = NULL;
|
||||
ventoy_virt_chunk *cur = NULL;
|
||||
|
||||
sector = (isosize + 2047) / 2048;
|
||||
offset = sizeof(ventoy_virt_chunk);
|
||||
|
||||
wim_secs = g_wim_data.wim_align_size / 2048;
|
||||
mem_secs = (g_wim_data.bin_align_len + g_wim_data.new_meta_align_len + g_wim_data.new_lookup_align_len) / 2048;
|
||||
|
||||
override = (char *)chain + chain->virt_chunk_offset;
|
||||
cur = (ventoy_virt_chunk *)override;
|
||||
|
||||
cur->remap_sector_start = sector;
|
||||
cur->remap_sector_end = cur->remap_sector_start + wim_secs;
|
||||
cur->org_sector_start = (grub_uint32_t)(g_wim_data.file_offset / 2048);
|
||||
|
||||
cur->mem_sector_start = cur->remap_sector_end;
|
||||
cur->mem_sector_end = cur->mem_sector_start + mem_secs;
|
||||
cur->mem_sector_offset = offset;
|
||||
|
||||
grub_memcpy(override + offset, g_wim_data.jump_bin_data, g_wim_data.bin_raw_len);
|
||||
offset += g_wim_data.bin_align_len;
|
||||
|
||||
grub_memcpy(override + offset, g_wim_data.new_meta_data, g_wim_data.new_meta_len);
|
||||
offset += g_wim_data.new_meta_align_len;
|
||||
|
||||
grub_memcpy(override + offset, g_wim_data.new_lookup_data, g_wim_data.new_lookup_len);
|
||||
offset += g_wim_data.new_lookup_align_len;
|
||||
|
||||
chain->virt_img_size_in_bytes += g_wim_data.wim_align_size +
|
||||
g_wim_data.bin_align_len +
|
||||
g_wim_data.new_meta_align_len +
|
||||
g_wim_data.new_lookup_align_len;
|
||||
return;
|
||||
}
|
||||
|
||||
static int ventoy_windows_drive_map(ventoy_chain_head *chain)
|
||||
{
|
||||
grub_disk_t disk;
|
||||
|
||||
debug("drive map begin <%p> ...\n", chain);
|
||||
|
||||
if (chain->disk_drive == 0x80)
|
||||
{
|
||||
disk = grub_disk_open("hd1");
|
||||
if (disk)
|
||||
{
|
||||
grub_disk_close(disk);
|
||||
debug("drive map needed %p\n", disk);
|
||||
chain->drive_map = 0x81;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("failed to open disk %s\n", "hd1");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("no need to map 0x%x\n", chain->disk_drive);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
int unknown_image = 0;
|
||||
int ventoy_compatible = 0;
|
||||
grub_uint32_t size = 0;
|
||||
grub_uint64_t isosize = 0;
|
||||
grub_uint32_t boot_catlog = 0;
|
||||
grub_uint32_t img_chunk_size = 0;
|
||||
grub_uint32_t override_size = 0;
|
||||
grub_uint32_t virt_chunk_size = 0;
|
||||
grub_file_t file;
|
||||
grub_disk_t disk;
|
||||
const char *pLastChain = NULL;
|
||||
const char *compatible;
|
||||
ventoy_chain_head *chain;
|
||||
char envbuf[64];
|
||||
|
||||
(void)ctxt;
|
||||
(void)argc;
|
||||
|
||||
debug("chain data begin <%s> ...\n", args[0]);
|
||||
|
||||
compatible = grub_env_get("ventoy_compatible");
|
||||
if (compatible && compatible[0] == 'Y')
|
||||
{
|
||||
ventoy_compatible = 1;
|
||||
}
|
||||
|
||||
if (NULL == g_img_chunk_list.chunk)
|
||||
{
|
||||
grub_printf("ventoy not ready\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 == ventoy_compatible && g_wim_data.new_meta_data == NULL)
|
||||
{
|
||||
unknown_image = 1;
|
||||
debug("Warning: %s was not recognized by Ventoy\n", args[0]);
|
||||
}
|
||||
|
||||
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
|
||||
if (!file)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
isosize = file->size;
|
||||
|
||||
boot_catlog = ventoy_get_iso_boot_catlog(file);
|
||||
if (boot_catlog)
|
||||
{
|
||||
if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
|
||||
{
|
||||
grub_env_set("LoadIsoEfiDriver", "on");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ventoy_is_efi_os())
|
||||
{
|
||||
grub_env_set("LoadIsoEfiDriver", "on");
|
||||
}
|
||||
else
|
||||
{
|
||||
return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
|
||||
|
||||
if (ventoy_compatible || unknown_image)
|
||||
{
|
||||
size = sizeof(ventoy_chain_head) + img_chunk_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
override_size = ventoy_get_override_chunk_num() * sizeof(ventoy_override_chunk);
|
||||
virt_chunk_size = sizeof(ventoy_virt_chunk) + g_wim_data.bin_align_len +
|
||||
g_wim_data.new_meta_align_len + g_wim_data.new_lookup_align_len;;
|
||||
size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
|
||||
}
|
||||
|
||||
pLastChain = grub_env_get("vtoy_chain_mem_addr");
|
||||
if (pLastChain)
|
||||
{
|
||||
chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
|
||||
if (chain)
|
||||
{
|
||||
debug("free last chain memory %p\n", chain);
|
||||
grub_free(chain);
|
||||
}
|
||||
}
|
||||
|
||||
chain = grub_malloc(size);
|
||||
if (!chain)
|
||||
{
|
||||
grub_printf("Failed to alloc chain memory size %u\n", size);
|
||||
grub_file_close(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
|
||||
grub_env_set("vtoy_chain_mem_addr", envbuf);
|
||||
grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
|
||||
grub_env_set("vtoy_chain_mem_size", envbuf);
|
||||
|
||||
grub_memset(chain, 0, sizeof(ventoy_chain_head));
|
||||
|
||||
/* part 1: os parameter */
|
||||
ventoy_fill_os_param(file, &(chain->os_param));
|
||||
|
||||
if (g_wim_data.jump_bin_data && g_wim_data.new_meta_data)
|
||||
{
|
||||
ventoy_update_before_chain(&(chain->os_param), args[0]);
|
||||
}
|
||||
|
||||
/* part 2: chain head */
|
||||
disk = file->device->disk;
|
||||
chain->disk_drive = disk->id;
|
||||
chain->disk_sector_size = (1 << disk->log_sector_size);
|
||||
chain->real_img_size_in_bytes = file->size;
|
||||
chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
|
||||
chain->boot_catalog = boot_catlog;
|
||||
|
||||
if (!ventoy_is_efi_os())
|
||||
{
|
||||
grub_file_seek(file, boot_catlog * 2048);
|
||||
grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
|
||||
}
|
||||
|
||||
/* part 3: image chunk */
|
||||
chain->img_chunk_offset = sizeof(ventoy_chain_head);
|
||||
chain->img_chunk_num = g_img_chunk_list.cur_chunk;
|
||||
grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
|
||||
|
||||
if (ventoy_compatible || unknown_image)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (g_wim_data.new_meta_data == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* part 4: override chunk */
|
||||
chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
|
||||
chain->override_chunk_num = ventoy_get_override_chunk_num();
|
||||
ventoy_windows_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
|
||||
|
||||
/* part 5: virt chunk */
|
||||
chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
|
||||
chain->virt_chunk_num = 1;
|
||||
ventoy_windows_fill_virt_data(isosize, chain);
|
||||
|
||||
if (ventoy_is_efi_os() == 0)
|
||||
{
|
||||
ventoy_windows_drive_map(chain);
|
||||
}
|
||||
|
||||
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
|
||||
}
|
||||
|
65
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h
Normal file
65
GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/******************************************************************************
|
||||
* wimboot.h
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef __WIMBOOT_H__
|
||||
#define __WIMBOOT_H__
|
||||
|
||||
#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>
|
||||
#include <grub/net.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/ventoy.h>
|
||||
#include "ventoy_def.h"
|
||||
|
||||
|
||||
#define size_t grub_size_t
|
||||
#define ssize_t grub_ssize_t
|
||||
#define memset grub_memset
|
||||
#define memcpy grub_memcpy
|
||||
|
||||
#define uint8_t grub_uint8_t
|
||||
#define uint16_t grub_uint16_t
|
||||
#define uint32_t grub_uint32_t
|
||||
#define uint64_t grub_uint64_t
|
||||
#define int32_t grub_int32_t
|
||||
|
||||
|
||||
|
||||
#define assert(exp)
|
||||
|
||||
//#define DBG grub_printf
|
||||
#define DBG(fmt, ...)
|
||||
|
||||
const char * huffman_bin ( unsigned long value, unsigned int bits );
|
||||
|
||||
#endif
|
||||
|
265
GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h
Normal file
265
GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_DISK_HEADER
|
||||
#define GRUB_DISK_HEADER 1
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/device.h>
|
||||
/* For NULL. */
|
||||
#include <grub/mm.h>
|
||||
|
||||
/* These are used to set a device id. When you add a new disk device,
|
||||
you must define a new id for it here. */
|
||||
enum grub_disk_dev_id
|
||||
{
|
||||
GRUB_DISK_DEVICE_BIOSDISK_ID,
|
||||
GRUB_DISK_DEVICE_OFDISK_ID,
|
||||
GRUB_DISK_DEVICE_LOOPBACK_ID,
|
||||
GRUB_DISK_DEVICE_EFIDISK_ID,
|
||||
GRUB_DISK_DEVICE_DISKFILTER_ID,
|
||||
GRUB_DISK_DEVICE_HOST_ID,
|
||||
GRUB_DISK_DEVICE_ATA_ID,
|
||||
GRUB_DISK_DEVICE_MEMDISK_ID,
|
||||
GRUB_DISK_DEVICE_NAND_ID,
|
||||
GRUB_DISK_DEVICE_SCSI_ID,
|
||||
GRUB_DISK_DEVICE_CRYPTODISK_ID,
|
||||
GRUB_DISK_DEVICE_ARCDISK_ID,
|
||||
GRUB_DISK_DEVICE_HOSTDISK_ID,
|
||||
GRUB_DISK_DEVICE_PROCFS_ID,
|
||||
GRUB_DISK_DEVICE_CBFSDISK_ID,
|
||||
GRUB_DISK_DEVICE_UBOOTDISK_ID,
|
||||
GRUB_DISK_DEVICE_XEN,
|
||||
GRUB_DISK_DEVICE_OBDISK_ID,
|
||||
};
|
||||
|
||||
struct grub_disk;
|
||||
#ifdef GRUB_UTIL
|
||||
struct grub_disk_memberlist;
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GRUB_DISK_PULL_NONE,
|
||||
GRUB_DISK_PULL_REMOVABLE,
|
||||
GRUB_DISK_PULL_RESCAN,
|
||||
GRUB_DISK_PULL_MAX
|
||||
} grub_disk_pull_t;
|
||||
|
||||
typedef int (*grub_disk_dev_iterate_hook_t) (const char *name, void *data);
|
||||
|
||||
/* Disk device. */
|
||||
struct grub_disk_dev
|
||||
{
|
||||
/* The device name. */
|
||||
const char *name;
|
||||
|
||||
/* The device id used by the cache manager. */
|
||||
enum grub_disk_dev_id id;
|
||||
|
||||
/* Call HOOK with each device name, until HOOK returns non-zero. */
|
||||
int (*disk_iterate) (grub_disk_dev_iterate_hook_t hook, void *hook_data,
|
||||
grub_disk_pull_t pull);
|
||||
|
||||
/* Open the device named NAME, and set up DISK. */
|
||||
grub_err_t (*disk_open) (const char *name, struct grub_disk *disk);
|
||||
|
||||
/* Close the disk DISK. */
|
||||
void (*disk_close) (struct grub_disk *disk);
|
||||
|
||||
/* Read SIZE sectors from the sector SECTOR of the disk DISK into BUF. */
|
||||
grub_err_t (*disk_read) (struct grub_disk *disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, char *buf);
|
||||
|
||||
/* Write SIZE sectors from BUF into the sector SECTOR of the disk DISK. */
|
||||
grub_err_t (*disk_write) (struct grub_disk *disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, const char *buf);
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
struct grub_disk_memberlist *(*disk_memberlist) (struct grub_disk *disk);
|
||||
const char * (*disk_raidname) (struct grub_disk *disk);
|
||||
#endif
|
||||
|
||||
/* The next disk device. */
|
||||
struct grub_disk_dev *next;
|
||||
};
|
||||
typedef struct grub_disk_dev *grub_disk_dev_t;
|
||||
|
||||
extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list);
|
||||
|
||||
struct grub_partition;
|
||||
|
||||
typedef void (*grub_disk_read_hook_t) (grub_disk_addr_t sector,
|
||||
unsigned offset, unsigned length,
|
||||
void *data);
|
||||
|
||||
/* Disk. */
|
||||
struct grub_disk
|
||||
{
|
||||
/* The disk name. */
|
||||
const char *name;
|
||||
|
||||
/* The underlying disk device. */
|
||||
grub_disk_dev_t dev;
|
||||
|
||||
/* The total number of sectors. */
|
||||
grub_uint64_t total_sectors;
|
||||
|
||||
/* Logarithm of sector size. */
|
||||
unsigned int log_sector_size;
|
||||
|
||||
/* Maximum number of sectors read divided by GRUB_DISK_CACHE_SIZE. */
|
||||
unsigned int max_agglomerate;
|
||||
|
||||
/* The id used by the disk cache manager. */
|
||||
unsigned long id;
|
||||
|
||||
/* The partition information. This is machine-specific. */
|
||||
struct grub_partition *partition;
|
||||
|
||||
/* Called when a sector was read. OFFSET is between 0 and
|
||||
the sector size minus 1, and LENGTH is between 0 and the sector size. */
|
||||
grub_disk_read_hook_t read_hook;
|
||||
|
||||
/* Caller-specific data passed to the read hook. */
|
||||
void *read_hook_data;
|
||||
|
||||
/* Device-specific data. */
|
||||
void *data;
|
||||
};
|
||||
typedef struct grub_disk *grub_disk_t;
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
struct grub_disk_memberlist
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_disk_memberlist *next;
|
||||
};
|
||||
typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
|
||||
#endif
|
||||
|
||||
/* The sector size. */
|
||||
#define GRUB_DISK_SECTOR_SIZE 0x200
|
||||
#define GRUB_DISK_SECTOR_BITS 9
|
||||
|
||||
/* The maximum number of disk caches. */
|
||||
#define GRUB_DISK_CACHE_NUM 1021
|
||||
|
||||
/* The size of a disk cache in 512B units. Must be at least as big as the
|
||||
largest supported sector size, currently 16K. */
|
||||
#define GRUB_DISK_CACHE_BITS 6
|
||||
#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS)
|
||||
|
||||
#define GRUB_DISK_MAX_MAX_AGGLOMERATE ((1 << (30 - GRUB_DISK_CACHE_BITS - GRUB_DISK_SECTOR_BITS)) - 1)
|
||||
|
||||
/* Return value of grub_disk_get_size() in case disk size is unknown. */
|
||||
#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL
|
||||
|
||||
/* This is called from the memory manager. */
|
||||
void grub_disk_cache_invalidate_all (void);
|
||||
|
||||
void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
|
||||
void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
|
||||
static inline int
|
||||
grub_disk_dev_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data)
|
||||
{
|
||||
grub_disk_dev_t p;
|
||||
grub_disk_pull_t pull;
|
||||
|
||||
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
|
||||
for (p = grub_disk_dev_list; p; p = p->next)
|
||||
if (p->disk_iterate && (p->disk_iterate) (hook, hook_data, pull))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name);
|
||||
void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk);
|
||||
grub_err_t EXPORT_FUNC(grub_disk_blocklist_read)(void *chunklist, grub_uint64_t sector,
|
||||
grub_uint64_t size, grub_uint32_t log_sector_size);
|
||||
|
||||
grub_err_t EXPORT_FUNC(grub_disk_read) (grub_disk_t disk,
|
||||
grub_disk_addr_t sector,
|
||||
grub_off_t offset,
|
||||
grub_size_t size,
|
||||
void *buf);
|
||||
grub_err_t grub_disk_write (grub_disk_t disk,
|
||||
grub_disk_addr_t sector,
|
||||
grub_off_t offset,
|
||||
grub_size_t size,
|
||||
const void *buf);
|
||||
extern grub_err_t (*EXPORT_VAR(grub_disk_write_weak)) (grub_disk_t disk,
|
||||
grub_disk_addr_t sector,
|
||||
grub_off_t offset,
|
||||
grub_size_t size,
|
||||
const void *buf);
|
||||
|
||||
|
||||
grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk);
|
||||
|
||||
#if DISK_CACHE_STATS
|
||||
void
|
||||
EXPORT_FUNC(grub_disk_cache_get_performance) (unsigned long *hits, unsigned long *misses);
|
||||
#endif
|
||||
|
||||
extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void);
|
||||
extern int EXPORT_VAR(grub_disk_firmware_is_tainted);
|
||||
|
||||
static inline void
|
||||
grub_stop_disk_firmware (void)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disk cache. */
|
||||
struct grub_disk_cache
|
||||
{
|
||||
enum grub_disk_dev_id dev_id;
|
||||
unsigned long disk_id;
|
||||
grub_disk_addr_t sector;
|
||||
char *data;
|
||||
int lock;
|
||||
};
|
||||
|
||||
extern struct grub_disk_cache EXPORT_VAR(grub_disk_cache_table)[GRUB_DISK_CACHE_NUM];
|
||||
|
||||
#if defined (GRUB_UTIL)
|
||||
void grub_lvm_init (void);
|
||||
void grub_ldm_init (void);
|
||||
void grub_mdraid09_init (void);
|
||||
void grub_mdraid1x_init (void);
|
||||
void grub_diskfilter_init (void);
|
||||
void grub_lvm_fini (void);
|
||||
void grub_ldm_fini (void);
|
||||
void grub_mdraid09_fini (void);
|
||||
void grub_mdraid1x_fini (void);
|
||||
void grub_diskfilter_fini (void);
|
||||
#endif
|
||||
|
||||
#endif /* ! GRUB_DISK_HEADER */
|
124
GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h
Normal file
124
GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/* efi.h - declare variables and functions for EFI support */
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_EFI_EFI_HEADER
|
||||
#define GRUB_EFI_EFI_HEADER 1
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/efi/api.h>
|
||||
|
||||
/* Functions. */
|
||||
void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol,
|
||||
void *registration);
|
||||
grub_efi_handle_t *
|
||||
EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type,
|
||||
grub_efi_guid_t *protocol,
|
||||
void *search_key,
|
||||
grub_efi_uintn_t *num_handles);
|
||||
void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
|
||||
grub_efi_guid_t *protocol,
|
||||
grub_efi_uint32_t attributes);
|
||||
int EXPORT_FUNC(grub_efi_set_text_mode) (int on);
|
||||
void EXPORT_FUNC(grub_efi_stall) (grub_efi_uintn_t microseconds);
|
||||
void *
|
||||
EXPORT_FUNC(grub_efi_allocate_pages_real) (grub_efi_physical_address_t address,
|
||||
grub_efi_uintn_t pages,
|
||||
grub_efi_allocate_type_t alloctype,
|
||||
grub_efi_memory_type_t memtype);
|
||||
void *
|
||||
EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
|
||||
grub_efi_uintn_t pages);
|
||||
void *
|
||||
EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
|
||||
void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
|
||||
grub_efi_uintn_t pages);
|
||||
grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);
|
||||
int
|
||||
EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size,
|
||||
grub_efi_memory_descriptor_t *memory_map,
|
||||
grub_efi_uintn_t *map_key,
|
||||
grub_efi_uintn_t *descriptor_size,
|
||||
grub_efi_uint32_t *descriptor_version);
|
||||
void grub_efi_memory_fini (void);
|
||||
grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle);
|
||||
void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
|
||||
char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
|
||||
grub_efi_device_path_t *
|
||||
EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle);
|
||||
grub_efi_device_path_t *
|
||||
EXPORT_FUNC(grub_efi_find_last_device_path) (const grub_efi_device_path_t *dp);
|
||||
grub_efi_device_path_t *
|
||||
EXPORT_FUNC(grub_efi_duplicate_device_path) (const grub_efi_device_path_t *dp);
|
||||
grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_efi_uintn_t *outbuf_size, void *outbuf,
|
||||
grub_efi_uintn_t *map_key,
|
||||
grub_efi_uintn_t *efi_desc_size,
|
||||
grub_efi_uint32_t *efi_desc_version);
|
||||
grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memory_map_size,
|
||||
grub_efi_uintn_t descriptor_size,
|
||||
grub_efi_uint32_t descriptor_version,
|
||||
grub_efi_memory_descriptor_t *virtual_map);
|
||||
void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable,
|
||||
const grub_efi_guid_t *guid,
|
||||
grub_size_t *datasize_out);
|
||||
grub_err_t
|
||||
EXPORT_FUNC (grub_efi_set_variable) (const char *var,
|
||||
const grub_efi_guid_t *guid,
|
||||
void *data,
|
||||
grub_size_t datasize);
|
||||
int
|
||||
EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
|
||||
const grub_efi_device_path_t *dp2);
|
||||
|
||||
void * EXPORT_FUNC (grub_efi_allocate_iso_buf) (grub_uint64_t size);
|
||||
|
||||
|
||||
extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
|
||||
char **device,
|
||||
char **path);
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__) || defined(__riscv)
|
||||
void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
|
||||
grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
|
||||
#include <grub/cpu/linux.h>
|
||||
grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
|
||||
grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
|
||||
char *args);
|
||||
#endif
|
||||
|
||||
grub_addr_t grub_efi_modules_addr (void);
|
||||
|
||||
void grub_efi_mm_init (void);
|
||||
void grub_efi_mm_fini (void);
|
||||
void grub_efi_init (void);
|
||||
void grub_efi_fini (void);
|
||||
void grub_efi_set_prefix (void);
|
||||
|
||||
/* Variables. */
|
||||
extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
|
||||
extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
|
||||
|
||||
extern int EXPORT_VAR(grub_efi_is_finished);
|
||||
|
||||
struct grub_net_card;
|
||||
|
||||
grub_efi_handle_t
|
||||
grub_efinet_get_device_handle (struct grub_net_card *card);
|
||||
|
||||
#endif /* ! GRUB_EFI_EFI_HEADER */
|
132
GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h
Normal file
132
GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* fs.h - filesystem manager */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2003,2004,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/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_FS_HEADER
|
||||
#define GRUB_FS_HEADER 1
|
||||
|
||||
#include <grub/device.h>
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
#include <grub/list.h>
|
||||
/* For embedding types. */
|
||||
#ifdef GRUB_UTIL
|
||||
#include <grub/partition.h>
|
||||
#endif
|
||||
|
||||
/* Forward declaration is required, because of mutual reference. */
|
||||
struct grub_file;
|
||||
|
||||
struct grub_dirhook_info
|
||||
{
|
||||
unsigned dir:1;
|
||||
unsigned mtimeset:1;
|
||||
unsigned case_insensitive:1;
|
||||
unsigned inodeset:1;
|
||||
grub_int32_t mtime;
|
||||
grub_uint64_t inode;
|
||||
grub_uint64_t size;
|
||||
};
|
||||
|
||||
typedef int (*grub_fs_dir_hook_t) (const char *filename,
|
||||
const struct grub_dirhook_info *info,
|
||||
void *data);
|
||||
|
||||
/* Filesystem descriptor. */
|
||||
struct grub_fs
|
||||
{
|
||||
/* The next filesystem. */
|
||||
struct grub_fs *next;
|
||||
struct grub_fs **prev;
|
||||
|
||||
/* My name. */
|
||||
const char *name;
|
||||
|
||||
/* Call HOOK with each file under DIR. */
|
||||
grub_err_t (*fs_dir) (grub_device_t device, const char *path,
|
||||
grub_fs_dir_hook_t hook, void *hook_data);
|
||||
|
||||
/* Open a file named NAME and initialize FILE. */
|
||||
grub_err_t (*fs_open) (struct grub_file *file, const char *name);
|
||||
|
||||
/* Read LEN bytes data from FILE into BUF. */
|
||||
grub_ssize_t (*fs_read) (struct grub_file *file, char *buf, grub_size_t len);
|
||||
|
||||
/* Close the file FILE. */
|
||||
grub_err_t (*fs_close) (struct grub_file *file);
|
||||
|
||||
/* Return the label of the device DEVICE in LABEL. The label is
|
||||
returned in a grub_malloc'ed buffer and should be freed by the
|
||||
caller. */
|
||||
grub_err_t (*fs_label) (grub_device_t device, char **label);
|
||||
|
||||
/* Return the uuid of the device DEVICE in UUID. The uuid is
|
||||
returned in a grub_malloc'ed buffer and should be freed by the
|
||||
caller. */
|
||||
grub_err_t (*fs_uuid) (grub_device_t device, char **uuid);
|
||||
|
||||
/* Get writing time of filesystem. */
|
||||
grub_err_t (*fs_mtime) (grub_device_t device, grub_int32_t *timebuf);
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
/* Determine sectors available for embedding. */
|
||||
grub_err_t (*fs_embed) (grub_device_t device, unsigned int *nsectors,
|
||||
unsigned int max_nsectors,
|
||||
grub_embed_type_t embed_type,
|
||||
grub_disk_addr_t **sectors);
|
||||
|
||||
/* Whether this filesystem reserves first sector for DOS-style boot. */
|
||||
int reserved_first_sector;
|
||||
|
||||
/* Whether blocklist installs have a chance to work. */
|
||||
int blocklist_install;
|
||||
#endif
|
||||
};
|
||||
typedef struct grub_fs *grub_fs_t;
|
||||
|
||||
/* This is special, because block lists are not files in usual sense. */
|
||||
extern struct grub_fs grub_fs_blocklist;
|
||||
|
||||
/* This hook is used to automatically load filesystem modules.
|
||||
If this hook loads a module, return non-zero. Otherwise return zero.
|
||||
The newly loaded filesystem is assumed to be inserted into the head of
|
||||
the linked list GRUB_FS_LIST through the function grub_fs_register. */
|
||||
typedef int (*grub_fs_autoload_hook_t) (void);
|
||||
extern grub_fs_autoload_hook_t EXPORT_VAR(grub_fs_autoload_hook);
|
||||
extern grub_fs_t EXPORT_VAR (grub_fs_list);
|
||||
|
||||
#ifndef GRUB_LST_GENERATOR
|
||||
static inline void
|
||||
grub_fs_register (grub_fs_t fs)
|
||||
{
|
||||
grub_list_push (GRUB_AS_LIST_P (&grub_fs_list), GRUB_AS_LIST (fs));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
grub_fs_unregister (grub_fs_t fs)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST (fs));
|
||||
}
|
||||
|
||||
#define FOR_FILESYSTEMS(var) FOR_LIST_ELEMENTS((var), (grub_fs_list))
|
||||
|
||||
grub_fs_t EXPORT_FUNC(grub_fs_probe) (grub_device_t device);
|
||||
|
||||
#endif /* ! GRUB_FS_HEADER */
|
242
GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h
Normal file
242
GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/******************************************************************************
|
||||
* ventoy.h
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VENTOY_H__
|
||||
#define __VENTOY_H__
|
||||
|
||||
#define COMPILE_ASSERT(expr) extern char __compile_assert[(expr) ? 1 : -1]
|
||||
|
||||
#define VENTOY_COMPATIBLE_STR "VENTOY COMPATIBLE"
|
||||
#define VENTOY_COMPATIBLE_STR_LEN 17
|
||||
|
||||
#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }}
|
||||
|
||||
typedef enum ventoy_fs_type
|
||||
{
|
||||
ventoy_fs_exfat = 0, /* 0: exfat */
|
||||
ventoy_fs_ntfs, /* 1: NTFS */
|
||||
ventoy_fs_ext, /* 2: ext2/ext3/ext4 */
|
||||
ventoy_fs_xfs, /* 3: XFS */
|
||||
ventoy_fs_udf, /* 4: UDF */
|
||||
|
||||
ventoy_fs_max
|
||||
}ventoy_fs_type;
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct ventoy_guid
|
||||
{
|
||||
grub_uint32_t data1;
|
||||
grub_uint16_t data2;
|
||||
grub_uint16_t data3;
|
||||
grub_uint8_t data4[8];
|
||||
}ventoy_guid;
|
||||
|
||||
|
||||
typedef struct ventoy_image_disk_region
|
||||
{
|
||||
grub_uint32_t image_sector_count; /* image sectors contained in this region (in 2048) */
|
||||
grub_uint32_t image_start_sector; /* image sector start (in 2048) */
|
||||
grub_uint64_t disk_start_sector; /* disk sector start (in 512) */
|
||||
}ventoy_image_disk_region;
|
||||
|
||||
typedef struct ventoy_image_location
|
||||
{
|
||||
ventoy_guid guid;
|
||||
|
||||
/* image sector size, currently this value is always 2048 */
|
||||
grub_uint32_t image_sector_size;
|
||||
|
||||
/* disk sector size, normally the value is 512 */
|
||||
grub_uint32_t disk_sector_size;
|
||||
|
||||
grub_uint32_t region_count;
|
||||
|
||||
/*
|
||||
* disk region data (region_count)
|
||||
* If the image file has more than one fragments in disk,
|
||||
* there will be more than one region data here.
|
||||
*
|
||||
*/
|
||||
ventoy_image_disk_region regions[1];
|
||||
|
||||
/* ventoy_image_disk_region regions[2~region_count-1] */
|
||||
}ventoy_image_location;
|
||||
|
||||
|
||||
typedef struct ventoy_os_param
|
||||
{
|
||||
ventoy_guid guid; // VENTOY_GUID
|
||||
grub_uint8_t chksum; // checksum
|
||||
|
||||
grub_uint8_t vtoy_disk_guid[16];
|
||||
grub_uint64_t vtoy_disk_size; // disk size in bytes
|
||||
grub_uint16_t vtoy_disk_part_id; // begin with 1
|
||||
grub_uint16_t vtoy_disk_part_type; // 0:exfat 1:ntfs other: reserved
|
||||
char vtoy_img_path[384]; // It seems to be enough, utf-8 format
|
||||
grub_uint64_t vtoy_img_size; // image file size in bytes
|
||||
|
||||
/*
|
||||
* Ventoy will write a copy of ventoy_image_location data into runtime memory
|
||||
* this is the physically address and length of that memory.
|
||||
* Address 0 means no such data exist.
|
||||
* Address will be aligned by 4KB.
|
||||
*
|
||||
*/
|
||||
grub_uint64_t vtoy_img_location_addr;
|
||||
grub_uint32_t vtoy_img_location_len;
|
||||
|
||||
/*
|
||||
* These 32 bytes are reserved by ventoy.
|
||||
*
|
||||
* vtoy_reserved[0]: vtoy_break_level
|
||||
* vtoy_reserved[1]: vtoy_debug_level
|
||||
*
|
||||
*/
|
||||
grub_uint8_t vtoy_reserved[32]; // Internal use by ventoy
|
||||
|
||||
grub_uint8_t reserved[31];
|
||||
}ventoy_os_param;
|
||||
|
||||
|
||||
typedef struct ventoy_windows_data
|
||||
{
|
||||
char auto_install_script[384];
|
||||
grub_uint8_t reserved[128];
|
||||
}ventoy_windows_data;
|
||||
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
// compile assert check : sizeof(ventoy_os_param) must be 512
|
||||
COMPILE_ASSERT(sizeof(ventoy_os_param) == 512);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma pack(4)
|
||||
|
||||
typedef struct ventoy_chain_head
|
||||
{
|
||||
ventoy_os_param os_param;
|
||||
|
||||
grub_uint32_t disk_drive;
|
||||
grub_uint32_t drive_map;
|
||||
grub_uint32_t disk_sector_size;
|
||||
|
||||
grub_uint64_t real_img_size_in_bytes;
|
||||
grub_uint64_t virt_img_size_in_bytes;
|
||||
grub_uint32_t boot_catalog;
|
||||
grub_uint8_t boot_catalog_sector[2048];
|
||||
|
||||
grub_uint32_t img_chunk_offset;
|
||||
grub_uint32_t img_chunk_num;
|
||||
|
||||
grub_uint32_t override_chunk_offset;
|
||||
grub_uint32_t override_chunk_num;
|
||||
|
||||
grub_uint32_t virt_chunk_offset;
|
||||
grub_uint32_t virt_chunk_num;
|
||||
}ventoy_chain_head;
|
||||
|
||||
typedef struct ventoy_img_chunk
|
||||
{
|
||||
grub_uint32_t img_start_sector; // sector size: 2KB
|
||||
grub_uint32_t img_end_sector; // included
|
||||
|
||||
grub_uint64_t disk_start_sector; // in disk_sector_size
|
||||
grub_uint64_t disk_end_sector; // included
|
||||
}ventoy_img_chunk;
|
||||
|
||||
|
||||
typedef struct ventoy_override_chunk
|
||||
{
|
||||
grub_uint64_t img_offset;
|
||||
grub_uint32_t override_size;
|
||||
grub_uint8_t override_data[512];
|
||||
}ventoy_override_chunk;
|
||||
|
||||
typedef struct ventoy_virt_chunk
|
||||
{
|
||||
grub_uint32_t mem_sector_start;
|
||||
grub_uint32_t mem_sector_end;
|
||||
grub_uint32_t mem_sector_offset;
|
||||
grub_uint32_t remap_sector_start;
|
||||
grub_uint32_t remap_sector_end;
|
||||
grub_uint32_t org_sector_start;
|
||||
}ventoy_virt_chunk;
|
||||
|
||||
#define DEFAULT_CHUNK_NUM 1024
|
||||
typedef struct ventoy_img_chunk_list
|
||||
{
|
||||
grub_uint32_t max_chunk;
|
||||
grub_uint32_t cur_chunk;
|
||||
ventoy_img_chunk *chunk;
|
||||
}ventoy_img_chunk_list;
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define ventoy_filt_register grub_file_filter_register
|
||||
|
||||
typedef const char * (*grub_env_get_pf)(const char *name);
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
#define GRUB_FILE_REPLACE_MAGIC 0x1258BEEF
|
||||
|
||||
typedef struct ventoy_grub_param_file_replace
|
||||
{
|
||||
grub_uint32_t magic;
|
||||
char old_file_name[4][256];
|
||||
grub_uint32_t old_name_cnt;
|
||||
grub_uint32_t new_file_virtual_id;
|
||||
}ventoy_grub_param_file_replace;
|
||||
|
||||
typedef struct ventoy_grub_param
|
||||
{
|
||||
grub_env_get_pf grub_env_get;
|
||||
|
||||
ventoy_grub_param_file_replace file_replace;
|
||||
}ventoy_grub_param;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
|
||||
int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list);
|
||||
grub_uint64_t grub_iso9660_get_last_read_pos(grub_file_t file);
|
||||
grub_uint64_t grub_iso9660_get_last_file_dirent_pos(grub_file_t file);
|
||||
grub_uint64_t grub_udf_get_file_offset(grub_file_t file);
|
||||
grub_uint64_t grub_udf_get_last_pd_size_offset(void);
|
||||
grub_uint64_t grub_udf_get_last_file_attr_offset
|
||||
(
|
||||
grub_file_t file,
|
||||
grub_uint32_t *startBlock,
|
||||
grub_uint64_t *fe_entry_size_offset
|
||||
);
|
||||
int ventoy_is_efi_os(void);
|
||||
|
||||
#endif /* __VENTOY_H__ */
|
||||
|
43
GRUB2/MOD_SRC/grub-2.04/install.sh
Normal file
43
GRUB2/MOD_SRC/grub-2.04/install.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
VT_DIR=$PWD/../../..
|
||||
|
||||
rm -rf $VT_DIR/GRUB2/INSTALL
|
||||
rm -rf $VT_DIR/GRUB2/PXE
|
||||
mkdir -p $VT_DIR/GRUB2/INSTALL
|
||||
mkdir -p $VT_DIR/GRUB2/PXE
|
||||
|
||||
make install
|
||||
|
||||
PATH=$PATH:$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/
|
||||
|
||||
net_modules_legacy="net tftp http"
|
||||
all_modules_legacy="date drivemap blocklist ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_msdos fat exfat ntfs loopback gzio normal udf gfxmenu gfxterm gfxterm_background gfxterm_menu"
|
||||
|
||||
net_modules_uefi="efinet net tftp http"
|
||||
all_modules_uefi="blocklist ventoy test ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu"
|
||||
|
||||
|
||||
if [ "$1" = "uefi" ]; then
|
||||
all_modules="$net_modules_uefi $all_modules_uefi"
|
||||
grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi" --prefix '(,msdos2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/grubx64_real.efi" --format 'x86_64-efi' --compression 'auto' $all_modules_uefi 'fat' 'part_msdos'
|
||||
else
|
||||
all_modules="$net_modules_legacy $all_modules_legacy"
|
||||
grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc" --prefix '(,msdos2)/grub' --output "$VT_DIR/INSTALL/grub/i386-pc/core.img" --format 'i386-pc' --compression 'auto' $all_modules_legacy 'fat' 'part_msdos' 'biosdisk'
|
||||
fi
|
||||
|
||||
grub-mknetdir --modules="$all_modules" --net-directory=$VT_DIR/GRUB2/PXE --subdir=grub2 --locales=en@quot || exit 1
|
||||
|
||||
if [ "$1" = "uefi" ]; then
|
||||
rm -f $VT_DIR/GRUB2/NBP/core.efi
|
||||
cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1
|
||||
|
||||
rm -f $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod
|
||||
cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/normal.mod $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod || exit 1
|
||||
else
|
||||
rm -f $VT_DIR/GRUB2/NBP/core.0
|
||||
cp -a $VT_DIR/GRUB2/PXE/grub2/i386-pc/core.0 $VT_DIR/GRUB2/NBP/core.0 || exit 1
|
||||
|
||||
rm -f $VT_DIR/INSTALL/grub/i386-pc/boot.img
|
||||
cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/boot.img $VT_DIR/INSTALL/grub/i386-pc/boot.img || exit 1
|
||||
fi
|
Reference in New Issue
Block a user