Add new ports: i386-xen and x86_64-xen. This allows running GRUB in
XEN PV environment and load kernels.
This commit is contained in:
parent
1a46a3a4b3
commit
9612ebc00e
59 changed files with 4167 additions and 259 deletions
712
grub-core/loader/i386/xen.c
Normal file
712
grub-core/loader/i386/xen.c
Normal file
|
@ -0,0 +1,712 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2013 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/loader.h>
|
||||
#include <grub/memory.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/cpu/linux.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/video_fb.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/xen/relocator.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/elfload.h>
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/xen.h>
|
||||
#include <grub/xen_file.h>
|
||||
#include <grub/linux.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static struct grub_relocator *relocator = NULL;
|
||||
static grub_uint64_t max_addr;
|
||||
static grub_dl_t my_mod;
|
||||
static int loaded = 0;
|
||||
static struct start_info next_start;
|
||||
static void *kern_chunk_src;
|
||||
static struct grub_xen_file_info xen_inf;
|
||||
static struct xen_multiboot_mod_list *xen_module_info_page;
|
||||
static grub_uint64_t modules_target_start;
|
||||
static grub_size_t n_modules;
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define MAX_MODULES (PAGE_SIZE / sizeof (struct xen_multiboot_mod_list))
|
||||
#define PAGE_SHIFT 12
|
||||
#define STACK_SIZE 1048576
|
||||
#define ADDITIONAL_SIZE (1 << 19)
|
||||
#define ALIGN_SIZE (1 << 22)
|
||||
#define LOG_POINTERS_PER_PAGE 9
|
||||
#define POINTERS_PER_PAGE (1 << LOG_POINTERS_PER_PAGE)
|
||||
|
||||
static grub_uint64_t
|
||||
page2offset (grub_uint64_t page)
|
||||
{
|
||||
return page << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define NUMBER_OF_LEVELS 4
|
||||
#define INTERMEDIATE_OR 7
|
||||
#else
|
||||
#define NUMBER_OF_LEVELS 3
|
||||
#define INTERMEDIATE_OR 3
|
||||
#endif
|
||||
|
||||
static grub_uint64_t
|
||||
get_pgtable_size (grub_uint64_t total_pages, grub_uint64_t virt_base)
|
||||
{
|
||||
if (!virt_base)
|
||||
total_pages++;
|
||||
grub_uint64_t ret = 0;
|
||||
grub_uint64_t ll = total_pages;
|
||||
int i;
|
||||
for (i = 0; i < NUMBER_OF_LEVELS; i++)
|
||||
{
|
||||
ll = (ll + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
|
||||
/* PAE wants all 4 root directories present. */
|
||||
#ifdef __i386__
|
||||
if (i == 1)
|
||||
ll = 4;
|
||||
#endif
|
||||
ret += ll;
|
||||
}
|
||||
for (i = 1; i < NUMBER_OF_LEVELS; i++)
|
||||
if (virt_base >> (PAGE_SHIFT + i * LOG_POINTERS_PER_PAGE))
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
generate_page_table (grub_uint64_t *where, grub_uint64_t paging_start,
|
||||
grub_uint64_t total_pages, grub_uint64_t virt_base,
|
||||
grub_xen_mfn_t *mfn_list)
|
||||
{
|
||||
if (!virt_base)
|
||||
total_pages++;
|
||||
|
||||
grub_uint64_t lx[NUMBER_OF_LEVELS], lxs[NUMBER_OF_LEVELS];
|
||||
grub_uint64_t nlx, nls, sz = 0;
|
||||
int l;
|
||||
|
||||
nlx = total_pages;
|
||||
nls = virt_base >> PAGE_SHIFT;
|
||||
for (l = 0; l < NUMBER_OF_LEVELS; l++)
|
||||
{
|
||||
nlx = (nlx + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
|
||||
/* PAE wants all 4 root directories present. */
|
||||
#ifdef __i386__
|
||||
if (l == 1)
|
||||
nlx = 4;
|
||||
#endif
|
||||
lx[l] = nlx;
|
||||
sz += lx[l];
|
||||
lxs[l] = nls & (POINTERS_PER_PAGE - 1);
|
||||
if (nls && l != 0)
|
||||
sz++;
|
||||
nls >>= LOG_POINTERS_PER_PAGE;
|
||||
}
|
||||
|
||||
grub_uint64_t lp;
|
||||
grub_uint64_t j;
|
||||
grub_uint64_t *pg = (grub_uint64_t *) where;
|
||||
int pr = 0;
|
||||
|
||||
grub_memset (pg, 0, sz * PAGE_SIZE);
|
||||
|
||||
lp = paging_start + lx[NUMBER_OF_LEVELS - 1];
|
||||
for (l = NUMBER_OF_LEVELS - 1; l >= 1; l--)
|
||||
{
|
||||
if (lxs[l] || pr)
|
||||
pg[0] = page2offset (mfn_list[lp++]) | INTERMEDIATE_OR;
|
||||
if (pr)
|
||||
pg += POINTERS_PER_PAGE;
|
||||
for (j = 0; j < lx[l - 1]; j++)
|
||||
pg[j + lxs[l]] = page2offset (mfn_list[lp++]) | INTERMEDIATE_OR;
|
||||
pg += lx[l] * POINTERS_PER_PAGE;
|
||||
if (lxs[l])
|
||||
pr = 1;
|
||||
}
|
||||
|
||||
if (lxs[0] || pr)
|
||||
pg[0] = page2offset (mfn_list[total_pages]) | 5;
|
||||
if (pr)
|
||||
pg += POINTERS_PER_PAGE;
|
||||
|
||||
for (j = 0; j < total_pages; j++)
|
||||
{
|
||||
if (j >= paging_start && j < lp)
|
||||
pg[j + lxs[0]] = page2offset (mfn_list[j]) | 5;
|
||||
else
|
||||
pg[j + lxs[0]] = page2offset (mfn_list[j]) | 7;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
set_mfns (grub_xen_mfn_t * new_mfn_list, grub_xen_mfn_t pfn)
|
||||
{
|
||||
grub_xen_mfn_t i, t;
|
||||
grub_xen_mfn_t cn_pfn = -1, st_pfn = -1;
|
||||
struct mmu_update m2p_updates[4];
|
||||
|
||||
|
||||
for (i = 0; i < grub_xen_start_page_addr->nr_pages; i++)
|
||||
{
|
||||
if (new_mfn_list[i] == grub_xen_start_page_addr->console.domU.mfn)
|
||||
cn_pfn = i;
|
||||
if (new_mfn_list[i] == grub_xen_start_page_addr->store_mfn)
|
||||
st_pfn = i;
|
||||
}
|
||||
if (cn_pfn == (grub_xen_mfn_t)-1)
|
||||
return grub_error (GRUB_ERR_BUG, "no console");
|
||||
if (st_pfn == (grub_xen_mfn_t)-1)
|
||||
return grub_error (GRUB_ERR_BUG, "no store");
|
||||
t = new_mfn_list[pfn];
|
||||
new_mfn_list[pfn] = new_mfn_list[cn_pfn];
|
||||
new_mfn_list[cn_pfn] = t;
|
||||
t = new_mfn_list[pfn + 1];
|
||||
new_mfn_list[pfn + 1] = new_mfn_list[st_pfn];
|
||||
new_mfn_list[st_pfn] = t;
|
||||
|
||||
m2p_updates[0].ptr = page2offset (new_mfn_list[pfn]) | MMU_MACHPHYS_UPDATE;
|
||||
m2p_updates[0].val = pfn;
|
||||
m2p_updates[1].ptr =
|
||||
page2offset (new_mfn_list[pfn + 1]) | MMU_MACHPHYS_UPDATE;
|
||||
m2p_updates[1].val = pfn + 1;
|
||||
m2p_updates[2].ptr =
|
||||
page2offset (new_mfn_list[cn_pfn]) | MMU_MACHPHYS_UPDATE;
|
||||
m2p_updates[2].val = cn_pfn;
|
||||
m2p_updates[3].ptr =
|
||||
page2offset (new_mfn_list[st_pfn]) | MMU_MACHPHYS_UPDATE;
|
||||
m2p_updates[3].val = st_pfn;
|
||||
|
||||
grub_xen_mmu_update (m2p_updates, 4, NULL, DOMID_SELF);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_xen_boot (void)
|
||||
{
|
||||
struct grub_relocator_xen_state state;
|
||||
grub_relocator_chunk_t ch;
|
||||
grub_err_t err;
|
||||
grub_size_t pgtsize;
|
||||
struct start_info *nst;
|
||||
grub_uint64_t nr_info_pages;
|
||||
grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
|
||||
struct gnttab_set_version gnttab_setver;
|
||||
grub_xen_mfn_t *new_mfn_list;
|
||||
grub_size_t i;
|
||||
|
||||
if (grub_xen_n_allocated_shared_pages)
|
||||
return grub_error (GRUB_ERR_BUG, "active grants");
|
||||
|
||||
state.mfn_list = max_addr;
|
||||
next_start.mfn_list = max_addr + xen_inf.virt_base;
|
||||
next_start.first_p2m_pfn = max_addr >> PAGE_SHIFT; /* Is this right? */
|
||||
pgtsize = sizeof (grub_xen_mfn_t) * grub_xen_start_page_addr->nr_pages;
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, pgtsize);
|
||||
next_start.nr_p2m_frames = (pgtsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
if (err)
|
||||
return err;
|
||||
new_mfn_list = get_virtual_current_address (ch);
|
||||
grub_memcpy (new_mfn_list,
|
||||
(void *) grub_xen_start_page_addr->mfn_list, pgtsize);
|
||||
max_addr = ALIGN_UP (max_addr + pgtsize, PAGE_SIZE);
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
|
||||
max_addr, sizeof (next_start));
|
||||
if (err)
|
||||
return err;
|
||||
state.start_info = max_addr + xen_inf.virt_base;
|
||||
nst = get_virtual_current_address (ch);
|
||||
max_addr = ALIGN_UP (max_addr + sizeof (next_start), PAGE_SIZE);
|
||||
|
||||
next_start.nr_pages = grub_xen_start_page_addr->nr_pages;
|
||||
grub_memcpy (next_start.magic, grub_xen_start_page_addr->magic,
|
||||
sizeof (next_start.magic));
|
||||
next_start.store_mfn = grub_xen_start_page_addr->store_mfn;
|
||||
next_start.store_evtchn = grub_xen_start_page_addr->store_evtchn;
|
||||
next_start.console.domU = grub_xen_start_page_addr->console.domU;
|
||||
next_start.shared_info = grub_xen_start_page_addr->shared_info;
|
||||
|
||||
err = set_mfns (new_mfn_list, max_addr >> PAGE_SHIFT);
|
||||
if (err)
|
||||
return err;
|
||||
max_addr += 2 * PAGE_SIZE;
|
||||
|
||||
next_start.pt_base = max_addr + xen_inf.virt_base;
|
||||
state.paging_start = max_addr >> PAGE_SHIFT;
|
||||
|
||||
nr_info_pages = max_addr >> PAGE_SHIFT;
|
||||
nr_pages = nr_info_pages;
|
||||
|
||||
while (1)
|
||||
{
|
||||
nr_pages = ALIGN_UP (nr_pages, (ALIGN_SIZE >> PAGE_SHIFT));
|
||||
nr_pt_pages = get_pgtable_size (nr_pages, xen_inf.virt_base);
|
||||
nr_need_pages =
|
||||
nr_info_pages + nr_pt_pages +
|
||||
((ADDITIONAL_SIZE + STACK_SIZE) >> PAGE_SHIFT);
|
||||
if (nr_pages >= nr_need_pages)
|
||||
break;
|
||||
nr_pages = nr_need_pages;
|
||||
}
|
||||
|
||||
grub_dprintf ("xen", "bootstrap domain %llx+%llx\n",
|
||||
(unsigned long long) xen_inf.virt_base,
|
||||
(unsigned long long) page2offset (nr_pages));
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
|
||||
max_addr, page2offset (nr_pt_pages));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
generate_page_table (get_virtual_current_address (ch),
|
||||
max_addr >> PAGE_SHIFT, nr_pages,
|
||||
xen_inf.virt_base, new_mfn_list);
|
||||
|
||||
max_addr += page2offset (nr_pt_pages);
|
||||
state.stack = max_addr + STACK_SIZE + xen_inf.virt_base;
|
||||
state.entry_point = xen_inf.entry_point;
|
||||
|
||||
next_start.nr_p2m_frames += nr_pt_pages;
|
||||
next_start.nr_pt_frames = nr_pt_pages;
|
||||
state.paging_size = nr_pt_pages;
|
||||
|
||||
*nst = next_start;
|
||||
|
||||
grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
|
||||
|
||||
gnttab_setver.version = 1;
|
||||
grub_xen_grant_table_op (GNTTABOP_set_version, &gnttab_setver, 1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (grub_xen_shared_info->evtchn_pending); i++)
|
||||
grub_xen_shared_info->evtchn_pending[i] = 0;
|
||||
|
||||
return grub_relocator_xen_boot (relocator, state, nr_pages,
|
||||
xen_inf.virt_base <
|
||||
PAGE_SIZE ? page2offset (nr_pages) : 0,
|
||||
nr_pages - 1,
|
||||
page2offset (nr_pages - 1) +
|
||||
xen_inf.virt_base);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_xen_unload (void)
|
||||
{
|
||||
grub_dl_unref (my_mod);
|
||||
loaded = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#define HYPERCALL_INTERFACE_SIZE 32
|
||||
|
||||
#ifdef __x86_64__
|
||||
static grub_uint8_t template[] =
|
||||
{
|
||||
0x51, /* push %rcx */
|
||||
0x41, 0x53, /* push %r11 */
|
||||
0x48, 0xc7, 0xc0, 0xbb, 0xaa, 0x00, 0x00, /* mov $0xaabb,%rax */
|
||||
0x0f, 0x05, /* syscall */
|
||||
0x41, 0x5b, /* pop %r11 */
|
||||
0x59, /* pop %rcx */
|
||||
0xc3 /* ret */
|
||||
};
|
||||
|
||||
static grub_uint8_t template_iret[] =
|
||||
{
|
||||
0x51, /* push %rcx */
|
||||
0x41, 0x53, /* push %r11 */
|
||||
0x50, /* push %rax */
|
||||
0x48, 0xc7, 0xc0, 0x17, 0x00, 0x00, 0x00, /* mov $0x17,%rax */
|
||||
0x0f, 0x05 /* syscall */
|
||||
};
|
||||
#define CALLNO_OFFSET 6
|
||||
#else
|
||||
|
||||
static grub_uint8_t template[] =
|
||||
{
|
||||
0xb8, 0xbb, 0xaa, 0x00, 0x00, /* mov imm32, %eax */
|
||||
0xcd, 0x82, /* int $0x82 */
|
||||
0xc3 /* ret */
|
||||
};
|
||||
|
||||
static grub_uint8_t template_iret[] =
|
||||
{
|
||||
0x50, /* push %eax */
|
||||
0xb8, 0x17, 0x00, 0x00, 0x00, /* mov $0x17,%eax */
|
||||
0xcd, 0x82, /* int $0x82 */
|
||||
};
|
||||
#define CALLNO_OFFSET 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
set_hypercall_interface (grub_uint8_t *tgt, unsigned callno)
|
||||
{
|
||||
if (callno == 0x17)
|
||||
{
|
||||
grub_memcpy (tgt, template_iret, ARRAY_SIZE (template_iret));
|
||||
grub_memset (tgt + ARRAY_SIZE (template_iret), 0xcc,
|
||||
HYPERCALL_INTERFACE_SIZE - ARRAY_SIZE (template_iret));
|
||||
return;
|
||||
}
|
||||
grub_memcpy (tgt, template, ARRAY_SIZE (template));
|
||||
grub_memset (tgt + ARRAY_SIZE (template), 0xcc,
|
||||
HYPERCALL_INTERFACE_SIZE - ARRAY_SIZE (template));
|
||||
tgt[CALLNO_OFFSET] = callno & 0xff;
|
||||
tgt[CALLNO_OFFSET + 1] = callno >> 8;
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define grub_elfXX_load grub_elf64_load
|
||||
#else
|
||||
#define grub_elfXX_load grub_elf32_load
|
||||
#endif
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_file_t file;
|
||||
grub_elf_t elf;
|
||||
grub_err_t err;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
|
||||
grub_loader_unset ();
|
||||
|
||||
grub_memset (&next_start, 0, sizeof (next_start));
|
||||
|
||||
xen_module_info_page = NULL;
|
||||
n_modules = 0;
|
||||
|
||||
grub_create_loader_cmdline (argc - 1, argv + 1,
|
||||
(char *) next_start.cmd_line,
|
||||
sizeof (next_start.cmd_line) - 1);
|
||||
|
||||
file = grub_file_open (argv[0]);
|
||||
if (!file)
|
||||
return grub_errno;
|
||||
|
||||
elf = grub_xen_file (file);
|
||||
if (!elf)
|
||||
goto fail;
|
||||
|
||||
err = grub_xen_get_info (elf, &xen_inf);
|
||||
if (err)
|
||||
goto fail;
|
||||
#ifdef __x86_64__
|
||||
if (xen_inf.arch != GRUB_XEN_FILE_X86_64)
|
||||
#else
|
||||
if (xen_inf.arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xen_inf.arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
#endif
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "incompatible architecture: %d",
|
||||
xen_inf.arch);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (xen_inf.virt_base & (PAGE_SIZE - 1))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "unaligned virt_base");
|
||||
goto fail;
|
||||
}
|
||||
grub_dprintf ("xen", "virt_base = %llx, entry = %llx\n",
|
||||
(unsigned long long) xen_inf.virt_base,
|
||||
(unsigned long long) xen_inf.entry_point);
|
||||
|
||||
relocator = grub_relocator_new ();
|
||||
if (!relocator)
|
||||
goto fail;
|
||||
|
||||
grub_relocator_chunk_t ch;
|
||||
grub_addr_t kern_start = xen_inf.kern_start - xen_inf.paddr_offset;
|
||||
grub_addr_t kern_end = xen_inf.kern_end - xen_inf.paddr_offset;
|
||||
|
||||
if (xen_inf.has_hypercall_page)
|
||||
{
|
||||
grub_dprintf ("xen", "hypercall page at 0x%llx\n",
|
||||
(unsigned long long) xen_inf.hypercall_page);
|
||||
if (xen_inf.hypercall_page - xen_inf.virt_base < kern_start)
|
||||
kern_start = xen_inf.hypercall_page - xen_inf.virt_base;
|
||||
|
||||
if (xen_inf.hypercall_page - xen_inf.virt_base + PAGE_SIZE > kern_end)
|
||||
kern_end = xen_inf.hypercall_page - xen_inf.virt_base + PAGE_SIZE;
|
||||
}
|
||||
|
||||
max_addr = ALIGN_UP (kern_end, PAGE_SIZE);
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
|
||||
kern_end - kern_start);
|
||||
if (err)
|
||||
goto fail;
|
||||
kern_chunk_src = get_virtual_current_address (ch);
|
||||
|
||||
grub_dprintf ("xen", "paddr_offset = 0x%llx\n",
|
||||
(unsigned long long) xen_inf.paddr_offset);
|
||||
grub_dprintf ("xen", "kern_start = 0x%llx, kern_end = 0x%llx\n",
|
||||
(unsigned long long) xen_inf.kern_start,
|
||||
(unsigned long long) xen_inf.kern_end);
|
||||
|
||||
err = grub_elfXX_load (elf, argv[0],
|
||||
(grub_uint8_t *) kern_chunk_src - kern_start
|
||||
- xen_inf.paddr_offset, 0, 0, 0);
|
||||
|
||||
if (xen_inf.has_hypercall_page)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < PAGE_SIZE / HYPERCALL_INTERFACE_SIZE; i++)
|
||||
set_hypercall_interface ((grub_uint8_t *) kern_chunk_src +
|
||||
i * HYPERCALL_INTERFACE_SIZE +
|
||||
xen_inf.hypercall_page - xen_inf.virt_base -
|
||||
kern_start, i);
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
grub_dl_ref (my_mod);
|
||||
loaded = 1;
|
||||
|
||||
grub_loader_set (grub_xen_boot, grub_xen_unload, 0);
|
||||
loaded = 1;
|
||||
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
|
||||
if (elf)
|
||||
grub_elf_close (elf);
|
||||
else if (file)
|
||||
grub_file_close (file);
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
loaded = 0;
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_size_t size = 0;
|
||||
grub_err_t err;
|
||||
struct grub_linux_initrd_context initrd_ctx;
|
||||
grub_relocator_chunk_t ch;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("you need to load the kernel first"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (next_start.mod_start || next_start.mod_len)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (grub_initrd_init (argc, argv, &initrd_ctx))
|
||||
goto fail;
|
||||
|
||||
size = grub_get_initrd_size (&initrd_ctx);
|
||||
|
||||
if (size)
|
||||
{
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (grub_initrd_load (&initrd_ctx, argv,
|
||||
get_virtual_current_address (ch)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
next_start.mod_start = max_addr + xen_inf.virt_base;
|
||||
next_start.mod_len = size;
|
||||
|
||||
max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
|
||||
|
||||
grub_dprintf ("xen", "Initrd, addr=0x%x, size=0x%x\n",
|
||||
(unsigned) next_start.mod_start, (unsigned) size);
|
||||
|
||||
fail:
|
||||
grub_initrd_close (&initrd_ctx);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
grub_size_t size = 0;
|
||||
grub_err_t err;
|
||||
grub_relocator_chunk_t ch;
|
||||
grub_size_t cmdline_len;
|
||||
int nounzip = 0;
|
||||
grub_file_t file;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
|
||||
if (grub_strcmp (argv[0], "--nounzip") == 0)
|
||||
{
|
||||
argv++;
|
||||
argc--;
|
||||
nounzip = 1;
|
||||
}
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
|
||||
|
||||
if (!loaded)
|
||||
{
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
N_("you need to load the kernel first"));
|
||||
}
|
||||
|
||||
if ((next_start.mod_start || next_start.mod_len) && !xen_module_info_page)
|
||||
{
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
|
||||
}
|
||||
|
||||
/* Leave one space for terminator. */
|
||||
if (n_modules >= MAX_MODULES - 1)
|
||||
{
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many modules");
|
||||
}
|
||||
|
||||
if (!xen_module_info_page)
|
||||
{
|
||||
n_modules = 0;
|
||||
max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
|
||||
modules_target_start = max_addr;
|
||||
next_start.mod_start = max_addr + xen_inf.virt_base;
|
||||
next_start.flags |= SIF_MULTIBOOT_MOD;
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
|
||||
max_addr, MAX_MODULES
|
||||
*
|
||||
sizeof (xen_module_info_page
|
||||
[0]));
|
||||
if (err)
|
||||
return err;
|
||||
xen_module_info_page = get_virtual_current_address (ch);
|
||||
grub_memset (xen_module_info_page, 0, MAX_MODULES
|
||||
* sizeof (xen_module_info_page[0]));
|
||||
max_addr += MAX_MODULES * sizeof (xen_module_info_page[0]);
|
||||
}
|
||||
|
||||
max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
|
||||
|
||||
if (nounzip)
|
||||
grub_file_filter_disable_compression ();
|
||||
file = grub_file_open (argv[0]);
|
||||
if (!file)
|
||||
return grub_errno;
|
||||
size = grub_file_size (file);
|
||||
|
||||
cmdline_len = grub_loader_cmdline_size (argc - 1, argv + 1);
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
|
||||
max_addr, cmdline_len);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
grub_create_loader_cmdline (argc - 1, argv + 1,
|
||||
get_virtual_current_address (ch), cmdline_len);
|
||||
|
||||
xen_module_info_page[n_modules].cmdline = max_addr - modules_target_start;
|
||||
max_addr = ALIGN_UP (max_addr + cmdline_len, PAGE_SIZE);
|
||||
|
||||
if (size)
|
||||
{
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
|
||||
if (err)
|
||||
goto fail;
|
||||
if (grub_file_read (file, get_virtual_current_address (ch), size)
|
||||
!= (grub_ssize_t) size)
|
||||
{
|
||||
if (!grub_errno)
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR,
|
||||
N_("premature end of file %s"), argv[0]);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
next_start.mod_len = max_addr + size - modules_target_start;
|
||||
xen_module_info_page[n_modules].mod_start = max_addr - modules_target_start;
|
||||
xen_module_info_page[n_modules].mod_end =
|
||||
max_addr + size - modules_target_start;
|
||||
|
||||
n_modules++;
|
||||
grub_dprintf ("xen", "module, addr=0x%x, size=0x%x\n",
|
||||
(unsigned) max_addr, (unsigned) size);
|
||||
max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
|
||||
|
||||
|
||||
fail:
|
||||
grub_file_close (file);
|
||||
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static grub_command_t cmd_xen, cmd_initrd, cmd_module, cmd_multiboot;
|
||||
|
||||
GRUB_MOD_INIT (xen)
|
||||
{
|
||||
cmd_xen = grub_register_command ("linux", grub_cmd_xen,
|
||||
0, N_("Load linux."));
|
||||
cmd_multiboot = grub_register_command ("multiboot", grub_cmd_xen,
|
||||
0, N_("Load linux."));
|
||||
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
|
||||
0, N_("Load initrd."));
|
||||
cmd_module = grub_register_command ("module", grub_cmd_module,
|
||||
0, N_("Load module."));
|
||||
my_mod = mod;
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (xen)
|
||||
{
|
||||
grub_unregister_command (cmd_xen);
|
||||
grub_unregister_command (cmd_initrd);
|
||||
grub_unregister_command (cmd_multiboot);
|
||||
grub_unregister_command (cmd_module);
|
||||
}
|
91
grub-core/loader/i386/xen_file.c
Normal file
91
grub-core/loader/i386/xen_file.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2013 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/xen_file.h>
|
||||
#include <grub/i386/linux.h>
|
||||
|
||||
grub_elf_t
|
||||
grub_xen_file (grub_file_t file)
|
||||
{
|
||||
grub_elf_t elf;
|
||||
struct linux_kernel_header lh;
|
||||
grub_file_t off_file;
|
||||
|
||||
elf = grub_elf_file (file, file->name);
|
||||
if (elf)
|
||||
return elf;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
if (grub_file_seek (file, 0) == (grub_off_t) -1)
|
||||
goto fail;
|
||||
|
||||
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
|
||||
goto fail;
|
||||
|
||||
if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)
|
||||
|| lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
|
||||
|| grub_le_to_cpu16 (lh.version) < 0x0208)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "version too old for xen boot");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lh.payload_length < 4)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_OS, "payload too short");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_dprintf ("xen", "found bzimage payload 0x%llx-0x%llx\n",
|
||||
(unsigned long long) (lh.setup_sects + 1) * 512
|
||||
+ lh.payload_offset,
|
||||
(unsigned long long) lh.payload_length - 4);
|
||||
|
||||
off_file = grub_file_offset_open (file, (lh.setup_sects + 1) * 512
|
||||
+ lh.payload_offset,
|
||||
lh.payload_length - 4);
|
||||
if (!off_file)
|
||||
goto fail;
|
||||
|
||||
elf = grub_elf_file (off_file, file->name);
|
||||
if (elf)
|
||||
return elf;
|
||||
grub_file_offset_close (off_file);
|
||||
|
||||
fail:
|
||||
grub_error (GRUB_ERR_BAD_OS, "not xen image");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_xen_get_info (grub_elf_t elf, struct grub_xen_file_info * xi)
|
||||
{
|
||||
grub_memset (xi, 0, sizeof (*xi));
|
||||
|
||||
if (grub_elf_is_elf64 (elf))
|
||||
{
|
||||
xi->arch = GRUB_XEN_FILE_X86_64;
|
||||
return grub_xen_get_info64 (elf, xi);
|
||||
}
|
||||
if (grub_elf_is_elf32 (elf))
|
||||
{
|
||||
xi->arch = GRUB_XEN_FILE_I386;
|
||||
return grub_xen_get_info32 (elf, xi);
|
||||
}
|
||||
return grub_error (GRUB_ERR_BAD_OS, "unknown ELF type");
|
||||
}
|
7
grub-core/loader/i386/xen_file32.c
Normal file
7
grub-core/loader/i386/xen_file32.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#define GRUB_TARGET_WORDSIZE 32
|
||||
#define XX 32
|
||||
#define grub_le_to_cpu_addr grub_le_to_cpu32
|
||||
#define ehdrXX ehdr32
|
||||
#define grub_xen_get_infoXX grub_xen_get_info32
|
||||
#define FOR_ELF_PHDRS FOR_ELF32_PHDRS
|
||||
#include "xen_fileXX.c"
|
7
grub-core/loader/i386/xen_file64.c
Normal file
7
grub-core/loader/i386/xen_file64.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#define GRUB_TARGET_WORDSIZE 64
|
||||
#define XX 64
|
||||
#define grub_le_to_cpu_addr grub_le_to_cpu64
|
||||
#define ehdrXX ehdr64
|
||||
#define grub_xen_get_infoXX grub_xen_get_info64
|
||||
#define FOR_ELF_PHDRS FOR_ELF64_PHDRS
|
||||
#include "xen_fileXX.c"
|
344
grub-core/loader/i386/xen_fileXX.c
Normal file
344
grub-core/loader/i386/xen_fileXX.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2013 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/xen_file.h>
|
||||
|
||||
static grub_err_t
|
||||
parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
|
||||
grub_off_t off, grub_size_t sz)
|
||||
{
|
||||
char *buf;
|
||||
char *ptr;
|
||||
int has_paddr = 0;
|
||||
if (grub_file_seek (elf->file, off) == (grub_off_t) -1)
|
||||
return grub_errno;
|
||||
buf = grub_malloc (sz);
|
||||
if (!buf)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_file_read (elf->file, buf, sz) != (grub_ssize_t) sz)
|
||||
{
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
elf->file->name);
|
||||
}
|
||||
xi->has_xen_guest = 1;
|
||||
for (ptr = buf; ptr && ptr - buf < (grub_ssize_t) sz;
|
||||
ptr = grub_strchr (ptr, ','), (ptr ? ptr++ : 0))
|
||||
{
|
||||
if (grub_strncmp (ptr, "PAE=no,", sizeof ("PAE=no,") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "PAE=yes,", sizeof ("PAE=yes,") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "PAE=yes[extended-cr3],",
|
||||
sizeof ("PAE=yes[extended-cr3],") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE;
|
||||
xi->extended_cr3 = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "PAE=bimodal,", sizeof ("PAE=bimodal,") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "PAE=bimodal[extended-cr3],",
|
||||
sizeof ("PAE=bimodal[extended-cr3],") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
|
||||
xi->extended_cr3 = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "PAE=yes,bimodal,", sizeof ("PAE=yes,bimodal,") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "PAE=yes[extended-cr3],bimodal,",
|
||||
sizeof ("PAE=yes[extended-cr3],bimodal,") - 1) == 0)
|
||||
{
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
continue;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
|
||||
xi->extended_cr3 = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_strncmp (ptr, "VIRT_BASE=", sizeof ("VIRT_BASE=") - 1) == 0)
|
||||
{
|
||||
xi->virt_base = grub_strtoull (ptr + sizeof ("VIRT_BASE=") - 1, &ptr, 16);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
continue;
|
||||
}
|
||||
if (grub_strncmp (ptr, "VIRT_ENTRY=", sizeof ("VIRT_ENTRY=") - 1) == 0)
|
||||
{
|
||||
xi->entry_point = grub_strtoull (ptr + sizeof ("VIRT_ENTRY=") - 1, &ptr, 16);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
continue;
|
||||
}
|
||||
if (grub_strncmp (ptr, "HYPERCALL_PAGE=", sizeof ("HYPERCALL_PAGE=") - 1) == 0)
|
||||
{
|
||||
xi->hypercall_page = grub_strtoull (ptr + sizeof ("HYPERCALL_PAGE=") - 1, &ptr, 16);
|
||||
xi->has_hypercall_page = 1;
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
continue;
|
||||
}
|
||||
if (grub_strncmp (ptr, "ELF_PADDR_OFFSET=", sizeof ("ELF_PADDR_OFFSET=") - 1) == 0)
|
||||
{
|
||||
xi->paddr_offset = grub_strtoull (ptr + sizeof ("ELF_PADDR_OFFSET=") - 1, &ptr, 16);
|
||||
has_paddr = 1;
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (xi->has_hypercall_page)
|
||||
xi->hypercall_page = (xi->hypercall_page << 12) + xi->virt_base;
|
||||
if (!has_paddr)
|
||||
xi->paddr_offset = xi->virt_base;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
parse_note (grub_elf_t elf, struct grub_xen_file_info *xi,
|
||||
grub_off_t off, grub_size_t sz)
|
||||
{
|
||||
grub_uint32_t *buf;
|
||||
grub_uint32_t *ptr;
|
||||
if (grub_file_seek (elf->file, off) == (grub_off_t) -1)
|
||||
return grub_errno;
|
||||
buf = grub_malloc (sz);
|
||||
if (!buf)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_file_read (elf->file, buf, sz) != (grub_ssize_t) sz)
|
||||
{
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
elf->file->name);
|
||||
}
|
||||
for (ptr = buf; ptr - buf < (grub_ssize_t) (sz / sizeof (grub_uint32_t));)
|
||||
{
|
||||
Elf_Nhdr *nh = (Elf_Nhdr *) ptr;
|
||||
char *name;
|
||||
grub_uint32_t *desc;
|
||||
grub_uint32_t namesz, descsz;
|
||||
ptr += sizeof (*nh) / sizeof (grub_uint32_t);
|
||||
name = (char *) ptr;
|
||||
namesz = grub_le_to_cpu32 (nh->n_namesz);
|
||||
descsz = grub_le_to_cpu32 (nh->n_descsz);
|
||||
ptr += (namesz + 3) / 4;
|
||||
desc = ptr;
|
||||
ptr += (grub_le_to_cpu32 (nh->n_descsz) + 3) / 4;
|
||||
if ((namesz < 3) || grub_memcmp (name, "Xen", namesz == 3 ? 3 : 4) != 0)
|
||||
continue;
|
||||
xi->has_note = 1;
|
||||
switch (nh->n_type)
|
||||
{
|
||||
case 1:
|
||||
xi->entry_point = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
|
||||
break;
|
||||
case 2:
|
||||
xi->hypercall_page = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
|
||||
xi->has_hypercall_page = 1;
|
||||
break;
|
||||
case 3:
|
||||
xi->virt_base = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
|
||||
break;
|
||||
case 4:
|
||||
xi->paddr_offset = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
|
||||
break;
|
||||
case 5:
|
||||
grub_dprintf ("xen", "xenversion = `%s'\n", (char *) desc);
|
||||
break;
|
||||
case 6:
|
||||
grub_dprintf ("xen", "name = `%s'\n", (char *) desc);
|
||||
break;
|
||||
case 7:
|
||||
grub_dprintf ("xen", "version = `%s'\n", (char *) desc);
|
||||
break;
|
||||
case 8:
|
||||
if (descsz < 7
|
||||
|| grub_memcmp (desc, "generic", descsz == 7 ? 7 : 8) != 0)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "invalid loader");
|
||||
break;
|
||||
/* PAE */
|
||||
case 9:
|
||||
grub_dprintf ("xen", "pae = `%s', %d, %d\n", (char *) desc,
|
||||
xi->arch, descsz);
|
||||
if (xi->arch != GRUB_XEN_FILE_I386
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE
|
||||
&& xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
|
||||
break;
|
||||
if (descsz >= 3 && grub_memcmp (desc, "yes",
|
||||
descsz == 3 ? 3 : 4) == 0)
|
||||
{
|
||||
xi->extended_cr3 = 1;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE;
|
||||
}
|
||||
if (descsz >= 7 && grub_memcmp (desc, "bimodal",
|
||||
descsz == 7 ? 7 : 8) == 0)
|
||||
{
|
||||
xi->extended_cr3 = 1;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
|
||||
}
|
||||
if (descsz >= 11 && grub_memcmp (desc, "yes,bimodal",
|
||||
descsz == 11 ? 11 : 12) == 0)
|
||||
{
|
||||
xi->extended_cr3 = 1;
|
||||
xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
|
||||
}
|
||||
if (descsz >= 2 && grub_memcmp (desc, "no",
|
||||
descsz == 2 ? 2 : 3) == 0)
|
||||
xi->arch = GRUB_XEN_FILE_I386;
|
||||
break;
|
||||
default:
|
||||
grub_dprintf ("xen", "unknown note type %d\n", nh->n_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_xen_get_infoXX (grub_elf_t elf, struct grub_xen_file_info *xi)
|
||||
{
|
||||
Elf_Shdr *s, *s0;
|
||||
grub_size_t shnum = elf->ehdr.ehdrXX.e_shnum;
|
||||
grub_size_t shentsize = elf->ehdr.ehdrXX.e_shentsize;
|
||||
grub_size_t shsize = shnum * shentsize;
|
||||
grub_off_t stroff;
|
||||
grub_err_t err;
|
||||
Elf_Phdr *phdr;
|
||||
|
||||
xi->kern_end = 0;
|
||||
xi->kern_start = ~0;
|
||||
xi->entry_point = elf->ehdr.ehdrXX.e_entry;
|
||||
|
||||
/* FIXME: check note. */
|
||||
FOR_ELF_PHDRS (elf, phdr)
|
||||
{
|
||||
Elf_Addr paddr;
|
||||
|
||||
if (phdr->p_type == PT_NOTE)
|
||||
{
|
||||
err = parse_note (elf, xi, phdr->p_offset, phdr->p_filesz);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (phdr->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
paddr = phdr->p_paddr;
|
||||
|
||||
if (paddr < xi->kern_start)
|
||||
xi->kern_start = paddr;
|
||||
|
||||
if (paddr + phdr->p_memsz > xi->kern_end)
|
||||
xi->kern_end = paddr + phdr->p_memsz;
|
||||
}
|
||||
|
||||
if (xi->has_note)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
if (!shnum || !shentsize)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "no XEN note");
|
||||
|
||||
s0 = grub_malloc (shsize);
|
||||
if (!s0)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_file_seek (elf->file, elf->ehdr.ehdrXX.e_shoff) == (grub_off_t) -1)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_file_read (elf->file, s0, shsize) != (grub_ssize_t) shsize)
|
||||
{
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
|
||||
elf->file->name);
|
||||
}
|
||||
|
||||
s = (Elf_Shdr *) ((char *) s0 + elf->ehdr.ehdrXX.e_shstrndx * shentsize);
|
||||
stroff = s->sh_offset;
|
||||
|
||||
for (s = s0; s < (Elf_Shdr *) ((char *) s0 + shnum * shentsize);
|
||||
s = (Elf_Shdr *) ((char *) s + shentsize))
|
||||
{
|
||||
char name[sizeof("__xen_guest")];
|
||||
grub_memset (name, 0, sizeof (name));
|
||||
if (grub_file_seek (elf->file, stroff + s->sh_name) == (grub_off_t) -1)
|
||||
return grub_errno;
|
||||
|
||||
if (grub_file_read (elf->file, name, sizeof (name)) != (grub_ssize_t) sizeof (name))
|
||||
{
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
continue;
|
||||
}
|
||||
if (grub_memcmp (name, "__xen_guest",
|
||||
sizeof("__xen_guest")) != 0)
|
||||
continue;
|
||||
return parse_xen_guest (elf, xi, s->sh_offset, s->sh_size);
|
||||
}
|
||||
return grub_error (GRUB_ERR_BAD_OS, "no XEN note found");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue