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,
|
||||
char *argv[],
|
||||
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_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_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. */
|
||||
#include "bsd_pagetable.c"
|
||||
|
||||
struct gdt_descriptor
|
||||
{
|
||||
grub_uint16_t limit;
|
||||
void *base;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static grub_err_t
|
||||
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;
|
||||
|
||||
if (is_64bit)
|
||||
p_size += 4096 * 4;
|
||||
p_size += 4096 * 3;
|
||||
|
||||
err = grub_relocator_alloc_chunk_addr (relocator, (void **) &p,
|
||||
kern_end, p_size);
|
||||
if (err)
|
||||
return err;
|
||||
kern_end += p_size;
|
||||
p0 = p;
|
||||
p_target = kern_end;
|
||||
p0 = p;
|
||||
kern_end += p_size;
|
||||
|
||||
grub_env_iterate (iterate_env);
|
||||
|
||||
|
@ -547,49 +541,30 @@ grub_freebsd_boot (void)
|
|||
|
||||
if (is_64bit)
|
||||
{
|
||||
grub_uint32_t *gdt;
|
||||
grub_uint8_t *trampoline;
|
||||
void (*launch_trampoline) (grub_addr_t entry_lo, ...)
|
||||
__attribute__ ((cdecl, regparm (0)));
|
||||
struct grub_relocator64_state state;
|
||||
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;
|
||||
fill_bsd64_pagetable (pagetable);
|
||||
pagetable = p - (4096 * 3);
|
||||
fill_bsd64_pagetable (pagetable, (pagetable - p0) + p_target);
|
||||
|
||||
/* Create GDT. */
|
||||
gdt = (grub_uint32_t *) (p - 4096);
|
||||
gdt[0] = 0;
|
||||
gdt[1] = 0;
|
||||
gdt[2] = 0;
|
||||
gdt[3] = 0x00209800;
|
||||
gdt[4] = 0;
|
||||
gdt[5] = 0x00008000;
|
||||
state.cr3 = (pagetable - p0) + p_target;
|
||||
state.rsp = stack_target;
|
||||
state.rip = (((grub_uint64_t) entry_hi) << 32) | entry;
|
||||
|
||||
/* Create GDT descriptor. */
|
||||
gdtdesc = (struct gdt_descriptor *) (p - 4096 + 24);
|
||||
gdtdesc->limit = 24;
|
||||
gdtdesc->base = gdt;
|
||||
|
||||
/* 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);
|
||||
stack[0] = entry;
|
||||
stack[1] = bi.bi_modulep;
|
||||
stack[2] = kern_end;
|
||||
return grub_relocator64_boot (relocator, state, 0, 0x40000000);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -936,7 +911,7 @@ grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)),
|
|||
|
||||
if (phdr->p_type != PT_LOAD
|
||||
&& phdr->p_type != PT_DYNAMIC)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
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)
|
||||
kern_end = paddr + phdr->p_memsz;
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
&& phdr->p_type != PT_DYNAMIC)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
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)
|
||||
kern_end = paddr + phdr->p_memsz;
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
if (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,
|
||||
kern_start, kern_end - kern_start);
|
||||
if (err)
|
||||
|
@ -1154,9 +1132,9 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
|
|||
return grub_errno;
|
||||
|
||||
if (is_64bit)
|
||||
err = grub_freebsd_load_elf_meta64 (file, &kern_end);
|
||||
err = grub_freebsd_load_elf_meta64 (relocator, file, &kern_end);
|
||||
else
|
||||
err = grub_freebsd_load_elf_meta32 (file, &kern_end);
|
||||
err = grub_freebsd_load_elf_meta32 (relocator, file, &kern_end);
|
||||
if (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,
|
||||
argc - 1, argv + 1, 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
|
||||
|
||||
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;
|
||||
Elf_Ehdr e;
|
||||
Elf_Shdr *s;
|
||||
char *shdr;
|
||||
unsigned symoff, stroff, symsize, strsize;
|
||||
grub_addr_t curload;
|
||||
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
|
||||
Elf_Sym *sym;
|
||||
void *sym_chunk;
|
||||
grub_uint8_t *curload;
|
||||
grub_freebsd_addr_t symtarget;
|
||||
const char *str;
|
||||
unsigned i;
|
||||
grub_size_t chunk_size;
|
||||
|
||||
err = read_headers (file, &e, &shdr);
|
||||
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;
|
||||
strsize = s->sh_size;
|
||||
|
||||
if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize
|
||||
> grub_os_area_addr + grub_os_area_size)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"not enough memory for kernel symbols");
|
||||
chunk_size = 2 * sizeof (grub_freebsd_addr_t)
|
||||
+ ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t));
|
||||
symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
|
||||
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));
|
||||
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize;
|
||||
symstart = symtarget;
|
||||
symend = symstart + chunk_size;
|
||||
|
||||
curload = sym_chunk;
|
||||
*((grub_freebsd_addr_t *) curload) = symsize;
|
||||
curload += sizeof (grub_freebsd_addr_t);
|
||||
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
|
||||
return grub_errno;
|
||||
sym = (Elf_Sym *) UINT_TO_PTR (curload);
|
||||
if (grub_file_read (file, UINT_TO_PTR (curload), symsize) !=
|
||||
(grub_ssize_t) symsize)
|
||||
sym = (Elf_Sym *) curload;
|
||||
if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
|
||||
{
|
||||
if (! grub_errno)
|
||||
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;
|
||||
|
||||
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize;
|
||||
*((grub_freebsd_addr_t *) curload) = strsize;
|
||||
curload += sizeof (grub_freebsd_addr_t);
|
||||
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
|
||||
return grub_errno;
|
||||
str = (char *) UINT_TO_PTR (curload);
|
||||
if (grub_file_read (file, UINT_TO_PTR (curload), strsize)
|
||||
!= (grub_ssize_t) strsize)
|
||||
str = (char *) curload;
|
||||
if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
|
||||
{
|
||||
if (! grub_errno)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
|
||||
return grub_errno;
|
||||
}
|
||||
curload += strsize;
|
||||
curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t));
|
||||
symend = curload;
|
||||
|
||||
for (i = 0;
|
||||
i * symentsize < symsize;
|
||||
|
@ -360,7 +365,8 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
|
|||
sizeof (symend));
|
||||
if (err)
|
||||
return err;
|
||||
*kern_end = ALIGN_PAGE (curload);
|
||||
|
||||
*kern_end = ALIGN_PAGE (symend);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -50,9 +50,10 @@
|
|||
|
||||
|
||||
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_addr_t pt2t, pt3t, pt4t;
|
||||
int i;
|
||||
|
||||
#define PG_V 0x001
|
||||
|
@ -60,11 +61,15 @@ fill_bsd64_pagetable (grub_uint8_t *target)
|
|||
#define PG_U 0x004
|
||||
#define PG_PS 0x080
|
||||
|
||||
pt4 = (grub_uint64_t *) target;
|
||||
pt3 = (grub_uint64_t *) (target + 4096);
|
||||
pt2 = (grub_uint64_t *) (target + 8192);
|
||||
pt4 = (grub_uint64_t *) src;
|
||||
pt3 = (grub_uint64_t *) (src + 4096);
|
||||
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
|
||||
|
@ -74,11 +79,11 @@ fill_bsd64_pagetable (grub_uint8_t *target)
|
|||
for (i = 0; i < 512; i++)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* The level 2 page slots are mapped with 2MB pages for 1GB. */
|
||||
|
|
Loading…
Reference in a new issue