2008-07-17 Bean <bean123ch@gmail.com>
* conf/i386/efi.rmk (pkglib_MODULES): add pci.mod and lspci.mod. (appleldr_mod_SOURCE): New variavle. (appleldr_mod_CFLAGS): Likewise. (appleldr_mod_LDFLAGS): Likewise. (pci_mod_SOURCES): Likewise. (pci_mod_CFLAGS): Likewise. (pci_mod_LDFLAGS): Likewise. (lspci_mod_SOURCES): Likewise. (lspci_mod_CFLAGS): Likewise. (lspci_mod_LDFLAGS): Likewise. * conf/x86_64-efi.rmk: New file. * disk/efi/efidisk.c (grub_efidisk_read): Wrap efi calls with efi_call_N macro. (grub_efidisk_write): Likewise. * include/efi/api.h (efi_call_0): New macro. (efi_call_1): Likewise. (efi_call_2): Likewise. (efi_call_3): Likewise. (efi_call_4): Likewise. (efi_call_5): Likewise. (efi_call_6): Likewise. * include/grub/efi/chainloader.h (grub_chainloader_cmd): Rename to grub_rescue_cmd_chainloader. * include/grub/efi/pe32.h (GRUB_PE32_MACHINE_X86_64): New macro. (grub_pe32_optional_header): Change some fields based on i386 or x86_64 platform. (GRUB_PE32_PE32_MAGIC): Likewise. * include/grub/efi/uga_draw.h: New file. * include/grub/elf.h (STN_ABS): New constant. (R_X86_64_NONE): Relocation constant for x86_64. (R_X86_64_64): Likewise. (R_X86_64_PC32): Likewise. (R_X86_64_GOT32): Likewise. (R_X86_64_PLT32): Likewise. (R_X86_64_COPY): Likewise. (R_X86_64_GLOB_DAT): Likewise. (R_X86_64_JUMP_SLOT): Likewise. (R_X86_64_RELATIVE): Likewise. (R_X86_64_GOTPCREL): Likewise. (R_X86_64_32): Likewise. (R_X86_64_32S): Likewise. (R_X86_64_16): Likewise. (R_X86_64_PC16): Likewise. (R_X86_64_8): Likewise. (R_X86_64_PC8): Likewise. * include/grub/i386/efi/pci.h: New file. * include/grub/i386/linux.h (GRUB_LINUX_EFI_SIGNATURE): Change it value based on platform. (GRUB_LINUX_EFI_SIGNATURE_0204): New constant. (GRUB_E820_RAM): Likewise. (GRUB_E820_RESERVED): Likewise. (GRUB_E820_ACPI): Likewise. (GRUB_E820_NVS): Likewise. (GRUB_E820_EXEC_CODE): Likewise. (GRUB_E820_MAX_ENTRY): Likewise. (grub_e820_mmap): New structure. (linux_kernel_header): Change the efi field according to different kernel version, also field from linux_kernel_header. * include/grub/kernel.h (grub_module_info): Add padding for x86_64. * include/grub/pci.h (GRUB_PCI_ADDR_SPACE_MASK): New constant. (GRUB_PCI_ADDR_SPACE_MEMORY): Likewise. (GRUB_PCI_ADDR_SPACE_IO): Likewise. (GRUB_PCI_ADDR_MEM_TYPE_MASK): Likewise. (GRUB_PCI_ADDR_MEM_TYPE_32): Likewise. (GRUB_PCI_ADDR_MEM_TYPE_1M): Likewise. (GRUB_PCI_ADDR_MEM_TYPE_64): Likewise. (GRUB_PCI_ADDR_MEM_PREFETCH): Likewise. (GRUB_PCI_ADDR_MEM_MASK): Likewise. (GRUB_PCI_ADDR_IO_MASK): Likewise. * include/grub/x86_64/efi/kernel.h: New file. * include/grub/x86_64/efi/loader.h: Likewise. * include/grub/x86_64/efi/machine.h: Likewise. * include/grub/x86_64/efi/pci.h: Likewise. * include/grub/x86_64/efi/time.h: Likewise. * include/grub/x86_64/linux.h: Likewise. * include/grub/x86_64/setjmp.h: Likewise. * include/grub/x86_64/time.h: Likewise. * include/grub/x86_64/types.h: Likewise. * kern/dl.c (GRUB_CPU_SIZEOF_VOID_P): Changed to GRUB_TARGET_SIZEOF_VOID_P. * kern/efi/efi.c (grub_efi_locate_protocol): Wrap efi calls. (grub_efi_locate_handle): Likewise. (grub_efi_open_protocol): Likewise. (grub_efi_set_text_mode): Likewise. (grub_efi_stall): Likewise. (grub_exit): Likewise. (grub_reboot): Likewise. (grub_halt): Likewise. (grub_efi_exit_boot_services): Likewise. (grub_get_rtc): Likewise. * kern/efi/mm.c (MEMORY_MAP_SIZE): Change to 0x3000 for new models. (GRUB_CPU_SIZEOF_VOID_P): Changed to GRUB_TARGET_SIZEOF_VOID_P. (grub_efi_allocate_pages): Wrap efi calls. (grub_efi_free_pages): Wrap efi calls. (grub_efi_get_memory_map): Wrap efi calls. * kern/x86_64/dl.c: New file. * kern/x86_64/efi/callwrap.S: Likewise. * kern/x86_64/efi/startup.S: Likewise. * loader/efi/appleloader.c: Likewise. * loader/efi/chainloader.c (cmdline): New variable. (grub_chainloader_unload): Wrap efi calls. (grub_chainloader_boot): Likewise. (grub_rescue_cmd_chainloader): Wrap efi calls, handle command line. * loader/efi/chainloader_normal.c (chainloader_command): Change grub_chainloader_cmd to grub_rescue_cmd_chainloader, pass command line. * loader/i386/efi/linux.c (allocate_pages): Change allocation method. (grub_e820_add_region): New function. (grub_linux_boot): Construct e820 map from efi map, handle x86_64 booting. (grub_find_video_card): New function. (grub_linux_setup_video): New function. (grub_rescue_cmd_linux): Probe for video information. * normal/x86_64/setjmp.S: New file. * term/efi/console.c (map_char): New function. (grub_console_putchar): Map unicode char. (grub_console_checkkey): Wrap efi calls. (grub_console_getkey): Likewise. (grub_console_getwh): Likewise. (grub_console_gotoxy): Likewise. (grub_console_cls): Likewise. (grub_console_setcolorstate): Likewise. (grub_console_setcursor): Likewise. * util/i386/efi/grub-mkimage.c: Add support for x86_64.
This commit is contained in:
parent
ef29405511
commit
2001169405
39 changed files with 3960 additions and 309 deletions
|
@ -30,6 +30,11 @@
|
|||
#include <grub/cpu/linux.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/uga_draw.h>
|
||||
#include <grub/pci.h>
|
||||
|
||||
#define GRUB_EFI_CL_OFFSET 0x1000
|
||||
#define GRUB_EFI_CL_END_OFFSET 0x2000
|
||||
|
||||
#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
|
||||
((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
|
||||
|
@ -60,28 +65,24 @@ static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
|
|||
|
||||
struct gdt_descriptor
|
||||
{
|
||||
grub_uint16_t dummy;
|
||||
grub_uint16_t limit;
|
||||
grub_uint32_t base;
|
||||
} __attribute__ ((aligned(4), packed));
|
||||
void *base;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static struct gdt_descriptor gdt_desc =
|
||||
{
|
||||
0,
|
||||
sizeof (gdt) - 1,
|
||||
(grub_addr_t) gdt
|
||||
gdt
|
||||
};
|
||||
|
||||
struct idt_descriptor
|
||||
{
|
||||
grub_uint16_t dummy;
|
||||
grub_uint16_t limit;
|
||||
grub_uint32_t base;
|
||||
} __attribute__ ((aligned(4)));
|
||||
void *base;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static struct idt_descriptor idt_desc =
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
@ -156,20 +157,21 @@ free_pages (void)
|
|||
/* Allocate pages for the real mode code and the protected mode code
|
||||
for linux as well as a memory map buffer. */
|
||||
static int
|
||||
allocate_pages (grub_size_t real_size, grub_size_t prot_size)
|
||||
allocate_pages (grub_size_t prot_size)
|
||||
{
|
||||
grub_efi_uintn_t desc_size;
|
||||
grub_efi_memory_descriptor_t *mmap, *mmap_end;
|
||||
grub_efi_uintn_t mmap_size, tmp_mmap_size;
|
||||
grub_efi_memory_descriptor_t *desc;
|
||||
grub_size_t real_size;
|
||||
|
||||
/* Make sure that each size is aligned to a page boundary. */
|
||||
real_size = page_align (real_size + GRUB_DISK_SECTOR_SIZE);
|
||||
real_size = GRUB_EFI_CL_END_OFFSET;
|
||||
prot_size = page_align (prot_size);
|
||||
mmap_size = find_mmap_size ();
|
||||
|
||||
grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %lx\n",
|
||||
real_size, prot_size, mmap_size);
|
||||
grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
|
||||
(unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
|
||||
|
||||
/* Calculate the number of pages; Combine the real mode code with
|
||||
the memory map buffer for simplicity. */
|
||||
|
@ -217,8 +219,8 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
|
|||
if (addr < 0x10000)
|
||||
continue;
|
||||
|
||||
grub_dprintf ("linux", "trying to allocate %lu pages at %x\n",
|
||||
real_mode_pages, (unsigned) addr);
|
||||
grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
|
||||
(unsigned) real_mode_pages, (unsigned long) addr);
|
||||
real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
|
||||
if (! real_mode_mem)
|
||||
grub_fatal ("cannot allocate pages");
|
||||
|
@ -246,6 +248,11 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
|
||||
"prot_mode_mem = %lx, prot_mode_pages = %x\n",
|
||||
(unsigned long) real_mode_mem, (unsigned) real_mode_pages,
|
||||
(unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
|
||||
|
||||
grub_free (mmap);
|
||||
return 1;
|
||||
|
||||
|
@ -255,56 +262,189 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
|
||||
grub_uint64_t start, grub_uint64_t size,
|
||||
grub_uint32_t type)
|
||||
{
|
||||
int n = *e820_num;
|
||||
|
||||
if (n >= GRUB_E820_MAX_ENTRY)
|
||||
grub_fatal ("Too many e820 memory map entries");
|
||||
|
||||
if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
|
||||
(e820_map[n - 1].type == type))
|
||||
e820_map[n - 1].size += size;
|
||||
else
|
||||
{
|
||||
e820_map[n].addr = start;
|
||||
e820_map[n].size = size;
|
||||
e820_map[n].type = type;
|
||||
(*e820_num)++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
struct
|
||||
{
|
||||
grub_uint32_t kernel_entry;
|
||||
grub_uint32_t kernel_cs;
|
||||
} jumpvector;
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_linux_boot (void)
|
||||
{
|
||||
struct linux_kernel_header *lh;
|
||||
struct linux_kernel_params *params;
|
||||
grub_efi_uintn_t mmap_size;
|
||||
grub_efi_uintn_t map_key;
|
||||
grub_efi_uintn_t desc_size;
|
||||
grub_efi_uint32_t desc_version;
|
||||
grub_efi_memory_descriptor_t *desc;
|
||||
int e820_num;
|
||||
|
||||
lh = real_mode_mem;
|
||||
params = real_mode_mem;
|
||||
|
||||
grub_dprintf ("linux", "code32_start = %x, idt_desc = %x, gdt_desc = %x\n",
|
||||
(unsigned) lh->code32_start, (grub_addr_t) &(idt_desc.limit),
|
||||
(grub_addr_t) &(gdt_desc.limit));
|
||||
grub_dprintf ("linux", "idt = %x:%x, gdt = %x:%x\n",
|
||||
(unsigned) idt_desc.limit, (unsigned) idt_desc.base,
|
||||
(unsigned) gdt_desc.limit, (unsigned) gdt_desc.base);
|
||||
grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
|
||||
(unsigned) params->code32_start,
|
||||
(unsigned long) &(idt_desc.limit),
|
||||
(unsigned long) &(gdt_desc.limit));
|
||||
grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
|
||||
(unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
|
||||
(unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
|
||||
|
||||
mmap_size = find_mmap_size ();
|
||||
if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
|
||||
&desc_size, &desc_version) <= 0)
|
||||
grub_fatal ("cannot get memory map");
|
||||
|
||||
e820_num = 0;
|
||||
for (desc = mmap_buf;
|
||||
desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
|
||||
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
|
||||
{
|
||||
switch (desc->type)
|
||||
{
|
||||
case GRUB_EFI_ACPI_RECLAIM_MEMORY:
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
desc->physical_start,
|
||||
desc->num_pages << 12,
|
||||
GRUB_E820_ACPI);
|
||||
break;
|
||||
|
||||
case GRUB_EFI_ACPI_MEMORY_NVS:
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
desc->physical_start,
|
||||
desc->num_pages << 12,
|
||||
GRUB_E820_NVS);
|
||||
break;
|
||||
|
||||
case GRUB_EFI_RUNTIME_SERVICES_CODE:
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
desc->physical_start,
|
||||
desc->num_pages << 12,
|
||||
GRUB_E820_EXEC_CODE);
|
||||
break;
|
||||
|
||||
case GRUB_EFI_LOADER_CODE:
|
||||
case GRUB_EFI_LOADER_DATA:
|
||||
case GRUB_EFI_BOOT_SERVICES_CODE:
|
||||
case GRUB_EFI_BOOT_SERVICES_DATA:
|
||||
case GRUB_EFI_CONVENTIONAL_MEMORY:
|
||||
{
|
||||
grub_uint64_t start, size, end;
|
||||
|
||||
start = desc->physical_start;
|
||||
size = desc->num_pages << 12;
|
||||
end = start + size;
|
||||
|
||||
/* Skip A0000 - 100000 region. */
|
||||
if ((start < 0x100000ULL) && (end > 0xA0000ULL))
|
||||
{
|
||||
if (start < 0xA0000ULL)
|
||||
{
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
start,
|
||||
0xA0000ULL - start,
|
||||
GRUB_E820_RAM);
|
||||
}
|
||||
|
||||
if (end <= 0x100000ULL)
|
||||
continue;
|
||||
|
||||
start = 0x100000ULL;
|
||||
size = end - start;
|
||||
}
|
||||
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
start, size, GRUB_E820_RAM);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
desc->physical_start,
|
||||
desc->num_pages << 12,
|
||||
GRUB_E820_RESERVED);
|
||||
}
|
||||
}
|
||||
|
||||
params->mmap_size = e820_num;
|
||||
|
||||
if (! grub_efi_exit_boot_services (map_key))
|
||||
grub_fatal ("cannot exit boot services");
|
||||
grub_fatal ("cannot exit boot services");
|
||||
|
||||
/* Note that no boot services are available from here. */
|
||||
|
||||
/* Pass EFI parameters. */
|
||||
if (grub_le_to_cpu16 (params->version) >= 0x0206)
|
||||
{
|
||||
params->v0206.efi_mem_desc_size = desc_size;
|
||||
params->v0206.efi_mem_desc_version = desc_version;
|
||||
params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
|
||||
params->v0206.efi_mmap_size = mmap_size;
|
||||
#ifdef __x86_64__
|
||||
params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32);
|
||||
#endif
|
||||
}
|
||||
else if (grub_le_to_cpu16 (params->version) >= 0x0204)
|
||||
{
|
||||
params->v0204.efi_mem_desc_size = desc_size;
|
||||
params->v0204.efi_mem_desc_version = desc_version;
|
||||
params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
|
||||
params->v0204.efi_mmap_size = mmap_size;
|
||||
}
|
||||
|
||||
/* Hardware interrupts are not safe any longer. */
|
||||
asm volatile ("cli" : : );
|
||||
|
||||
/* Pass EFI parameters. */
|
||||
params->efi_mem_desc_size = desc_size;
|
||||
params->efi_mem_desc_version = desc_version;
|
||||
params->efi_mmap = (grub_addr_t) mmap_buf;
|
||||
params->efi_mmap_size = mmap_size;
|
||||
/* Load the IDT and the GDT for the bootstrap. */
|
||||
asm volatile ("lidt %0" : : "m" (idt_desc));
|
||||
asm volatile ("lgdt %0" : : "m" (gdt_desc));
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
jumpvector.kernel_entry = (grub_uint64_t) grub_linux_real_boot;
|
||||
jumpvector.kernel_cs = 0x10;
|
||||
|
||||
asm volatile ( "mov %0, %%rbx" : : "m" (params->code32_start));
|
||||
asm volatile ( "mov %0, %%rsi" : : "m" (real_mode_mem));
|
||||
|
||||
asm volatile ( "ljmp *%0" : : "m" (jumpvector));
|
||||
|
||||
#else
|
||||
|
||||
/* Pass parameters. */
|
||||
asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start));
|
||||
asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
|
||||
asm volatile ("movl %0, %%ecx" : : "m" (lh->code32_start));
|
||||
asm volatile ("xorl %%ebx, %%ebx" : : );
|
||||
|
||||
/* Load the IDT and the GDT for the bootstrap. */
|
||||
asm volatile ("lidt %0" : : "m" (idt_desc.limit));
|
||||
asm volatile ("lgdt %0" : : "m" (gdt_desc.limit));
|
||||
asm volatile ("xorl %%ebx, %%ebx" : : );
|
||||
|
||||
/* Enter Linux. */
|
||||
asm volatile ("jmp *%%ecx" : : );
|
||||
|
||||
#endif
|
||||
|
||||
/* Never reach here. */
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -318,6 +458,111 @@ grub_linux_unload (void)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_uint64_t video_base;
|
||||
|
||||
static int
|
||||
grub_find_video_card (int bus, int dev, int func,
|
||||
grub_pci_id_t pciid __attribute__ ((unused)))
|
||||
{
|
||||
grub_pci_address_t addr;
|
||||
|
||||
addr = grub_pci_make_address (bus, dev, func, 2);
|
||||
|
||||
if (grub_pci_read (addr) >> 24 == 0x3)
|
||||
{
|
||||
int i;
|
||||
|
||||
addr = grub_pci_make_address (bus, dev, func, 4);
|
||||
for (i = 0; i < 6; i++, addr += 4)
|
||||
{
|
||||
grub_uint32_t base, type;
|
||||
|
||||
base = grub_pci_read (addr);
|
||||
|
||||
if ((base == 0) || (base == 0xffffffff) ||
|
||||
(base & GRUB_PCI_ADDR_SPACE_IO))
|
||||
continue;
|
||||
|
||||
type = base & GRUB_PCI_ADDR_MEM_TYPE_MASK;
|
||||
if (! (addr & GRUB_PCI_ADDR_MEM_PREFETCH))
|
||||
{
|
||||
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
|
||||
{
|
||||
i++;
|
||||
addr +=4 ;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
base &= GRUB_PCI_ADDR_MEM_MASK;
|
||||
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
|
||||
{
|
||||
if (i == 5)
|
||||
break;
|
||||
|
||||
video_base = grub_pci_read (addr + 4);
|
||||
video_base <<= 32;
|
||||
}
|
||||
|
||||
video_base |= base;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
|
||||
|
||||
static int
|
||||
grub_linux_setup_video (struct linux_kernel_params *params)
|
||||
{
|
||||
grub_efi_uga_draw_protocol_t *c;
|
||||
grub_uint32_t width, height, depth, rate;
|
||||
|
||||
c = grub_efi_locate_protocol (&uga_draw_guid, 0);
|
||||
if (! c)
|
||||
return 1;
|
||||
|
||||
if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
|
||||
return 1;
|
||||
|
||||
grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
|
||||
|
||||
video_base = 0;
|
||||
grub_pci_iterate (grub_find_video_card);
|
||||
|
||||
if (! video_base)
|
||||
{
|
||||
grub_printf ("Can\'t find frame buffer address\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
grub_printf ("Video frame buffer: %llx\n", (unsigned long long) video_base);
|
||||
|
||||
params->lfb_width = width;
|
||||
params->lfb_height = height;
|
||||
params->lfb_depth = depth;
|
||||
|
||||
/* FIXME: shouldn't use fixed value. */
|
||||
params->lfb_line_len = 8192;
|
||||
|
||||
params->lfb_base = video_base;
|
||||
params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16;
|
||||
|
||||
params->red_mask_size = 8;
|
||||
params->red_field_pos = 16;
|
||||
params->green_mask_size = 8;
|
||||
params->green_field_pos = 8;
|
||||
params->blue_mask_size = 8;
|
||||
params->blue_field_pos = 0;
|
||||
params->reserved_mask_size = 8;
|
||||
params->reserved_field_pos = 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_rescue_cmd_linux (int argc, char *argv[])
|
||||
{
|
||||
|
@ -329,6 +574,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
grub_ssize_t len;
|
||||
int i;
|
||||
char *dest;
|
||||
int video_type;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
|
@ -384,19 +630,33 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
|
||||
prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
|
||||
|
||||
if (! allocate_pages (real_size, prot_size))
|
||||
if (! allocate_pages (prot_size))
|
||||
goto fail;
|
||||
|
||||
params = (struct linux_kernel_params *) real_mode_mem;
|
||||
grub_memset (params, 0, GRUB_EFI_CL_END_OFFSET);
|
||||
grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
|
||||
|
||||
params->ps_mouse = params->padding10 = 0;
|
||||
|
||||
len = 0x400 - sizeof (lh);
|
||||
if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* XXX Linux assumes that only elilo can boot Linux on EFI!!! */
|
||||
lh.type_of_loader = 0x50;
|
||||
params->type_of_loader = 0x50;
|
||||
|
||||
lh.cl_magic = GRUB_LINUX_CL_MAGIC;
|
||||
lh.cl_offset = GRUB_LINUX_CL_END_OFFSET;
|
||||
lh.cmd_line_ptr = (char *) real_mode_mem + GRUB_LINUX_CL_OFFSET;
|
||||
lh.ramdisk_image = 0;
|
||||
lh.ramdisk_size = 0;
|
||||
params->cl_magic = GRUB_LINUX_CL_MAGIC;
|
||||
params->cl_offset = 0x1000;
|
||||
params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
|
||||
params->ramdisk_image = 0;
|
||||
params->ramdisk_size = 0;
|
||||
|
||||
params = (struct linux_kernel_params *) &lh;
|
||||
params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
|
||||
params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
|
||||
|
||||
/* These are not needed to be precise, because Linux uses these values
|
||||
only to raise an error when the decompression code cannot find good
|
||||
|
@ -414,6 +674,23 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
params->have_vga = 0;
|
||||
params->font_size = 16; /* XXX */
|
||||
|
||||
if (grub_le_to_cpu16 (params->version) >= 0x0206)
|
||||
{
|
||||
params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
|
||||
params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
|
||||
#ifdef __x86_64__
|
||||
params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
|
||||
#endif
|
||||
}
|
||||
else if (grub_le_to_cpu16 (params->version) >= 0x0204)
|
||||
{
|
||||
params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
|
||||
params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* The structure is zeroed already. */
|
||||
|
||||
/* No VBE on EFI. */
|
||||
params->lfb_width = 0;
|
||||
params->lfb_height = 0;
|
||||
|
@ -457,10 +734,6 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
/* No MCA on EFI. */
|
||||
params->rom_config_len = 0;
|
||||
|
||||
params->efi_signature = GRUB_LINUX_EFI_SIGNATURE; /* XXX not used */
|
||||
params->efi_system_table = (grub_addr_t) grub_efi_system_table;
|
||||
/* The other EFI parameters are filled when booting. */
|
||||
|
||||
/* No need to fake the BIOS's memory map. */
|
||||
params->mmap_size = 0;
|
||||
|
||||
|
@ -478,22 +751,19 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
grub_memset (params->padding8, 0, sizeof (params->padding8));
|
||||
grub_memset (params->padding9, 0, sizeof (params->padding9));
|
||||
|
||||
/* Put the real mode code at the real location. */
|
||||
grub_memmove (real_mode_mem, &lh, sizeof (lh));
|
||||
#endif
|
||||
|
||||
len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
|
||||
if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
|
||||
goto fail;
|
||||
}
|
||||
/* The other EFI parameters are filled when booting. */
|
||||
|
||||
grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
|
||||
|
||||
/* XXX there is no way to know if the kernel really supports EFI. */
|
||||
grub_printf (" [Linux-EFI, setup=0x%x, size=0x%x]\n",
|
||||
real_size, prot_size);
|
||||
(unsigned) real_size, (unsigned) prot_size);
|
||||
|
||||
/* Detect explicitly specified memory size, if any. */
|
||||
linux_mem_size = 0;
|
||||
video_type = 0;
|
||||
for (i = 1; i < argc; i++)
|
||||
if (grub_memcmp (argv[i], "mem=", 4) == 0)
|
||||
{
|
||||
|
@ -529,9 +799,22 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
linux_mem_size <<= shift;
|
||||
}
|
||||
}
|
||||
else if (grub_memcmp (argv[i], "video=", 6) == 0)
|
||||
{
|
||||
if (grub_memcmp (&argv[i][6], "vesafb", 6) == 0)
|
||||
video_type = GRUB_VIDEO_TYPE_VLFB;
|
||||
else if (grub_memcmp (&argv[i][6], "efifb", 5) == 0)
|
||||
video_type = GRUB_VIDEO_TYPE_EFI;
|
||||
}
|
||||
|
||||
if (video_type)
|
||||
{
|
||||
if (! grub_linux_setup_video (params))
|
||||
params->have_vga = video_type;
|
||||
}
|
||||
|
||||
/* Specify the boot file. */
|
||||
dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
|
||||
dest = grub_stpcpy ((char *) real_mode_mem + GRUB_EFI_CL_OFFSET,
|
||||
"BOOT_IMAGE=");
|
||||
dest = grub_stpcpy (dest, argv[0]);
|
||||
|
||||
|
@ -539,7 +822,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
|
|||
for (i = 1;
|
||||
i < argc
|
||||
&& dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
|
||||
+ GRUB_LINUX_CL_END_OFFSET);
|
||||
+ GRUB_EFI_CL_END_OFFSET);
|
||||
i++)
|
||||
{
|
||||
*dest++ = ' ';
|
||||
|
@ -601,7 +884,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
|
|||
|
||||
lh = (struct linux_kernel_header *) real_mode_mem;
|
||||
|
||||
addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
|
||||
addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
|
||||
if (linux_mem_size != 0 && linux_mem_size < addr_max)
|
||||
addr_max = linux_mem_size;
|
||||
|
||||
|
@ -612,7 +895,8 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
|
|||
addr_max -= 0x10000;
|
||||
|
||||
/* Usually, the compression ratio is about 50%. */
|
||||
addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12);
|
||||
addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
|
||||
+ page_align (size);
|
||||
|
||||
/* Find the highest address to put the initrd. */
|
||||
mmap_size = find_mmap_size ();
|
||||
|
@ -625,8 +909,6 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
|
|||
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
|
||||
{
|
||||
if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
|
||||
&& desc->physical_start >= addr_min
|
||||
&& desc->physical_start + size < addr_max
|
||||
&& desc->num_pages >= initrd_pages)
|
||||
{
|
||||
grub_efi_physical_address_t physical_end;
|
||||
|
@ -635,6 +917,9 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
|
|||
if (physical_end > addr_max)
|
||||
physical_end = addr_max;
|
||||
|
||||
if (physical_end < addr_min)
|
||||
continue;
|
||||
|
||||
if (physical_end > addr)
|
||||
addr = physical_end - page_align (size);
|
||||
}
|
||||
|
@ -657,7 +942,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
|
|||
}
|
||||
|
||||
grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n",
|
||||
addr, size);
|
||||
(unsigned) addr, (unsigned) size);
|
||||
|
||||
lh->ramdisk_image = addr;
|
||||
lh->ramdisk_size = size;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue