Fix various bugs in *bsd. Freebsd64 on relocators
This commit is contained in:
parent
14933205d1
commit
73910decff
4 changed files with 73 additions and 82 deletions
|
@ -263,9 +263,11 @@ grub_err_t grub_freebsd_load_elfmodule_obj64 (struct grub_relocator *relocator,
|
||||||
grub_file_t file, int argc,
|
grub_file_t file, int argc,
|
||||||
char *argv[],
|
char *argv[],
|
||||||
grub_addr_t *kern_end);
|
grub_addr_t *kern_end);
|
||||||
grub_err_t grub_freebsd_load_elf_meta32 (grub_file_t file,
|
grub_err_t grub_freebsd_load_elf_meta32 (struct grub_relocator *relocator,
|
||||||
|
grub_file_t file,
|
||||||
grub_addr_t *kern_end);
|
grub_addr_t *kern_end);
|
||||||
grub_err_t grub_freebsd_load_elf_meta64 (grub_file_t file,
|
grub_err_t grub_freebsd_load_elf_meta64 (struct grub_relocator *relocator,
|
||||||
|
grub_file_t file,
|
||||||
grub_addr_t *kern_end);
|
grub_addr_t *kern_end);
|
||||||
|
|
||||||
grub_err_t grub_freebsd_add_meta (grub_uint32_t type, void *data,
|
grub_err_t grub_freebsd_add_meta (grub_uint32_t type, void *data,
|
||||||
|
|
|
@ -436,12 +436,6 @@ grub_freebsd_list_modules (void)
|
||||||
/* This function would be here but it's under different license. */
|
/* This function would be here but it's under different license. */
|
||||||
#include "bsd_pagetable.c"
|
#include "bsd_pagetable.c"
|
||||||
|
|
||||||
struct gdt_descriptor
|
|
||||||
{
|
|
||||||
grub_uint16_t limit;
|
|
||||||
void *base;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_freebsd_boot (void)
|
grub_freebsd_boot (void)
|
||||||
{
|
{
|
||||||
|
@ -499,15 +493,15 @@ grub_freebsd_boot (void)
|
||||||
p_size = ALIGN_PAGE (kern_end + p_size + mod_buf_len) - kern_end;
|
p_size = ALIGN_PAGE (kern_end + p_size + mod_buf_len) - kern_end;
|
||||||
|
|
||||||
if (is_64bit)
|
if (is_64bit)
|
||||||
p_size += 4096 * 4;
|
p_size += 4096 * 3;
|
||||||
|
|
||||||
err = grub_relocator_alloc_chunk_addr (relocator, (void **) &p,
|
err = grub_relocator_alloc_chunk_addr (relocator, (void **) &p,
|
||||||
kern_end, p_size);
|
kern_end, p_size);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
kern_end += p_size;
|
|
||||||
p0 = p;
|
|
||||||
p_target = kern_end;
|
p_target = kern_end;
|
||||||
|
p0 = p;
|
||||||
|
kern_end += p_size;
|
||||||
|
|
||||||
grub_env_iterate (iterate_env);
|
grub_env_iterate (iterate_env);
|
||||||
|
|
||||||
|
@ -547,49 +541,30 @@ grub_freebsd_boot (void)
|
||||||
|
|
||||||
if (is_64bit)
|
if (is_64bit)
|
||||||
{
|
{
|
||||||
grub_uint32_t *gdt;
|
struct grub_relocator64_state state;
|
||||||
grub_uint8_t *trampoline;
|
|
||||||
void (*launch_trampoline) (grub_addr_t entry_lo, ...)
|
|
||||||
__attribute__ ((cdecl, regparm (0)));
|
|
||||||
grub_uint8_t *pagetable;
|
grub_uint8_t *pagetable;
|
||||||
|
grub_uint32_t *stack;
|
||||||
|
grub_addr_t stack_target;
|
||||||
|
|
||||||
struct gdt_descriptor *gdtdesc;
|
err = grub_relocator_alloc_chunk_align (relocator, (void **) &stack,
|
||||||
|
&stack_target,
|
||||||
|
0x10000, 0x90000,
|
||||||
|
3 * sizeof (grub_uint32_t)
|
||||||
|
+ sizeof (bi), 4);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
pagetable = p - 16384;
|
pagetable = p - (4096 * 3);
|
||||||
fill_bsd64_pagetable (pagetable);
|
fill_bsd64_pagetable (pagetable, (pagetable - p0) + p_target);
|
||||||
|
|
||||||
/* Create GDT. */
|
state.cr3 = (pagetable - p0) + p_target;
|
||||||
gdt = (grub_uint32_t *) (p - 4096);
|
state.rsp = stack_target;
|
||||||
gdt[0] = 0;
|
state.rip = (((grub_uint64_t) entry_hi) << 32) | entry;
|
||||||
gdt[1] = 0;
|
|
||||||
gdt[2] = 0;
|
|
||||||
gdt[3] = 0x00209800;
|
|
||||||
gdt[4] = 0;
|
|
||||||
gdt[5] = 0x00008000;
|
|
||||||
|
|
||||||
/* Create GDT descriptor. */
|
stack[0] = entry;
|
||||||
gdtdesc = (struct gdt_descriptor *) (p - 4096 + 24);
|
stack[1] = bi.bi_modulep;
|
||||||
gdtdesc->limit = 24;
|
stack[2] = kern_end;
|
||||||
gdtdesc->base = gdt;
|
return grub_relocator64_boot (relocator, state, 0, 0x40000000);
|
||||||
|
|
||||||
/* Prepare trampoline. */
|
|
||||||
trampoline = (grub_uint8_t *) (p - 4096 + 24
|
|
||||||
+ sizeof (struct gdt_descriptor));
|
|
||||||
launch_trampoline = (void __attribute__ ((cdecl, regparm (0)))
|
|
||||||
(*) (grub_addr_t entry_lo, ...)) trampoline;
|
|
||||||
grub_bsd64_trampoline_gdt = (grub_uint32_t) gdtdesc;
|
|
||||||
grub_bsd64_trampoline_selfjump
|
|
||||||
= (grub_uint32_t) (trampoline + 6
|
|
||||||
+ ((grub_uint8_t *) &grub_bsd64_trampoline_selfjump
|
|
||||||
- &grub_bsd64_trampoline_start));
|
|
||||||
|
|
||||||
/* Copy trampoline. */
|
|
||||||
grub_memcpy (trampoline, &grub_bsd64_trampoline_start,
|
|
||||||
&grub_bsd64_trampoline_end - &grub_bsd64_trampoline_start);
|
|
||||||
|
|
||||||
/* Launch trampoline. */
|
|
||||||
launch_trampoline (entry, entry_hi, pagetable, bi.bi_modulep,
|
|
||||||
kern_end);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -936,7 +911,7 @@ grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)),
|
||||||
|
|
||||||
if (phdr->p_type != PT_LOAD
|
if (phdr->p_type != PT_LOAD
|
||||||
&& phdr->p_type != PT_DYNAMIC)
|
&& phdr->p_type != PT_DYNAMIC)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
paddr = phdr->p_paddr & 0xFFFFFF;
|
paddr = phdr->p_paddr & 0xFFFFFF;
|
||||||
|
|
||||||
|
@ -946,7 +921,7 @@ grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)),
|
||||||
if (paddr + phdr->p_memsz > kern_end)
|
if (paddr + phdr->p_memsz > kern_end)
|
||||||
kern_end = paddr + phdr->p_memsz;
|
kern_end = paddr + phdr->p_memsz;
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -978,7 +953,7 @@ grub_bsd_elf64_size_hook (grub_elf_t elf __attribute__ ((unused)),
|
||||||
|
|
||||||
if (phdr->p_type != PT_LOAD
|
if (phdr->p_type != PT_LOAD
|
||||||
&& phdr->p_type != PT_DYNAMIC)
|
&& phdr->p_type != PT_DYNAMIC)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
paddr = phdr->p_paddr & 0xffffff;
|
paddr = phdr->p_paddr & 0xffffff;
|
||||||
|
|
||||||
|
@ -988,7 +963,7 @@ grub_bsd_elf64_size_hook (grub_elf_t elf __attribute__ ((unused)),
|
||||||
if (paddr + phdr->p_memsz > kern_end)
|
if (paddr + phdr->p_memsz > kern_end)
|
||||||
kern_end = paddr + phdr->p_memsz;
|
kern_end = paddr + phdr->p_memsz;
|
||||||
|
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -1054,6 +1029,9 @@ grub_bsd_load_elf (grub_elf_t elf)
|
||||||
err = grub_elf64_phdr_iterate (elf, grub_bsd_elf64_size_hook, NULL);
|
err = grub_elf64_phdr_iterate (elf, grub_bsd_elf64_size_hook, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
grub_dprintf ("bsd", "kern_start = %x, kern_end = %x\n", kern_start,
|
||||||
|
kern_end);
|
||||||
err = grub_relocator_alloc_chunk_addr (relocator, &kern_chunk_src,
|
err = grub_relocator_alloc_chunk_addr (relocator, &kern_chunk_src,
|
||||||
kern_start, kern_end - kern_start);
|
kern_start, kern_end - kern_start);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1154,9 +1132,9 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
if (is_64bit)
|
if (is_64bit)
|
||||||
err = grub_freebsd_load_elf_meta64 (file, &kern_end);
|
err = grub_freebsd_load_elf_meta64 (relocator, file, &kern_end);
|
||||||
else
|
else
|
||||||
err = grub_freebsd_load_elf_meta32 (file, &kern_end);
|
err = grub_freebsd_load_elf_meta32 (relocator, file, &kern_end);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
|
@ -249,24 +249,28 @@ SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator,
|
||||||
grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
|
grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
|
||||||
argc - 1, argv + 1, module,
|
argc - 1, argv + 1, module,
|
||||||
curload - module);
|
curload - module);
|
||||||
return SUFFIX (grub_freebsd_load_elf_meta) (file, kern_end);
|
return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, kern_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
grub_err_t
|
grub_err_t
|
||||||
SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
|
SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator,
|
||||||
|
grub_file_t file, grub_addr_t *kern_end)
|
||||||
{
|
{
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
Elf_Ehdr e;
|
Elf_Ehdr e;
|
||||||
Elf_Shdr *s;
|
Elf_Shdr *s;
|
||||||
char *shdr;
|
char *shdr;
|
||||||
unsigned symoff, stroff, symsize, strsize;
|
unsigned symoff, stroff, symsize, strsize;
|
||||||
grub_addr_t curload;
|
|
||||||
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
|
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
|
||||||
Elf_Sym *sym;
|
Elf_Sym *sym;
|
||||||
|
void *sym_chunk;
|
||||||
|
grub_uint8_t *curload;
|
||||||
|
grub_freebsd_addr_t symtarget;
|
||||||
const char *str;
|
const char *str;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
grub_size_t chunk_size;
|
||||||
|
|
||||||
err = read_headers (file, &e, &shdr);
|
err = read_headers (file, &e, &shdr);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -293,19 +297,24 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
|
||||||
stroff = s->sh_offset;
|
stroff = s->sh_offset;
|
||||||
strsize = s->sh_size;
|
strsize = s->sh_size;
|
||||||
|
|
||||||
if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize
|
chunk_size = 2 * sizeof (grub_freebsd_addr_t)
|
||||||
> grub_os_area_addr + grub_os_area_size)
|
+ ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t));
|
||||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
|
||||||
"not enough memory for kernel symbols");
|
err = grub_relocator_alloc_chunk_addr (relocator, &sym_chunk,
|
||||||
|
symtarget, chunk_size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
|
symstart = symtarget;
|
||||||
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize;
|
symend = symstart + chunk_size;
|
||||||
|
|
||||||
|
curload = sym_chunk;
|
||||||
|
*((grub_freebsd_addr_t *) curload) = symsize;
|
||||||
curload += sizeof (grub_freebsd_addr_t);
|
curload += sizeof (grub_freebsd_addr_t);
|
||||||
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
|
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
sym = (Elf_Sym *) UINT_TO_PTR (curload);
|
sym = (Elf_Sym *) curload;
|
||||||
if (grub_file_read (file, UINT_TO_PTR (curload), symsize) !=
|
if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
|
||||||
(grub_ssize_t) symsize)
|
|
||||||
{
|
{
|
||||||
if (! grub_errno)
|
if (! grub_errno)
|
||||||
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
|
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
|
||||||
|
@ -313,21 +322,17 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
|
||||||
}
|
}
|
||||||
curload += symsize;
|
curload += symsize;
|
||||||
|
|
||||||
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize;
|
*((grub_freebsd_addr_t *) curload) = strsize;
|
||||||
curload += sizeof (grub_freebsd_addr_t);
|
curload += sizeof (grub_freebsd_addr_t);
|
||||||
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
|
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
str = (char *) UINT_TO_PTR (curload);
|
str = (char *) curload;
|
||||||
if (grub_file_read (file, UINT_TO_PTR (curload), strsize)
|
if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
|
||||||
!= (grub_ssize_t) strsize)
|
|
||||||
{
|
{
|
||||||
if (! grub_errno)
|
if (! grub_errno)
|
||||||
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
|
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
}
|
}
|
||||||
curload += strsize;
|
|
||||||
curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t));
|
|
||||||
symend = curload;
|
|
||||||
|
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
i * symentsize < symsize;
|
i * symentsize < symsize;
|
||||||
|
@ -360,7 +365,8 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
|
||||||
sizeof (symend));
|
sizeof (symend));
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
*kern_end = ALIGN_PAGE (curload);
|
|
||||||
|
*kern_end = ALIGN_PAGE (symend);
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,10 @@
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fill_bsd64_pagetable (grub_uint8_t *target)
|
fill_bsd64_pagetable (grub_uint8_t *src, grub_addr_t target)
|
||||||
{
|
{
|
||||||
grub_uint64_t *pt2, *pt3, *pt4;
|
grub_uint64_t *pt2, *pt3, *pt4;
|
||||||
|
grub_addr_t pt2t, pt3t, pt4t;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#define PG_V 0x001
|
#define PG_V 0x001
|
||||||
|
@ -60,11 +61,15 @@ fill_bsd64_pagetable (grub_uint8_t *target)
|
||||||
#define PG_U 0x004
|
#define PG_U 0x004
|
||||||
#define PG_PS 0x080
|
#define PG_PS 0x080
|
||||||
|
|
||||||
pt4 = (grub_uint64_t *) target;
|
pt4 = (grub_uint64_t *) src;
|
||||||
pt3 = (grub_uint64_t *) (target + 4096);
|
pt3 = (grub_uint64_t *) (src + 4096);
|
||||||
pt2 = (grub_uint64_t *) (target + 8192);
|
pt2 = (grub_uint64_t *) (src + 8192);
|
||||||
|
|
||||||
grub_memset ((char *) target, 0, 4096 * 3);
|
pt4t = target;
|
||||||
|
pt3t = target + 4096;
|
||||||
|
pt2t = target + 8192;
|
||||||
|
|
||||||
|
grub_memset (src, 0, 4096 * 3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is kinda brutal, but every single 1GB VM memory segment points to
|
* This is kinda brutal, but every single 1GB VM memory segment points to
|
||||||
|
@ -74,11 +79,11 @@ fill_bsd64_pagetable (grub_uint8_t *target)
|
||||||
for (i = 0; i < 512; i++)
|
for (i = 0; i < 512; i++)
|
||||||
{
|
{
|
||||||
/* Each slot of the level 4 pages points to the same level 3 page */
|
/* Each slot of the level 4 pages points to the same level 3 page */
|
||||||
pt4[i] = (grub_addr_t) &pt3[0];
|
pt4[i] = (grub_addr_t) pt3t;
|
||||||
pt4[i] |= PG_V | PG_RW | PG_U;
|
pt4[i] |= PG_V | PG_RW | PG_U;
|
||||||
|
|
||||||
/* Each slot of the level 3 pages points to the same level 2 page */
|
/* Each slot of the level 3 pages points to the same level 2 page */
|
||||||
pt3[i] = (grub_addr_t) &pt2[0];
|
pt3[i] = (grub_addr_t) pt2t;
|
||||||
pt3[i] |= PG_V | PG_RW | PG_U;
|
pt3[i] |= PG_V | PG_RW | PG_U;
|
||||||
|
|
||||||
/* The level 2 page slots are mapped with 2MB pages for 1GB. */
|
/* The level 2 page slots are mapped with 2MB pages for 1GB. */
|
||||||
|
|
Loading…
Reference in a new issue